mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 11:22:27 +00:00 
			
		
		
		
	rsetboot for openbmc in python (#4784)
* rsetboot for openbmc in python
This commit is contained in:
		| @@ -0,0 +1,64 @@ | ||||
| #!/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 openbmc_client as openbmc | ||||
|  | ||||
| import logging | ||||
| logger = logging.getLogger('xcatagent') | ||||
|  | ||||
|  | ||||
| class OpenBMCBootTask(ParallelNodesCommand): | ||||
|     """Executor for setboot-related actions.""" | ||||
|  | ||||
|     def get_state(self, **kw): | ||||
|  | ||||
|         node = kw['node'] | ||||
|         obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, | ||||
|                                    debugmode=self.debugmode, verbose=self.verbose) | ||||
|  | ||||
|         state = 'Unknown' | ||||
|         try: | ||||
|             obmc.login() | ||||
|             state = obmc.get_boot_state() | ||||
|  | ||||
|             result = '%s: %s' % (node, state) | ||||
|  | ||||
|         except (SelfServerException, SelfClientException) as e: | ||||
|             result = '%s: %s'  % (node, e.message) | ||||
|  | ||||
|         self.callback.info(result) | ||||
|         return state | ||||
|  | ||||
|     def set_state(self, state, persistant, **kw): | ||||
|  | ||||
|         node = kw['node'] | ||||
|         obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, | ||||
|                                    debugmode=self.debugmode, verbose=self.verbose) | ||||
|  | ||||
|         try: | ||||
|             obmc.login() | ||||
|             if persistant: | ||||
|                 obmc.set_one_time_boot_enable(0) | ||||
|                 obmc.set_boot_state(state) | ||||
|             else: | ||||
|                 obmc.set_one_time_boot_enable(1) | ||||
|                 obmc.set_one_time_boot_state(state) | ||||
|  | ||||
|             state = obmc.get_boot_state() | ||||
|  | ||||
|             result = '%s: %s' % (node, state) | ||||
|  | ||||
|         except (SelfServerException, SelfClientException) as e: | ||||
|             result = '%s: %s'  % (node, e.message) | ||||
|  | ||||
|         self.callback.info(result) | ||||
|  | ||||
| @@ -62,6 +62,37 @@ BMC_URLS = { | ||||
|     }, | ||||
| } | ||||
|  | ||||
| BOOTSOURCE_URLS = { | ||||
|     "enable"       : { | ||||
|         "path"      : "/control/host0/boot/one_time/attr/Enabled", | ||||
|     }, | ||||
|     "get"          : { | ||||
|         "path"      : "/control/host0/enumerate", | ||||
|     }, | ||||
|     "set_one_time" : { | ||||
|         "path"      : "/control/host0/boot/one_time/attr/BootSource", | ||||
|     }, | ||||
|     "set"          : { | ||||
|         "path"      : "/control/host0/boot/attr/BootSource", | ||||
|     }, | ||||
|     "field"        : "xyz.openbmc_project.Control.Boot.Source.Sources.", | ||||
| } | ||||
|  | ||||
| BOOTSOURCE_GET_STATE = { | ||||
|     "Default"       : "Default", | ||||
|     "Disk"          : "Hard Drive", | ||||
|     "ExternalMedia" : "CD/DVD", | ||||
|     "Network"       : "Network", | ||||
| } | ||||
|  | ||||
| BOOTSOURCE_SET_STATE = { | ||||
|     "cd"      : "ExternalMedia", | ||||
|     "def"     : "Default", | ||||
|     "default" : "Default", | ||||
|     "hd"      : "Disk", | ||||
|     "net"     : "Network", | ||||
| } | ||||
|  | ||||
| RESULT_OK = 'ok' | ||||
| RESULT_FAIL = 'fail' | ||||
|  | ||||
| @@ -225,3 +256,37 @@ class OpenBMCRest(object): | ||||
|         except SelfServerException,SelfClientException: | ||||
|             # TODO: Need special handling for bmc reset, as it is normal bmc may return error | ||||
|             pass | ||||
|  | ||||
|     def set_one_time_boot_enable(self, enabled): | ||||
|  | ||||
|         payload = { "data": enabled } | ||||
|         self.request('PUT', BOOTSOURCE_URLS['enable']['path'], payload=payload, cmd='set_one_time_boot_enable') | ||||
|  | ||||
|     def set_boot_state(self, state): | ||||
|  | ||||
|         payload = { "data": BOOTSOURCE_URLS['field'] + BOOTSOURCE_SET_STATE[state] }  | ||||
|         self.request('PUT', BOOTSOURCE_URLS['set']['path'], payload=payload, cmd='set_boot_state') | ||||
|  | ||||
|     def set_one_time_boot_state(self, state): | ||||
|  | ||||
|         payload = { "data": BOOTSOURCE_URLS['field'] + BOOTSOURCE_SET_STATE[state] } | ||||
|         self.request('PUT', BOOTSOURCE_URLS['set_one_time']['path'], payload=payload, cmd='set_one_time_boot_state') | ||||
|  | ||||
|     def get_boot_state(self): | ||||
|  | ||||
|         state = self.request('GET', BOOTSOURCE_URLS['get']['path'], cmd='get_boot_state') | ||||
|         try: | ||||
|             one_time_path = PROJECT_URL + '/control/host0/boot/one_time' | ||||
|             one_time_enabled =  state[one_time_path]['Enabled'] | ||||
|             if one_time_enabled: | ||||
|                 boot_source = state[one_time_path]['BootSource'].split('.')[-1] | ||||
|             else: | ||||
|                 boot_source = state[PROJECT_URL + '/control/host0/boot']['BootSource'].split('.')[-1] | ||||
|  | ||||
|             error = 'Can not get valid rsetboot status, the data is %s' % boot_source | ||||
|             boot_state = BOOTSOURCE_GET_STATE.get(boot_source.split('.')[-1], error) | ||||
|             return boot_state | ||||
|         except KeyError: | ||||
|             error = 'Error: Received wrong format response: %s' % states | ||||
|             raise SelfServerException(error) | ||||
|  | ||||
|   | ||||
							
								
								
									
										34
									
								
								xCAT-openbmc-py/lib/python/agent/hwctl/setboot.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								xCAT-openbmc-py/lib/python/agent/hwctl/setboot.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #!/usr/bin/env python | ||||
