/usr/lib/python2.7/dist-packages/provisioningserver/drivers/hardware/mscm.py is in python-maas-provisioningserver 1.5.4+bzr2294-0ubuntu1.2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | # Copyright 2014 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Support for managing nodes via the Moonshot HP iLO Chassis Manager CLI.
This module provides support for interacting with HP Moonshot iLO Chassis
Management (MSCM) CLI via SSH, and for using that support to allow MAAS to
manage systems via iLO.
"""
from __future__ import (
absolute_import,
print_function,
unicode_literals,
)
str = None
__metaclass__ = type
__all__ = [
'power_control_mscm',
'probe_and_enlist_mscm',
]
import re
from paramiko import (
AutoAddPolicy,
SSHClient,
)
import provisioningserver.custom_hardware.utils as utils
cartridge_mapping = {
'ProLiant Moonshot Cartridge': 'amd64/generic',
'ProLiant m300 Server Cartridge': 'amd64/generic',
'ProLiant m350 Server Cartridge': 'amd64/generic',
'ProLiant m400 Server Cartridge': 'arm64/xgene-uboot',
'ProLiant m500 Server Cartridge': 'amd64/generic',
'ProLiant m710 Server Cartridge': 'amd64/generic',
'ProLiant m800 Server Cartridge': 'armhf/keystone',
'Default': 'arm64/generic',
}
class MSCM_CLI_API(object):
"""An API for interacting with the Moonshot iLO CM CLI."""
def __init__(self, host, username, password):
"""MSCM_CLI_API Constructor."""
self.host = host
self.username = username
self.password = password
self._ssh = SSHClient()
self._ssh.set_missing_host_key_policy(AutoAddPolicy())
def _run_cli_command(self, command):
"""Run a single command and return unparsed text from stdout."""
self._ssh.connect(
self.host, username=self.username, password=self.password)
try:
_, stdout, _ = self._ssh.exec_command(command)
output = stdout.read()
finally:
self._ssh.close()
return output
def discover_nodes(self):
"""Discover all available nodes.
Example of stdout from running "show node list":
'show node list\r\r\nSlot ID Proc Manufacturer
Architecture Memory Power Health\r\n----
----- ---------------------- --------------------
------ ----- ------\r\n 01 c1n1 Intel Corporation
x86 Architecture 32 GB On OK \r\n 02 c2n1
N/A No Asset Information \r\n\r\n'
The regex 'c\d+n\d' is finding the node_id's c1-45n1-8
"""
node_list = self._run_cli_command("show node list")
return re.findall(r'c\d+n\d', node_list)
def get_node_macaddr(self, node_id):
"""Get node MAC address(es).
Example of stdout from running "show node macaddr <node_id>":
'show node macaddr c1n1\r\r\nSlot ID NIC 1 (Switch A)
NIC 2 (Switch B) NIC 3 (Switch A) NIC 4 (Switch B)\r\n
---- ----- ----------------- ----------------- -----------------
-----------------\r\n 1 c1n1 a0:1d:48:b5:04:34 a0:1d:48:b5:04:35
a0:1d:48:b5:04:36 a0:1d:48:b5:04:37\r\n\r\n\r\n'
The regex '[\:]'.join(['[0-9A-F]{1,2}'] * 6) is finding
the MAC Addresses for the given node_id.
"""
macs = self._run_cli_command("show node macaddr %s" % node_id)
return re.findall(r':'.join(['[0-9a-f]{2}'] * 6), macs)
def get_node_arch(self, node_id):
"""Get node architecture.
Example of stdout from running "show node info <node_id>":
'show node info c1n1\r\r\n\r\nCartridge #1 \r\n Type: Compute\r\n
Manufacturer: HP\r\n Product Name: ProLiant m500 Server Cartridge\r\n'
Parsing this retrieves 'ProLiant m500 Server Cartridge'
"""
node_detail = self._run_cli_command("show node info %s" % node_id)
cartridge = node_detail.split('Product Name: ')[1].splitlines()[0]
if cartridge in cartridge_mapping:
return cartridge_mapping[cartridge]
else:
return cartridge_mapping['Default']
def get_node_power_status(self, node_id):
"""Get power state of node (on/off).
Example of stdout from running "show node power <node_id>":
'show node power c1n1\r\r\n\r\nCartridge #1\r\n Node #1\r\n
Power State: On\r\n'
Parsing this retrieves 'On'
"""
power_state = self._run_cli_command("show node power %s" % node_id)
return power_state.split('Power State: ')[1].splitlines()[0]
def power_node_on(self, node_id):
"""Power node on."""
return self._run_cli_command("set node power on %s" % node_id)
def power_node_off(self, node_id):
"""Power node off."""
return self._run_cli_command("set node power off force %s" % node_id)
def configure_node_boot_m2(self, node_id):
"""Configure HDD boot for node."""
return self._run_cli_command("set node boot M.2 %s" % node_id)
def configure_node_bootonce_pxe(self, node_id):
"""Configure PXE boot for node once."""
return self._run_cli_command("set node bootonce pxe %s" % node_id)
def power_control_mscm(host, username, password, node_id, power_change):
"""Handle calls from the power template for nodes with a power type
of 'mscm'.
"""
mscm = MSCM_CLI_API(host, username, password)
power_status = mscm.get_node_power_status(node_id)
if power_change == 'off':
mscm.power_node_off(node_id)
return
if power_change != 'on':
raise AssertionError('Unexpected maas power mode.')
if power_status == 'On':
mscm.power_node_off(node_id)
mscm.configure_node_bootonce_pxe(node_id)
mscm.power_node_on(node_id)
def probe_and_enlist_mscm(host, username, password):
""" Extracts all of nodes from mscm, sets all of them to boot via HDD by,
default, sets them to bootonce via PXE, and then enlists them into MAAS.
"""
mscm = MSCM_CLI_API(host, username, password)
nodes = mscm.discover_nodes()
for node_id in nodes:
# Set default boot to HDD
mscm.configure_node_boot_m2(node_id)
params = {
'power_address': host,
'power_user': username,
'power_pass': password,
'node_id': node_id,
}
arch = mscm.get_node_arch(node_id)
macs = mscm.get_node_macaddr(node_id)
utils.create_node(macs, arch, 'mscm', params)
|