2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-06-13 09:50:19 +00:00

rsetboot for openbmc in python (#4784)

* rsetboot for openbmc in python
This commit is contained in:
xuweibj
2018-02-05 16:42:37 +08:00
committed by Bin Xu
parent 44938a324a
commit 64f8602755
5 changed files with 223 additions and 2 deletions

View File

@ -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)

View File

@ -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)

View 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

View File

@ -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

View File

@ -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" ]);
}