| ############################################################################### | ||||
| # IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html | ||||
| ############################################################################### | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
|  | ||||
| class BootInterface(object): | ||||
|     """Interface for setboot-related actions.""" | ||||
|     interface_type = 'setboot' | ||||
|     version = '1.0' | ||||
|  | ||||
|     def get_boot_state(self, task): | ||||
|         """Return the setboot state of the task's nodes. | ||||
|  | ||||
|         :param task: a Task instance containing the nodes to act on. | ||||
|         :returns: a setboot state. | ||||
|         """ | ||||
|         return task.run('get_state') | ||||
|  | ||||
|     def set_boot_state(self, task, setboot_state, persistant=False, timeout=None): | ||||
|         """Set the setboot state of the task's nodes. | ||||
|  | ||||
|         :param task: a Task instance containing the nodes to act on. | ||||
|         :param setboot_state: Any boot state allowed. | ||||
|         :param persistant: whether set boot state persistant | ||||
|         :param timeout: timeout (in seconds) positive integer (> 0) for any | ||||
|           setboot state. ``None`` indicates to use default timeout. | ||||
|         """ | ||||
|         return task.run('set_state', setboot_state, persistant, timeout=timeout) | ||||
|  | ||||
| class DefaultBootManager(BootInterface): | ||||
|     """Interface for setboot-related actions.""" | ||||
|     pass | ||||
| @@ -10,11 +10,14 @@ import os | ||||
| import time | ||||
| import sys | ||||
| import gevent | ||||
| from docopt import docopt | ||||
|  | ||||
| from common import utils | ||||
| from common import exceptions as xcat_exception | ||||
| from hwctl.executor.openbmc_power import OpenBMCPowerTask | ||||
| from hwctl.executor.openbmc_setboot import OpenBMCBootTask | ||||
| from hwctl.power import DefaultPowerManager | ||||
| from hwctl.setboot import DefaultBootManager | ||||
|  | ||||
| from xcatagent import base | ||||
| import openbmc_rest | ||||
| @@ -73,6 +76,10 @@ POWER_REBOOT_OPTIONS = ('boot', 'reset') | ||||
| POWER_SET_OPTIONS = ('on', 'off', 'bmcreboot', 'softoff') | ||||
| POWER_GET_OPTIONS = ('bmcstate', 'state', 'stat', 'status') | ||||
|  | ||||
| # global variables of rsetboot | ||||
| SETBOOT_GET_OPTIONS = ('stat', '') | ||||
| SETBOOT_SET_OPTIONS = ('cd', 'def', 'default', 'hd', 'net') | ||||
|  | ||||
| class OpenBMC(base.BaseDriver): | ||||
|  | ||||
|     headers = {'Content-Type': 'application/json'} | ||||
| @@ -562,6 +569,44 @@ class OpenBMCManager(base.BaseManager): | ||||
|         else: | ||||
|             DefaultPowerManager().set_power_state(runner, power_state=opts.action) | ||||
|  | ||||
|     def rsetboot(self, nodesinfo, args): | ||||
|  | ||||
|         # 1, parse args | ||||
|         if not args: | ||||
|             args = ['stat'] | ||||
|  | ||||
|         rsetboot_usage = """ | ||||
|         Usage: | ||||
|             rsetboot [-V|--verbose] [cd|def|default|hd|net|stat] [-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 = OpenBMCBootTask(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) | ||||
|  | ||||
|  | ||||
|     def _get_full_path(self,file_path): | ||||
|         if type(self.cwd) == 'unicode': | ||||
|             dir_path = self.cwd | ||||
|   | ||||
| @@ -137,6 +137,13 @@ sub parse_args { | ||||
|     my $noderange = shift; | ||||
|     my $subcommand = undef; | ||||
|  | ||||
|     my $verbose; | ||||
|     unless (GetOptions( | ||||
|         'V|verbose'  => \$verbose, | ||||
|     )) { | ||||
|         return ([ 1, "Error parsing arguments." ]); | ||||
|     } | ||||
|  | ||||
|     if (scalar(@ARGV) >= 2 and ($command =~ /rpower/)) { | ||||
|         return ([ 1, "Only one option is supported at the same time for $command" ]); | ||||
|     } elsif (scalar(@ARGV) == 0 and $command =~ /rpower|rflash/) { | ||||
| @@ -146,7 +153,6 @@ sub parse_args { | ||||
|     } | ||||
|  | ||||
|     if ($command eq "rflash") { | ||||
|         my $verbose; | ||||
|         my ($activate, $check, $delete, $directory, $list, $upload) = (0) x 6; | ||||
|         my $no_host_reboot; | ||||
|         GetOptions( | ||||
| @@ -156,7 +162,6 @@ sub parse_args { | ||||
|             'd'          => \$directory, | ||||
|             'l|list'     => \$list, | ||||
|             'u|upload'   => \$upload, | ||||
|             'V|verbose'  => \$verbose, | ||||
|             'no-host-reboot' => \$no_host_reboot, | ||||
|         ); | ||||
|         my $option_num = $activate+$check+$delete+$directory+$list+$upload; | ||||
| @@ -200,6 +205,14 @@ sub parse_args { | ||||
|         unless ($subcommand =~ /^on$|^off$|^softoff$|^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$/) { | ||||
|             return ([ 1, "Unsupported command: $command $subcommand" ]); | ||||
|         } | ||||
|     } else { | ||||
|         return ([ 1, "Unsupported command: $command" ]); | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user