mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-04 13:22:36 +00:00 
			
		
		
		
	rsetboot for redfish support
This commit is contained in:
		@@ -0,0 +1,51 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
###############################################################################
 | 
			
		||||
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
			
		||||
###############################################################################
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
#
 | 
			
		||||
from __future__ import print_function
 | 
			
		||||
import gevent
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
from common.task import ParallelNodesCommand
 | 
			
		||||
from common.exceptions import SelfClientException, SelfServerException
 | 
			
		||||
from hwctl import redfish_client as redfish
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
logger = logging.getLogger('xcatagent')
 | 
			
		||||
 | 
			
		||||
class RedfishBootTask(ParallelNodesCommand):
 | 
			
		||||
    """Executor for setboot-related actions."""
 | 
			
		||||
 | 
			
		||||
    def get_state(self, **kw):
 | 
			
		||||
 | 
			
		||||
        node = kw['node']
 | 
			
		||||
        rf = redfish.RedfishRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
 | 
			
		||||
                                 debugmode=self.debugmode, verbose=self.verbose)
 | 
			
		||||
 | 
			
		||||
        state = 'Unknown'
 | 
			
		||||
        try:
 | 
			
		||||
            rf.login()
 | 
			
		||||
            state = rf.get_boot_state()
 | 
			
		||||
            self.callback.info('%s: %s' % (node, state))
 | 
			
		||||
 | 
			
		||||
        except (SelfServerException, SelfClientException) as e:
 | 
			
		||||
            self.callback.error(e.message, node)
 | 
			
		||||
 | 
			
		||||
        return state 
 | 
			
		||||
 | 
			
		||||
    def set_state(self, setboot_state, persistant, **kw):
 | 
			
		||||
 | 
			
		||||
        node = kw['node']
 | 
			
		||||
        rf = redfish.RedfishRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
 | 
			
		||||
                                 debugmode=self.debugmode, verbose=self.verbose)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            rf.login()
 | 
			
		||||
            rf.set_boot_state(persistant, setboot_state)
 | 
			
		||||
            state = rf.get_boot_state()
 | 
			
		||||
            self.callback.info('%s: %s' % (node, state))
 | 
			
		||||
 | 
			
		||||
        except (SelfServerException, SelfClientException) as e:
 | 
			
		||||
            self.callback.error(e.message, node)
 | 
			
		||||
