mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-22 03:32:04 +00:00
rbeacon & rvitals for openbmc in python (#4795)
* rbeacon & rvitals for openbmc in python
This commit is contained in:
parent
09ee65672c
commit
ce3a32fdeb
@ -7,6 +7,7 @@
|
||||
import struct
|
||||
import sys
|
||||
import inspect
|
||||
import re
|
||||
import logging
|
||||
from logging.handlers import SysLogHandler
|
||||
|
||||
@ -70,6 +71,17 @@ def update2Ddict(updata_dict, key_a, key_b, value):
|
||||
else:
|
||||
updata_dict.update({key_a: {key_b: value}})
|
||||
|
||||
def emb_numbers(string):
|
||||
re_digits = re.compile(r'(\d+)')
|
||||
pieces = re_digits.split(string)
|
||||
pieces[1::2] = map(int,pieces[1::2])
|
||||
return pieces
|
||||
|
||||
def sort_string_with_numbers(origin_list):
|
||||
new_list = [(emb_numbers(string),string) for string in origin_list]
|
||||
new_list.sort()
|
||||
return [string for __,string in new_list]
|
||||
|
||||
class Messager(object):
|
||||
def __init__(self, name=None):
|
||||
self.logger = logging.getLogger(name or 'xcatagent')
|
||||
|
26
xCAT-openbmc-py/lib/python/agent/hwctl/beacon.py
Normal file
26
xCAT-openbmc-py/lib/python/agent/hwctl/beacon.py
Normal file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
###############################################################################
|
||||
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
|
||||
###############################################################################
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
class BeaconInterface(object):
|
||||
"""Interface for beacon-related actions."""
|
||||
interface_type = 'beacon'
|
||||
version = '1.0'
|
||||
|
||||
def set_beacon_state(self, task, beacon_state, timeout=None):
|
||||
"""Set the beacon state of the task's nodes.
|
||||
|
||||
:param task: a Task instance containing the nodes to act on.
|
||||
:param beacon_state: on|off beacon state.
|
||||
:param timeout: timeout (in seconds) positive integer (> 0) for any
|
||||
beacon state. ``None`` indicates to use default timeout.
|
||||
"""
|
||||
return task.run('set_state', beacon_state, timeout=timeout)
|
||||
|
||||
|
||||
class DefaultBeaconManager(BeaconInterface):
|
||||
"""Interface for beacon-related actions."""
|
||||
pass
|
@ -0,0 +1,35 @@
|
||||
#!/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 OpenBMCBeaconTask(ParallelNodesCommand):
|
||||
"""Executor for beacon-related actions."""
|
||||
|
||||
def set_state(self, state, **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_beacon_state(state)
|
||||
result = '%s: %s' % (node, state)
|
||||
|
||||
except (SelfServerException, SelfClientException) as e:
|
||||
result = '%s: %s' % (node, e.message)
|
||||
|
||||
self.callback.info(result)
|
@ -0,0 +1,118 @@
|
||||
#!/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
|
||||
from common import utils
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger('xcatagent')
|
||||
|
||||
|
||||
SENSOR_TYPE_UNIT = {
|
||||
"altitude" : "Meters",
|
||||
"fanspeed" : "RPMS",
|
||||
"temp" : "DegreesC",
|
||||
"voltage" : "Volts",
|
||||
"wattage" : "Watts",
|
||||
}
|
||||
|
||||
SENSOR_POWER_UNITS = ("Amperes", "Joules", "Watts")
|
||||
|
||||
|
||||
class OpenBMCSensorTask(ParallelNodesCommand):
|
||||
"""Executor for sensor-related actions."""
|
||||
|
||||
def _get_beacon_info(self, beacon_dict):
|
||||
|
||||
info_list = []
|
||||
info_list.append('Front . . . . . : Power:%s Fault:%s Identify:%s' %
|
||||
(beacon_dict.get('front_power', 'N/A'),
|
||||
beacon_dict.get('front_fault', 'N/A'),
|
||||
beacon_dict.get('front_id', 'N/A')))
|
||||
if (beacon_dict.get('fan0', 'N/A') == 'Off' and beacon_dict.get('fan1', 'N/A') == 'Off' and
|
||||
beacon_dict.get('fan2', 'N/A') == 'Off' and beacon_dict.get('fan3', 'N/A') == 'Off'):
|
||||
info_list.append('Front Fans . . : No LEDs On')
|
||||
else:
|
||||
info_list.append('Front Fans . . : fan0:%s fan1:%s fan2:%s fan3:%s' %
|
||||
(beacon_dict.get('fan0', 'N/A'), beacon_dict.get('fan1', 'N/A'),
|
||||
beacon_dict.get('fan2', 'N/A'), beacon_dict.get('fan3', 'N/A')))
|
||||
info_list.append('Rear . . . . . : Power:%s Fault:%s Identify:%s' %
|
||||
(beacon_dict.get('rear_power', 'N/A'),
|
||||
beacon_dict.get('rear_fault', 'N/A'),
|
||||
beacon_dict.get('rear_id', 'N/A')))
|
||||
return info_list
|
||||
|
||||
|
||||
def get_sensor_info(self, sensor_type, **kw):
|
||||
|
||||
node = kw['node']
|
||||
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
|
||||
debugmode=self.debugmode, verbose=self.verbose)
|
||||
|
||||
sensor_info = []
|
||||
try:
|
||||
obmc.login()
|
||||
sensor_info_dict = obmc.get_sensor_info()
|
||||
|
||||
if sensor_type == 'all' or not sensor_type:
|
||||
for sensor_key in sensor_info_dict:
|
||||
sensor_info += sensor_info_dict[sensor_key]
|
||||
sensor_info = utils.sort_string_with_numbers(sensor_info)
|
||||
beacon_dict = obmc.get_beacon_info()
|
||||
sensor_info += self._get_beacon_info(beacon_dict)
|
||||
elif sensor_type == 'power':
|
||||
for sensor_key in sensor_info_dict:
|
||||
if sensor_key in SENSOR_POWER_UNITS:
|
||||
sensor_info += sensor_info_dict[sensor_key]
|
||||
sensor_info = utils.sort_string_with_numbers(sensor_info)
|
||||
else:
|
||||
sensor_unit = SENSOR_TYPE_UNIT[sensor_type]
|
||||
if sensor_unit in sensor_info_dict:
|
||||
sensor_info += sensor_info_dict[sensor_unit]
|
||||
sensor_info = utils.sort_string_with_numbers(sensor_info)
|
||||
|
||||
if not sensor_info:
|
||||
sensor_info = ['No attributes returned from the BMC.']
|
||||
|
||||
for info in sensor_info:
|
||||
self.callback.info( '%s: %s' % (node, info))
|
||||
|
||||
except (SelfServerException, SelfClientException) as e:
|
||||
self.callback.info('%s: %s' % (node, e.message))
|
||||
|
||||
return sensor_info
|
||||
|
||||
def get_beacon_info(self, **kw):
|
||||
|
||||
node = kw['node']
|
||||
obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback,
|
||||
debugmode=self.debugmode, verbose=self.verbose)
|
||||
|
||||
beacon_info = []
|
||||
try:
|
||||
obmc.login()
|
||||
beacon_dict = obmc.get_beacon_info()
|
||||
beacon_info = self._get_beacon_info(beacon_dict)
|
||||
|
||||
if not beacon_info:
|
||||
beacon_info = ['No attributes returned from the BMC.']
|
||||
|
||||
for info in beacon_info:
|
||||
self.callback.info( '%s: %s' % (node, info))
|
||||
|
||||
except (SelfServerException, SelfClientException) as e:
|
||||
self.callback.info('%s: %s' % (node, e.message))
|
||||
|
||||
return beacon_info
|
||||
|
||||
|
@ -19,6 +19,34 @@ HTTP_PROTOCOL = "https://"
|
||||
PROJECT_URL = "/xyz/openbmc_project"
|
||||
PROJECT_PAYLOAD = "xyz.openbmc_project."
|
||||
|
||||
RBEACON_URLS = {
|
||||
"path" : "/led/groups/enclosure_identify/attr/Asserted",
|
||||
"on" : {
|
||||
"field" : True,
|
||||
},
|
||||
"off" : {
|
||||
"field" : False,
|
||||
},
|
||||
}
|
||||
|
||||
LEDS_URL = "/led/physical/enumerate"
|
||||
|
||||
LEDS_KEY_LIST = ("fan0", "fan1", "fan2", "fan3",
|
||||
"front_id", "front_fault", "front_power",
|
||||
"rear_id", "rear_fault", "rear_power")
|
||||
|
||||
SENSOR_URL = "/sensors/enumerate"
|
||||
|
||||
SENSOR_UNITS = {
|
||||
"Amperes" : "Amps",
|
||||
"DegreesC" : "C",
|
||||
"Joules" : "Joules",
|
||||
"Meters" : "Meters",
|
||||
"RPMS" : "RPMS",
|
||||
"Volts" : "Volts",
|
||||
"Watts" : "Watts",
|
||||
}
|
||||
|
||||
RPOWER_STATES = {
|
||||
"on" : "on",
|
||||
"off" : "off",
|
||||
@ -308,6 +336,52 @@ class OpenBMCRest(object):
|
||||
error = 'Error: Received wrong format response: %s' % states
|
||||
raise SelfServerException(error)
|
||||
|
||||
def get_beacon_info(self):
|
||||
|
||||
beacon_data = self.request('GET', LEDS_URL, cmd='get_beacon_info')
|
||||
try:
|
||||
beacon_dict = {}
|
||||
for key, value in beacon_data.items():
|
||||
key_id = key.split('/')[-1]
|
||||
if key_id in LEDS_KEY_LIST:
|
||||
beacon_dict[key_id] = value['State'].split('.')[-1]
|
||||
return beacon_dict
|
||||
except KeyError:
|
||||
error = 'Error: Received wrong format response: %s' % beacon_data
|
||||
raise SelfServerException(error)
|
||||
|
||||
def set_beacon_state(self, state):
|
||||
|
||||
payload = { "data": RBEACON_URLS[state]['field'] }
|
||||
self.request('PUT', RBEACON_URLS['path'], payload=payload, cmd='set_beacon_state')
|
||||
|
||||
def get_sensor_info(self):
|
||||
|
||||
sensor_data = self.request('GET', SENSOR_URL, cmd='get_sensor_info')
|
||||
try:
|
||||
sensor_dict = {}
|
||||
for k, v in sensor_data.items():
|
||||
if 'Unit' in v:
|
||||
unit = v['Unit'].split('.')[-1]
|
||||
if unit in SENSOR_UNITS:
|
||||
label = k.split('/')[-1].replace('_', ' ').title()
|
||||
value = v['Value']
|
||||
scale = v['Scale']
|
||||
value = value * pow(10, scale)
|
||||
value = '{:g}'.format(value)
|
||||
if unit not in sensor_dict:
|
||||
sensor_dict[unit] = []
|
||||
sensor_dict[unit].append('%s: %s %s' % (label, value, SENSOR_UNITS[unit]))
|
||||
elif 'units' in v and 'value' in v:
|
||||
label = k.split('/')[-1]
|
||||
value = v['value']
|
||||
sensor_dict[label] = ['%s: %s' % (label, value)]
|
||||
|
||||
return sensor_dict
|
||||
except KeyError:
|
||||
error = 'Error: Received wrong format response: %s' % sensor_data
|
||||
raise SelfServerException(error)
|
||||
|
||||
def list_firmware(self):
|
||||
|
||||
data = self.request('GET', FIRM_URLS['list']['path'], cmd='list_firmware')
|
||||
@ -347,3 +421,4 @@ class OpenBMCImage(object):
|
||||
|
||||
def __str__(self):
|
||||
return '%s-%s' % (self.purpose, self.id)
|
||||
|
||||
|
32
xCAT-openbmc-py/lib/python/agent/hwctl/sensor.py
Normal file
32
xCAT-openbmc-py/lib/python/agent/hwctl/sensor.py
Normal file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
###############################################################################
|
||||
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
|
||||
###############################################################################
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
class SensorInterface(object):
|
||||
"""Interface for sensor-related actions."""
|
||||
interface_type = 'sensor'
|
||||
version = '1.0'
|
||||
|
||||
def get_sensor_info(self, task, sensor_type=None):
|
||||
"""Return the sensor info of the task's nodes.
|
||||
|
||||
:param sensor_type: type of sensor info want to get.
|
||||
:param task: a Task instance containing the nodes to act on.
|
||||
:return: sensor info list
|
||||
"""
|
||||
return task.run('get_sensor_info', sensor_type)
|
||||
|
||||
def get_beacon_info(self, task):
|
||||
"""Return the beacon info of the task's nodes.
|
||||
|
||||
:param task: a Task instance containing the nodes to act on.
|
||||
:return: beacon info list
|
||||
"""
|
||||
return task.run('get_beacon_info')
|
||||
|
||||
class DefaultSensorManager(SensorInterface):
|
||||
"""Interface for sensor-related actions."""
|
||||
pass
|
@ -13,10 +13,14 @@ from docopt import docopt
|
||||
|
||||
from common import utils
|
||||
from common import exceptions as xcat_exception
|
||||
from hwctl.executor.openbmc_beacon import OpenBMCBeaconTask
|
||||
from hwctl.executor.openbmc_power import OpenBMCPowerTask
|
||||
from hwctl.executor.openbmc_setboot import OpenBMCBootTask
|
||||
from hwctl.executor.openbmc_sensor import OpenBMCSensorTask
|
||||
from hwctl.beacon import DefaultBeaconManager
|
||||
from hwctl.power import DefaultPowerManager
|
||||
from hwctl.setboot import DefaultBootManager
|
||||
from hwctl.sensor import DefaultSensorManager
|
||||
|
||||
from xcatagent import base
|
||||
import openbmc_rest
|
||||
@ -36,6 +40,9 @@ VERBOSE = False
|
||||
|
||||
all_nodes_result = {}
|
||||
|
||||
# global variables of rbeacon
|
||||
BEACON_SET_OPTIONS = ('on', 'off')
|
||||
|
||||
# global variables of rflash
|
||||
RFLASH_OPTIONS = {
|
||||
"-a" : "activate",
|
||||
@ -83,6 +90,10 @@ POWER_GET_OPTIONS = ('bmcstate', 'state', 'stat', 'status')
|
||||
SETBOOT_GET_OPTIONS = ('stat', '')
|
||||
SETBOOT_SET_OPTIONS = ('cd', 'def', 'default', 'hd', 'net')
|
||||
|
||||
# global variables of rvitals
|
||||
VITALS_OPTIONS = ('all', 'altitude', 'fanspeed', 'leds', 'power',
|
||||
'temp', 'voltage', 'wattage')
|
||||
|
||||
class OpenBMC(base.BaseDriver):
|
||||
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
@ -541,6 +552,39 @@ class OpenBMCManager(base.BaseManager):
|
||||
if self.debugmode:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
def rbeacon(self, nodesinfo, args):
|
||||
|
||||
# 1, parse args
|
||||
rbeacon_usage = """
|
||||
Usage:
|
||||
rbeacon [-V|--verbose] [on|off]
|
||||
|
||||
Options:
|
||||
-V --verbose rbeacon verbose mode.
|
||||
"""
|
||||
|
||||
try:
|
||||
opts = docopt(rbeacon_usage, argv=args)
|
||||
|
||||
self.verbose = opts.pop('--verbose')
|
||||
action = [k for k,v in opts.items() if v][0]
|
||||
except Exception as e:
|
||||
self.messager.error("Failed to parse arguments for rbeacon: %s" % args)
|
||||
return
|
||||
|
||||
# 2, validate the args
|
||||
if action is None:
|
||||
self.messager.error("Not specify the subcommand for rbeacon")
|
||||
return
|
||||
|
||||
if action not in BEACON_SET_OPTIONS:
|
||||
self.messager.error("Not supported subcommand for rbeacon: %s" % action)
|
||||
return
|
||||
|
||||
# 3, run the subcommands
|
||||
runner = OpenBMCBeaconTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
|
||||
DefaultBeaconManager().set_beacon_state(runner, beacon_state=action)
|
||||
|
||||
def rpower(self, nodesinfo, args):
|
||||
|
||||
# 1, parse args
|
||||
@ -617,6 +661,41 @@ class OpenBMCManager(base.BaseManager):
|
||||
else:
|
||||
DefaultBootManager().set_boot_state(runner, setboot_state=action, persistant=action_type)
|
||||
|
||||
def rvitals(self, nodesinfo, args):
|
||||
|
||||
# 1, parse agrs
|
||||
if not args:
|
||||
args = ['all']
|
||||
|
||||
rvitals_usage = """
|
||||
Usage:
|
||||
rvitals [-V|--verbose] [all|altitude|fanspeed|leds|power|temp|voltage|wattage]
|
||||
|
||||
Options:
|
||||
-V --verbose rvitals verbose mode.
|
||||
"""
|
||||
|
||||
try:
|
||||
opts = docopt(rvitals_usage, argv=args)
|
||||
|
||||
self.verbose = opts.pop('--verbose')
|
||||
action = [k for k,v in opts.items() if v][0]
|
||||
except Exception as e:
|
||||
self.messager.error("Failed to parse arguments for rvitals: %s" % args)
|
||||
return
|
||||
|
||||
# 2, validate the args
|
||||
if action not in VITALS_OPTIONS:
|
||||
self.messager.error("Not supported subcommand for rvitals: %s" % action)
|
||||
return
|
||||
|
||||
# 3, run the subcommands
|
||||
runner = OpenBMCSensorTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose)
|
||||
if action == 'leds':
|
||||
DefaultSensorManager().get_beacon_info(runner)
|
||||
else:
|
||||
DefaultSensorManager().get_sensor_info(runner, action)
|
||||
|
||||
|
||||
def _get_full_path(self,file_path):
|
||||
if type(self.cwd) == 'unicode':
|
||||
|
@ -30,8 +30,11 @@ use xCAT::OPENBMC;
|
||||
|
||||
sub handled_commands {
|
||||
return {
|
||||
rbeacon => 'nodehm:mgt=openbmc',
|
||||
rflash => 'nodehm:mgt=openbmc',
|
||||
rpower => 'nodehm:mgt=openbmc',
|
||||
rsetboot => 'nodehm:mgt=openbmc',
|
||||
rvitals => 'nodehm:mgt=openbmc',
|
||||
};
|
||||
}
|
||||
|
||||
@ -144,15 +147,19 @@ sub parse_args {
|
||||
return ([ 1, "Error parsing arguments." ]);
|
||||
}
|
||||
|
||||
if (scalar(@ARGV) >= 2 and ($command =~ /rpower/)) {
|
||||
if (scalar(@ARGV) >= 2 and ($command =~ /rbeacon|rpower|rvitals/)) {
|
||||
return ([ 1, "Only one option is supported at the same time for $command" ]);
|
||||
} elsif (scalar(@ARGV) == 0 and $command =~ /rpower|rflash/) {
|
||||
} elsif (scalar(@ARGV) == 0 and $command =~ /rbeacon|rpower|rflash/) {
|
||||
return ([ 1, "No option specified for $command" ]);
|
||||
} else {
|
||||
$subcommand = $ARGV[0];
|
||||
}
|
||||
|
||||
if ($command eq "rflash") {
|
||||
if ($command eq "rbeacon") {
|
||||
unless ($subcommand =~ /^on$|^off$/) {
|
||||
return ([ 1, "Only 'on' or 'off' is supported for OpenBMC managed nodes."]);
|
||||
}
|
||||
} elsif ($command eq "rflash") {
|
||||
my ($activate, $check, $delete, $directory, $list, $upload) = (0) x 6;
|
||||
my $no_host_reboot;
|
||||
GetOptions(
|
||||
@ -173,7 +180,7 @@ sub parse_args {
|
||||
return ([ 1, "Unsupported command: $command $arg" ]);
|
||||
}
|
||||
}
|
||||
return ([ 1, "No options specified."]);
|
||||
return ([ 1, "No options specified." ]);
|
||||
}
|
||||
if ($activate or $check or $delete or $upload) {
|
||||
return ([ 1, "More than one firmware specified is not supported."]) if ($#ARGV >= 1);
|
||||
@ -213,6 +220,11 @@ sub parse_args {
|
||||
unless ($subcommand =~ /^net$|^hd$|^cd$|^def$|^default$|^stat$/) {
|
||||
return ([ 1, "Unsupported command: $command $subcommand" ]);
|
||||
}
|
||||
} elsif ($command eq "rvitals") {
|
||||
$subcommand = "all" if (!defined($ARGV[0]));
|
||||
unless ($subcommand =~ /^all$|^altitude$|^fanspeed$|^leds$|^power$|^temp$|^voltage$|^wattage$/) {
|
||||
return ([ 1, "Unsupported command: $command $subcommand" ]);
|
||||
}
|
||||
} else {
|
||||
return ([ 1, "Unsupported command: $command" ]);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user