2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-22 03:32:04 +00:00

Merge pull request #4786 from zet809/rspconfig_sshcfg

Rspconfig framework for openbmc in python
This commit is contained in:
xuweibj 2018-02-08 13:27:16 +08:00 committed by GitHub
commit acae60a30a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 375 additions and 3 deletions

View File

@ -0,0 +1,42 @@
#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
class BmcConfigInterface(object):
"""Interface for bmc configuration related actions."""
interface_type = 'bmcconfig'
version = '1.0'
def dump_list(self, task):
return task.run('dump_list')
def dump_generate(self, task):
return task.run("dump_generate")
def dump_clear(self, task, id):
return task.run("dump_clear", id)
def dump_download(self, task, id):
return task.run("dump_download", id)
def dump_process(self, task):
return task.run("dump_process")
def set_sshcfg(self, task):
return task.run("set_sshcfg")
def set_ipdhcp(self, task):
return task.run("set_ipdhcp")
def get_attributes(self, task, attributes):
return task.run("get_attributes", attributes)
def set_attributes(self, task, attributes):
return task.run("set_attributes", attributes)
class DefaultBmcConfigManager(BmcConfigInterface):
"""Interface for BmcConfig actions."""
pass

View File

@ -0,0 +1,132 @@
#!/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')
RSPCONFIG_GET_NETINFO=['ip', 'netmask', 'gateway', 'vlan', 'ipsrc', 'hostname']
RSPCONFIG_SET_NETINFO=['ip', 'netmask', 'gateway', 'vlan']
class OpenBMCBmcConfigTask(ParallelNodesCommand):
def dump_list(self, **kw):
return self.callback.info('dump_list')
def dump_generate(self, **kw):
return self.callback.info("dump_generate")
def dump_clear(self, id, **kw):
return self.callback.info("dump_clear id: %s" % id)
def dump_download(self, id, **kw):
return self.callback.info("dump_download id: %s" % id)
def dump_process(self, **kw):
return self.callback.info("dump_process: trigger, list and download")
def set_sshcfg(self, **kw):
return self.callback.info("set_sshcfg")
def set_ipdhcp(self, **kw):
return self.callback.info("set_ipdhcp")
def get_attributes(self, attributes, **kw):
netinfo_dict={}
for attr in attributes:
if attr in RSPCONFIG_GET_NETINFO:
netinfo_dict[attr]=True
getnet=1
elif openbmc.RSPCONFIG_APIS.has_key(attr):
self._get_apis_values(attr, **kw)
else:
self.callback.error("get_attributes can not deal with attr %s" % attr)
if len(netinfo_dict):
self._get_netinfo(netinfo_dict.has_key('ip'), netinfo_dict.has_key('ipsrc'), netinfo_dict.has_key('netmask'),
netinfo_dict.has_key('gateway'), netinfo_dict.has_key('vlan'), netinfo_dict.has_key('hostname'), **kw)
def set_attributes(self, attributes, **kw):
netinfo_dict={'vlan':False}
for attr in attributes:
k,v = attr.split('=')
if k in RSPCONFIG_SET_NETINFO:
netinfo_dict[k] = v
elif k == 'hostname':
self._set_hostname(v, **kw)
elif openbmc.RSPCONFIG_APIS.has_key(k):
self._set_apis_values(k, v, **kw)
else:
return self.callback.error("set_attributes unsupported attribute:%s" % k)
if len(netinfo_dict) > 1 and (not netinfo_dict.has_key('ip') or not netinfo_dict.has_key('netmask') or not netinfo_dict.has_key('gateway')):
self.callback.info("set_attributes miss either ip, netmask or gateway to set network information")
else:
self._set_netinfo(netinfo_dict['ip'], netinfo_dict['netmask'],
netinfo_dict['gateway'], netinfo_dict['vlan'])
def _set_hostname(self, hostname, **kw):
if hostname == '*':
if kw['nodeinfo']['bmc'] != kw['nodeinfo']['bmcip']:
hostname = kw['nodeinfo']['bmc']
else:
hostname = '%s-bmc' % kw['node']
return self.callback.info("set_hostname: %s" % hostname)
def _set_apis_values(self, key, value, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
obmc.set_apis_values(key, value)
except (SelfServerException, SelfClientException) as e:
self.callback.info("%s: %s" % (node, e.message))
self.callback.info("%s: BMC Setting %s..." % (node, openbmc.RSPCONFIG_APIS[key]['display_name']))
def _get_apis_values(self, key, **kw):
node = kw['node']
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
debugmode=self.debugmode, verbose=self.verbose)
try:
obmc.login()
value = obmc.get_apis_values(key)
except (SelfServerException, SelfClientException) as e:
self.callback.info('%s: %s' % (node, e.message))
str_value = '0.'+str(value)
result = '%s: %s: %s' % (node, openbmc.RSPCONFIG_APIS[key]['display_name'], str_value.split('.')[-1])
self.callback.info(result)
def _set_netinfo(self, ip, netmask, gateway, vlan=False, **kw):
if vlan:
result = "set net(%s, %s, %s) for vlan %s" % (ip, netmask, gateway, vlan)
else:
result = "set net(%s, %s, %s) for eth0" % (ip, netmask, gateway)
return self.callback.info("set_netinfo %s" % result)
def _get_netinfo(self, ip=False, ipsrc=False, netmask=False, gateway=False, vlan=False, hostname=False, **kw):
result = ''
if ip:
result += "Get IP, "
if netmask:
result += "Get Mask, "
if gateway:
result += "Get Gateway, "
if ipsrc:
result += "Get IP source, "
if hostname:
result += "Get BMC hostname, "
if vlan:
result += "Get BMC vlan."
return self.callback.info("get_netinfo: %s" % result)