@@ -32,6 +32,28 @@ POWER_RESET_TYPE = {
 | 
			
		||||
    'on'      : 'ForceOn',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
manager_reset_string = '#Manager.Reset'
 | 
			
		||||
system_reset_string = '#ComputerSystem.Reset'
 | 
			
		||||
reset_type_string = 'ResetType@Redfish.AllowableValues'
 | 
			
		||||
 | 
			
		||||
BOOTSOURCE_SET_STATE = {
 | 
			
		||||
    "cd"    : "Cd",
 | 
			
		||||
    "def"   : "None",
 | 
			
		||||
    "floppy": "Floppy",
 | 
			
		||||
    "hd"    : 'Hdd',
 | 
			
		||||
    "net"   : "Pxe",
 | 
			
		||||
    "setup" : "BiosSetup",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOTSOURCE_GET_STATE = {
 | 
			
		||||
    "BiosSetup": "BIOS Setup",
 | 
			
		||||
    "Floppy"   : "Floppy",
 | 
			
		||||
    "Cd"       : "CD/DVD",
 | 
			
		||||
    "Hdd"      : "Hard Drive",
 | 
			
		||||
    "None"     : "boot override inactive",
 | 
			
		||||
    "Pxe"      : "Network",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class RedfishRest(object):
 | 
			
		||||
 | 
			
		||||
    headers = {'Content-Type': 'application/json'}
 | 
			
		||||
@@ -185,8 +207,8 @@ class RedfishRest(object):
 | 
			
		||||
        target_url = members[0]['@odata.id']
 | 
			
		||||
        data = self.request('GET', target_url, cmd='get_bmc_actions')
 | 
			
		||||
        try:
 | 
			
		||||
            actions = data['Actions']['#Manager.Reset']['ResetType@Redfish.AllowableValues']
 | 
			
		||||
            target_url = data['Actions']['#Manager.Reset']['target']
 | 
			
		||||
            actions = data['Actions'][manager_reset_string][reset_type_string]
 | 
			
		||||
            target_url = data['Actions'][manager_reset_string]['target']
 | 
			
		||||
        except KeyError as e:
 | 
			
		||||
            raise SelfServerException('Get KeyError %s' % e.message)
 | 
			
		||||
 | 
			
		||||
@@ -196,7 +218,7 @@ class RedfishRest(object):
 | 
			
		||||
 | 
			
		||||
        target_url, actions = self._get_bmc_actions()
 | 
			
		||||
        if BMC_RESET_TYPE not in actions:
 | 
			
		||||
            raise SelfClientException('Unsupport option: %s' % BMC_RESET_TYPE)
 | 
			
		||||
            raise SelfClientException('Unsupported option: %s' % BMC_RESET_TYPE)
 | 
			
		||||
 | 
			
		||||
        data = { "ResetType": BMC_RESET_TYPE }
 | 
			
		||||
        return self.request('POST', target_url, payload=data, cmd='set_bmc_state')
 | 
			
		||||
@@ -207,8 +229,8 @@ class RedfishRest(object):
 | 
			
		||||
        target_url = members[0]['@odata.id']
 | 
			
		||||
        data = self.request('GET', target_url, cmd='get_power_actions')
 | 
			
		||||
        try:
 | 
			
		||||
            actions = data['Actions']['#ComputerSystem.Reset']['ResetType@Redfish.AllowableValues']
 | 
			
		||||
            target_url = data['Actions']['#ComputerSystem.Reset']['target']
 | 
			
		||||
            actions = data['Actions'][system_reset_string][reset_type_string]
 | 
			
		||||
            target_url = data['Actions'][system_reset_string]['target']
 | 
			
		||||
        except KeyError as e:
 | 
			
		||||
            raise SelfServerException('Get KeyError %s' % e.message)
 | 
			
		||||
 | 
			
		||||
@@ -218,9 +240,48 @@ class RedfishRest(object):
 | 
			
		||||
 | 
			
		||||
        target_url, actions = self._get_power_actions()
 | 
			
		||||
        if POWER_RESET_TYPE[state] not in actions:
 | 
			
		||||
            raise SelfClientException('Unsupport option: %s' % state)
 | 
			
		||||
            raise SelfClientException('Unsupported option: %s' % state)
 | 
			
		||||
 | 
			
		||||
        data = { "ResetType": POWER_RESET_TYPE[state] }
 | 
			
		||||
        return self.request('POST', target_url, payload=data, cmd='set_power_state')
 | 
			
		||||
 | 
			
		||||
    def get_boot_state(self):
 | 
			
		||||
 | 
			
		||||
        members = self._get_members(SYSTEMS_URL)
 | 
			
		||||
        target_url = members[0]['@odata.id']
 | 
			
		||||
        data = self.request('GET', target_url, cmd='get_boot_state')
 | 
			
		||||
        try:
 | 
			
		||||
            boot_enable = data['Boot']['BootSourceOverrideEnabled']
 | 
			
		||||
            if boot_enable == 'Disabled':
 | 
			
		||||
                return 'boot override inactive'
 | 
			
		||||
            bootsource = data['Boot']['BootSourceOverrideTarget']
 | 
			
		||||
            return BOOTSOURCE_GET_STATE.get(bootsource, bootsource)
 | 
			
		||||
        except KeyError as e:
 | 
			
		||||
            raise SelfServerException('Get KeyError %s' % e.message)
 | 
			
		||||
 | 
			
		||||
    def _get_boot_actions(self):
 | 
			
		||||
 | 
			
		||||
        members = self._get_members(SYSTEMS_URL)
 | 
			
		||||
        target_url = members[0]['@odata.id']
 | 
			
		||||
        data = self.request('GET', target_url, cmd='get_boot_actions')
 | 
			
		||||
        try:
 | 
			
		||||
            actions = data['Boot']['BootSourceOverrideTarget@Redfish.AllowableValues']
 | 
			
		||||
        except KeyError as e:
 | 
			
		||||
            raise SelfServerException('Get KeyError %s' % e.message)
 | 
			
		||||
 | 
			
		||||
        return (target_url, actions) 
 | 
			
		||||
 | 
			
		||||
    def set_boot_state(self, persistant, state):
 | 
			
		||||
 | 
			
		||||
        target_url, actions = self._get_boot_actions()
 | 
			
		||||
        target_data = BOOTSOURCE_SET_STATE[state]
 | 
			
		||||
        if target_data not in actions:
 | 
			
		||||
            raise SelfClientException('Unsupported option: %s' % state)
 | 
			
		||||
 | 
			
		||||
        boot_enable = 'Once'
 | 
			
		||||
        if persistant:
 | 
			
		||||
            boot_enable = 'Continuous' 
 | 
			
		||||
        if target_data == 'None':
 | 
			
		||||
            boot_enable = 'Disabled'
 | 
			
		||||
        data = {'Boot': {'BootSourceOverrideEnabled': boot_enable, "BootSourceOverrideTarget": target_data} }
 | 
			
		||||
        return self.request('PATCH', target_url, payload=data, cmd='set_boot_state')
 | 
			
		||||
 
 | 
			
		||||
@@ -14,13 +14,13 @@ from docopt import docopt,DocoptExit
 | 
			
		||||
 | 
			
		||||
from common import utils
 | 
			
		||||
from common import exceptions as xcat_exception
 | 
			
		||||
from hwctl.executor.openbmc_beacon import OpenBMCBeaconTask
 | 
			
		||||
from hwctl.executor.openbmc_setboot import OpenBMCBootTask
 | 
			
		||||
from hwctl.executor.openbmc_flash import OpenBMCFlashTask
 | 
			
		||||
from hwctl.executor.openbmc_inventory import OpenBMCInventoryTask
 | 
			
		||||
from hwctl.executor.openbmc_power import OpenBMCPowerTask
 | 
			
		||||
from hwctl.executor.openbmc_sensor import OpenBMCSensorTask
 | 
			
		||||
from hwctl.executor.openbmc_eventlog import OpenBMCEventlogTask
 | 
			
		||||
from hwctl.openbmc.openbmc_beacon import OpenBMCBeaconTask
 | 
			
		||||
from hwctl.openbmc.openbmc_setboot import OpenBMCBootTask
 | 
			
		||||
from hwctl.openbmc.openbmc_flash import OpenBMCFlashTask
 | 
			
		||||
from hwctl.openbmc.openbmc_inventory import OpenBMCInventoryTask
 | 
			
		||||
from hwctl.openbmc.openbmc_power import OpenBMCPowerTask
 | 
			
		||||
from hwctl.openbmc.openbmc_sensor import OpenBMCSensorTask
 | 
			
		||||
from hwctl.openbmc.openbmc_eventlog import OpenBMCEventlogTask
 | 
			
		||||
from hwctl.beacon import DefaultBeaconManager
 | 
			
		||||
from hwctl.setboot import DefaultBootManager
 | 
			
		||||
from hwctl.flash import DefaultFlashManager
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,10 @@ from docopt import docopt,DocoptExit
 | 
			
		||||
 | 
			
		||||
from common import utils
 | 
			
		||||
from common import exceptions as xcat_exception
 | 
			
		||||
from hwctl.executor.redfish_power import RedfishPowerTask
 | 
			
		||||
from hwctl.redfish.redfish_power import RedfishPowerTask
 | 
			
		||||
from hwctl.redfish.redfish_setboot import RedfishBootTask
 | 
			
		||||
from hwctl.power import DefaultPowerManager
 | 
			
		||||
from hwctl.setboot import DefaultBootManager
 | 
			
		||||
 | 
			
		||||
from xcatagent import base
 | 
			
		||||
import logging
 | 
			
		||||
@@ -33,6 +35,10 @@ POWER_REBOOT_OPTIONS = ('boot', 'reset')
 | 
			
		||||
POWER_SET_OPTIONS = ('on', 'off', 'bmcreboot')
 | 
			
		||||
POWER_GET_OPTIONS = ('bmcstate', 'state', 'stat', 'status')
 | 
			
		||||
 | 
			
		||||
# global variables of rsetboot
 | 
			
		||||
SETBOOT_GET_OPTIONS = ('stat', '')
 | 
			
		||||
SETBOOT_SET_OPTIONS = ('cd', 'def', 'default', 'floppy', 'hd', 'net', 'setup')
 | 
			
		||||
 | 
			
		||||
class RedfishManager(base.BaseManager):
 | 
			
		||||
    def __init__(self, messager, cwd, nodes=None, envs=None):
 | 
			
		||||
        super(RedfishManager, self).__init__(messager, cwd)
 | 
			
		||||
@@ -84,3 +90,40 @@ class RedfishManager(base.BaseManager):
 | 
			
		||||
        else:
 | 
			
		||||
            DefaultPowerManager().set_power_state(runner, power_state=action)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def rsetboot(self, nodesinfo, args):
 | 
			
		||||
 | 
			
		||||
        # 1, parse args
 | 
			
		||||
        if not args:
 | 
			
		||||
            args = ['stat']
 | 
			
		||||
 | 
			
		||||
        rsetboot_usage = """
 | 
			
		||||
        Usage:
 | 
			
		||||
            rsetboot [-V|--verbose] [cd|def|default|floppy||hd|net|stat|setup] [-p]
 | 
			
		||||
 | 
			
		||||
        Options:
 | 
			
		||||
            -V --verbose    rsetboot verbose mode.
 | 
			
		||||
            -p              persistant boot source.
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            opts = docopt(rsetboot_usage, argv=args)
 | 
			
		||||
 | 
			
		||||
            self.verbose = opts.pop('--verbose')
 | 
			
		||||
            action_type = opts.pop('-p')
 | 
			
		||||
            action = [k for k,v in opts.items() if v][0]
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self.messager.error("Failed to parse arguments for rsetboot: %s" % args)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # 2, validate the args
 | 
			
		||||
        if action not in (SETBOOT_GET_OPTIONS + SETBOOT_SET_OPTIONS):
 | 
			
		||||
            self.messager.error("Not supported subcommand for rsetboot: %s" % action)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # 3, run the subcommands
 | 
			
		||||
        runner = RedfishBootTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
 | 
			
		||||
        if action in SETBOOT_GET_OPTIONS:
 | 
			
		||||
            DefaultBootManager().get_boot_state(runner)
 | 
			
		||||
        else:
 | 
			
		||||
            DefaultBootManager().set_boot_state(runner, setboot_state=action, persistant=action_type)
 | 
			
		||||
 
 | 
			
		||||
@@ -165,6 +165,14 @@ sub parse_args {
 | 
			
		||||
        unless ($subcommand =~ /^on$|^off$|^reset$|^boot$|^bmcreboot$|^bmcstate$|^status$|^stat$|^state$/) {
 | 
			
		||||
            return ([ 1, "Unsupported command: $command $subcommand" ]);
 | 
			
		||||
        }
 | 
			
		||||
    } elsif ($command eq "rsetboot") {
 | 
			
		||||
        my $persistant;
 | 
			
		||||
        GetOptions('p'  => \$persistant);
 | 
			
		||||
        return ([ 1, "Only one option is supported at the same time for $command" ]) if (@ARGV > 1);
 | 
			
		||||
        $subcommand = "stat" if (!defined($ARGV[0]));
 | 
			
		||||
        unless ($subcommand =~ /^net$|^hd$|^cd$|^def$|^default$|^stat$|^setup$|^floppy$/) {
 | 
			
		||||
            return ([ 1, "Unsupported command: $command $subcommand" ]);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return ([ 1, "Unsupported command: $command" ]);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user