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