View File

@ -141,6 +141,49 @@ FIRM_URLS = {
}
}
RSPCONFIG_APIS = {
'autoreboot' : {
'baseurl': "/control/host0/auto_reboot/",
'set_url': "attr/AutoReboot",
'get_url': "attr/AutoReboot",
'display_name': "BMC AutoReboot",
},
'powersupplyredundancy':{
'baseurl': "/sensors/chassis/PowerSupplyRedundancy/",
'set_url': "/action/setValue",
'get_url': "/action/getValue",
'get_method': 'POST',
'get_data': '[]',
'display_name': "BMC PowerSupplyRedundancy",
'attr_values': {
'disabled': "Disables",
'enabled': "Enabled",
},
},
'powerrestorepolicy': {
'baseurl': "/control/host0/power_restore_policy/",
'set_url': "attr/PowerRestorePolicy",
'get_url': "attr/PowerRestorePolicy",
'display_name': "BMC PowerRestorePolicy",
'attr_values': {
'restore': "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
'always_on': "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
'always_off': "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
},
},
'bootmode': {
'baseurl': "/control/host0/boot/",
'set_url': "attr/BootMode",
'get_url': "attr/BootMode",
'display_name':"BMC BootMode",
'attr_values': {
'regular': "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular",
'safe': "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe",
'setup': "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup",
},
},
}
RESULT_OK = 'ok'
RESULT_FAIL = 'fail'
@ -443,6 +486,31 @@ class OpenBMCRest(object):
return bool(func_list), fw_dict
def set_apis_values(self, key, value):
attr_info = RSPCONFIG_APIS[key]
if not attr_info.has_key('set_url'):
raise SelfServerException("config %s failed, not url available" % key)
set_url = attr_info['baseurl']+attr_info['set_url']
if attr_info.has_key('attr_values') and attr_info['attr_values'].has_key(value):
data = attr_info['attr_values'][value]
else:
data = value
self.request('PUT', set_url, payload={"data": data}, cmd="set_%s" % key)
def get_apis_values(self, key):
attr_info = RSPCONFIG_APIS[key]
if not attr_info.has_key('get_url'):
raise SelfServerException("Reading %s failed, not url available" % key)
get_url = attr_info['baseurl']+attr_info['get_url']
method = 'GET'
if attr_info.has_key('get_method'):
method = attr_info['get_method']
data = None
if attr_info.has_key('get_data'):
data={"data": attr_info['get_data']}
return self.request(method, get_url, payload=data, cmd="get_%s" % key)
class OpenBMCImage(object):
def __init__(self, rawid, data=None):
self.id = rawid.split('/')[-1]

