"""
Tools for datacenter or physical management of ACCRE hardware
"""
import subprocess
from time import sleep
import sys
from accre.dcim.client import DCIMClient
from accre.config import get_config
from accre.util import accre_argparser, RedStr, GreenStr
CONFIG = get_config()
[docs]def blink_locate_led(
hostname,
make='dell',
blinktime=15,
verbose=False,
ssh=True
):
"""
Cause the location LED of the node chassis to blink for a while
to locate the node.
..note::
You must be root on a node with passwordless root ssh
to all other nodes for this function to work
:param str hostname: Hostname of the node to blink
:param str make: Manufacturer of the chassis. Defaults to dell,
and if set to supermicro will use an alternative command
to blink the indicator light
:param int blinktime: Seconds to blink the location LED
:param bool verbose: If true, print information in real time
to stdout about the operation and wait for completion
:param bool ssh: use ssh to connect to servers if true, rsh if false
:returns: True if the command(s) succeeded as determined by exit code.
:rtype: bool
"""
if make == 'supermicro':
start_cmd = ['ipmitool', 'raw', '0x30', '0xd']
end_cmd = ['ipmitool', 'raw', '0x30', '0xe']
else:
start_cmd = ['ipmitool', 'chassis', 'identify', str(blinktime)]
end_cmd = None
if ssh:
start_cmd = ['ssh', '-oBatchMode=yes', hostname] + start_cmd
if end_cmd is not None:
end_cmd = ['ssh', '-oBatchMode=yes', hostname] + end_cmd
else:
start_cmd = ['rsh', hostname] + start_cmd
if end_cmd is not None:
end_cmd = ['rsh', hostname] + end_cmd
try:
retval = subprocess.call(start_cmd, timeout=15)
except subprocess.TimeoutExpired:
retval = -1
if retval != 0:
if verbose:
print(
'[ {0} ] - Set LED for {1}'.format(RedStr('ERROR'), hostname)
)
return False
if verbose:
print('[ {0} ] - {1}: '.format(GreenStr('OK'), hostname), end='')
sys.stdout.flush()
if end_cmd is None and not verbose:
return True
elif end_cmd is None:
for _ in range(blinktime):
print('.', end='')
sys.stdout.flush()
sleep(1)
print(' [ {0} ]'.format(GreenStr('DONE')))
return True
try:
retval = subprocess.call(end_cmd, timeout=15)
except subprocess.TimeoutExpired:
retval = -1
if retval != 0:
if verbose:
print(' [ {0} ]'.format(RedStr('RESET ERROR')))
return False
if verbose:
print(' [ {0} ]'.format(GreenStr('DONE')))
return True
[docs]def griswold(cabinet, blinktime=15, ssh=True):
"""
Cause all servers in a cabinet (as known in OpenDCIM) to blink
in sequence from highest to lowest position and print information
about the make, model, and serial number/service tag of each
physical server.
..note::
You must be root on a node with passwordless root ssh
to all other nodes for this function to work
..todo:: Add support for blades/child servers
:param str cabinet: Cabinet location, ex. "H15"
:param int blinktime: Time to spend locating each server
:param bool ssh: use ssh to connect to servers if true, rsh if false
:returns: True if all servers blinked successfully, false if errors
:rtype: bool
"""
with DCIMClient(caching=True) as client:
devices = client.get_cabinet_devices(cabinet, nochildren=True)
servers = [d for d in devices if d['DeviceType'] == 'Server']
servers.sort(key=lambda s: s['Position'], reverse=True)
everything_ok = True
for server in servers:
hostname = server['Label']
position = server['Position']
info = client.model(hostname)
msg = 'U{0} contains {1}, a {2} {3} with SN={4}'.format(
position, hostname,
info['make'], info['model'], info['serial']
)
print(msg)
result = blink_locate_led(
hostname,
blinktime=blinktime,
ssh=ssh,
verbose=True
)
if not result:
everything_ok = False
return everything_ok
[docs]def griswold_cli():
"""
CLI entry point for the griswold function.
Use ``griswold --help`` for usage.
"""
description = (
'Check locate LEDs on all servers on a given cabinet,'
' and spread the holiday cheer.'
)
parser = accre_argparser('griswold', description=description)
parser.add_argument('cabinet',
help="Cabinet to light up with holiday cheer"
)
parser.add_argument('-s', '--seconds',
action='store',
default=15,
type=int,
help="Number of seconds to blink for"
)
parser.add_argument('-n', '--nossl',
action='store_true',
help="Use rsh instead of ssh"
)
args = parser.parse_args()
ssh = True
if args.nossl:
ssh = False
msg = (
'This command will spread holiday cheer to rack {0}! Are you sure?'
.format(args.cabinet)
)
cheer = input(msg)
if not cheer.lower().startswith('y'):
sys.exit(1)
griswold(args.cabinet, blinktime=args.seconds, ssh=ssh)
if __name__ == '__main__':
griswold_cli()