View File

@ -9,7 +9,8 @@ import os
import time
import sys
import gevent
from docopt import docopt
import re
from docopt import docopt,DocoptExit
from common import utils
from common import exceptions as xcat_exception
@ -18,11 +19,13 @@ from hwctl.executor.openbmc_setboot import OpenBMCBootTask
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_bmcconfig import OpenBMCBmcConfigTask
from hwctl.beacon import DefaultBeaconManager
from hwctl.setboot import DefaultBootManager
from hwctl.inventory import DefaultInventoryManager
from hwctl.power import DefaultPowerManager
from hwctl.sensor import DefaultSensorManager
from hwctl.bmcconfig import DefaultBmcConfigManager
from xcatagent import base
import openbmc_rest
@ -77,6 +80,46 @@ RFLASH_URLS = {
}
}
RSPCONFIG_GET_OPTIONS = ['ip','ipsrc','netmask','gateway','vlan','hostname','bootmode','autoreboot','powersupplyredundancy','powerrestorepolicy']
RSPCONFIG_SET_OPTIONS = {
'ip':'.*',
'netmask':'.*',
'gateway':'.*',
'vlan':'\d+',
'hostname':"\*|.*",
'autoreboot':"^0|1$",
'powersupplyredundancy':"^enabled$|^disabled$",
'powerrestorepolicy':"^always_on$|^always_off$|^restore$",
'bootmode':"^regular$|^safe$|^setup$",
}
RSPCONFIG_USAGE = """
Handle rspconfig operations.
Usage:
rspconfig -h|--help
rspconfig dump [[-l|--list] | [-g|--generate] | [-c|--clear <arg>] | [-d|--download <arg>]] [-V|--verbose]
rspconfig sshcfg [-V|--verbose]
rspconfig ip=dhcp [-V|--verbose]
rspconfig get [<args>...] [-V|--verbose]
rspconfig set [<args>...] [-V|--verbose]
Options:
-V,--verbose Show verbose message
-l,--list List are dump files
-g,--generate Trigger a new dump file
-c,--clear <arg> The id of file to clear or all if specify 'all'
-d,--download <arg> The id of file to download or all if specify 'all'
The supported attributes to get are: %s
The supported attributes and its values to set are:
ip=<ip address> netmask=<mask> gateway=<gateway> [vlan=<vlanid>]
hostname=*|<string>
autoreboot={0|1}
powersupplyredundancy={enabled|disabled}
powerrestorepolicy={always_on|always_off|restore}
""" % RSPCONFIG_GET_OPTIONS
XCAT_LOG_DIR = "/var/log/xcat"
XCAT_LOG_RFLASH_DIR = XCAT_LOG_DIR + "/rflash/"
@ -663,7 +706,56 @@ class OpenBMCManager(base.BaseManager):
DefaultPowerManager().reboot(runner, optype=action)
else:
DefaultPowerManager().set_power_state(runner, power_state=action)
def rspconfig(self, nodesinfo, args):
try:
opts=docopt(RSPCONFIG_USAGE, argv=args)
except DocoptExit as e:
self.messager.error("Failed to parse args by docopt: %s" % e)
return
except Exception as e:
self.messager.error("Failed to parse arguments for rspconfig: %s" % args)
return
self.verbose=opts.pop('--verbose')
runner = OpenBMCBmcConfigTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
if opts['dump']:
if opts['--list']:
DefaultBmcConfigManager().dump_list(runner)
elif opts['--generate']:
DefaultBmcConfigManager().dump_generate(runner)
elif opts['--clear']:
DefaultBmcConfigManager().dump_clear(runner, opts['--clear'])
elif opts['--download']:
DefaultBmcConfigManager().dump_download(runner, opts['--download'])
else:
DefaultBmcConfigManager().dump_process(runner)
elif opts['sshcfg']:
DefaultBmcConfigManager().set_sshcfg(runner)
elif opts['ip=dhcp']:
DefaultBmcConfigManager().set_ipdhcp(runner)
elif opts['get']:
unsupport_list=list(set(opts['<args>']) - set(RSPCONFIG_GET_OPTIONS))
if len(unsupport_list) > 0:
self.messager.error("Have unsupported option: %s" % unsupport_args)
return
else:
DefaultBmcConfigManager().get_attributes(runner, opts['<args>'])
elif opts['set']:
rc=0
for attr in opts['<args>']:
k,v = attr.split('=')
if not RSPCONFIG_SET_OPTIONS.has_key(k):
self.messager.error("The attribute %s is not support to set" % k)
rc=1
elif not re.match(RSPCONFIG_SET_OPTIONS[k], v):
self.messager.error("The value %s is invalid for %s" %(v, k))
rc=1
if rc:
return
else:
DefaultBmcConfigManager().set_attributes(runner, opts['<args>'])
else:
self.messager.error("Failed to deal with rspconfig: %s" % args)
def rsetboot(self, nodesinfo, args):
# 1, parse args
@ -736,7 +828,6 @@ class OpenBMCManager(base.BaseManager):
else:
DefaultSensorManager().get_sensor_info(runner, action)
def _get_full_path(self,file_path):
if type(self.cwd) == 'unicode':
dir_path = self.cwd

View File

@ -92,8 +92,12 @@ class Server(object):
if not hasattr(manager, req['command']):
messager.error("command %s is not supported" % req['command'])
func = getattr(manager, req['command'])
# translate unicode string to normal string to avoid docopt error
new_args=[]
for a in req['args']:
new_args.append(a.encode('utf-8'))
# call the function in the specified manager
func(req['nodeinfo'], req['args'])
func(req['nodeinfo'], new_args)
# after the method returns, the request should be handled
# completely, close the socket for client
if not self.standalone:

View File

@ -17,6 +17,7 @@ use xCAT::Utils;
use xCAT::Usage;
use xCAT::SvrUtils;
use xCAT::OPENBMC;
use xCAT_plugin::openbmc;
#-------------------------------------------------------
@ -36,6 +37,7 @@ sub handled_commands {
rpower => 'nodehm:mgt=openbmc',
rsetboot => 'nodehm:mgt=openbmc',
rvitals => 'nodehm:mgt=openbmc',
rspconfig => 'nodehm:mgt=openbmc',
};
}
@ -114,6 +116,10 @@ sub process_request {
$callback = shift;
my $noderange = $request->{node};
my $check = parse_node_info($noderange);
if (&refactor_args($request)) {
xCAT::MsgUtils->message("E", { data => ["Failed to refactor arguments"] }, $callback);
return;
}
$callback->({ errorcode => [$check] }) if ($check);
return unless(%node_info);
my $pid = xCAT::OPENBMC::start_python_agent();
@ -231,6 +237,8 @@ sub parse_args {
unless ($subcommand =~ /^all$|^altitude$|^fanspeed$|^leds$|^power$|^temp$|^voltage$|^wattage$/) {
return ([ 1, "Unsupported command: $command $subcommand" ]);
}
} elsif ($command eq 'rspconfig') {
xCAT_plugin::openbmc::parse_args('rspconfig', $extrargs, $noderange);
} else {
return ([ 1, "Unsupported command: $command" ]);
}
@ -304,4 +312,31 @@ sub parse_node_info {
return $rst;
}
#-------------------------------------------------------
=head3 refactor_args
refractor args to be easily dealt by python client
=cut
#-------------------------------------------------------
sub refactor_args {
my $request = shift;
my $command = $request->{command}->[0];
my $extrargs = $request->{arg};
if ($command eq "rspconfig") {
my $subcommand = $extrargs->[0];
if ($subcommand !~ /^dump$|^sshcfg$|^ip=dhcp$/) {
if (grep /=/, @$extrargs) {
unshift @$extrargs, "set";
} else {
unshift @$extrargs, "get";
}
}
}
return 0;
}
1;