Use OOB driver creds for MAAS

During MAAS enlistment (and commissioning), an IPMI account (named
"maas" by default) is created on each node, which MAAS then uses for
power management.

This change allows MAAS to use the same credentials as the ones used by
the OOB driver, by overwriting the power parameters for the discovered
nodes. This includes the power type, so if the node is configured to use
Redfish, then Drydock will update a MAAS node discovered as IPMI to use
Redfish instead.

It also provides an option to instruct MAAS not to recreate IPMI
credentials during commissioning, which is passed through to the MAAS
API. Setting this to true is only supported in MAAS 2.7 or later [0].

The two maasdriver configuration options are introduced in drydock.conf,
along with their default values:

    [maasdriver]
    use_node_oob_params = false
    skip_bmc_config = false

These options do not prevent MAAS from creating the IPMI account during
enlistment - this would require addition MAAS customization.

0: 8842d0bfd3

Change-Id: I24d3bc3b1cc94907d73bc247de3fc06dd4750ab1
This commit is contained in:
Phil Sphicas 2021-07-25 02:49:50 +00:00
parent 3cbeb29f2d
commit 611e98de3f
5 changed files with 109 additions and 11 deletions

View File

@ -55,6 +55,9 @@
# Authentication URL (string value)
#auth_url = <None>
# Scope for system operations (string value)
#system_scope = <None>
# Domain ID to scope to (string value)
#domain_id = <None>
@ -295,6 +298,14 @@
# The URL for accessing MaaS API (string value)
#maas_api_url = <None>
# Update MAAS to use the provided Node OOB params, overwriting discovered values
# (boolean value)
#use_node_oob_params = false
# Skip BMC reconfiguration during commissioning (requires MAAS 2.7+) (boolean
# value)
#skip_bmc_config = false
# Polling interval for querying MaaS status in seconds (integer value)
#poll_interval = 10
@ -370,6 +381,28 @@
#poll_interval = 10
[redfish_driver]
#
# From drydock_provisioner
#
# Maximum number of connection retries to Redfish server (integer value)
# Minimum value: 1
#max_retries = 10
# Maximum reties to wait for power state change (integer value)
# Minimum value: 1
#power_state_change_max_retries = 18
# Polling interval in seconds between retries for power state change (integer
# value)
#power_state_change_retry_interval = 10
# Use SSL to communicate with Redfish API server (boolean value)
#use_ssl = true
[timeouts]
#

View File

@ -55,6 +55,9 @@
# Authentication URL (string value)
#auth_url = <None>
# Scope for system operations (string value)
#system_scope = <None>
# Domain ID to scope to (string value)
#domain_id = <None>
@ -295,6 +298,14 @@
# The URL for accessing MaaS API (string value)
#maas_api_url = <None>
# Update MAAS to use the provided Node OOB params, overwriting discovered values
# (boolean value)
#use_node_oob_params = false
# Skip BMC reconfiguration during commissioning (requires MAAS 2.7+) (boolean
# value)
#skip_bmc_config = false
# Polling interval for querying MaaS status in seconds (integer value)
#poll_interval = 10
@ -376,13 +387,16 @@
# From drydock_provisioner
#
# Maximum number of connection retries to Redfish server
#max_retries = 5
# Maximum number of connection retries to Redfish server (integer value)
# Minimum value: 1
#max_retries = 10
# Maximum reties to wait for power state change
# Maximum reties to wait for power state change (integer value)
# Minimum value: 1
#power_state_change_max_retries = 18
# Polling interval in seconds between retries for power state change
# Polling interval in seconds between retries for power state change (integer
# value)
#power_state_change_retry_interval = 10
# Use SSL to communicate with Redfish API server (boolean value)

View File

@ -1100,7 +1100,11 @@ class IdentifyNode(BaseMaasAction):
ctx=n.name,
ctx_type='node')
elif type(machine) == maas_machine.Machine:
machine.update_identity(n, domain=n.get_domain(site_design))
machine.update_identity(
n,
domain=n.get_domain(site_design),
use_node_oob_params=config.config_mgr.conf.maasdriver.use_node_oob_params,
)
msg = "Node %s identified in MaaS" % n.name
self.logger.debug(msg)
self.task.add_status_msg(
@ -1199,7 +1203,9 @@ class ConfigureHardware(BaseMaasAction):
self.logger.debug(
"Located node %s in MaaS, starting commissioning" %
(n.name))
machine.commission()
machine.commission(
skip_bmc_config=config.config_mgr.conf.maasdriver.skip_bmc_config
)
# Poll machine status
attempts = 0

View File

@ -49,6 +49,16 @@ class MaasNodeDriver(NodeDriver):
'maas_api_key', help='The API key for accessing MaaS',
secret=True),
cfg.StrOpt('maas_api_url', help='The URL for accessing MaaS API'),
cfg.BoolOpt(
'use_node_oob_params',
default=False,
help='Update MAAS to use the provided Node OOB params, overwriting discovered values',
),
cfg.BoolOpt(
'skip_bmc_config',
default=False,
help='Skip BMC reconfiguration during commissioning (requires MAAS 2.7+)',
),
cfg.IntOpt(
'poll_interval',
default=10,

View File

@ -274,17 +274,21 @@ class Machine(model_base.ResourceBase):
self.logger.debug("MaaS response: %s" % resp.text)
raise errors.DriverError(brief_msg)
def commission(self, debug=False):
def commission(self, debug=False, skip_bmc_config=False):
"""Start the MaaS commissioning process.
:param debug: If true, enable ssh on the node and leave it power up after commission
:param skip_bmc_config: If true, skip re-configuration of the BMC for IPMI based machines
"""
url = self.interpolate_url()
# If we want to debug this node commissioning, enable SSH
# after commissioning and leave the node powered up
options = {'enable_ssh': '1' if debug else '0'}
options = {
'enable_ssh': '1' if debug else '0',
'skip_bmc_config': '1' if skip_bmc_config else '0',
}
resp = self.api_client.post(url, op='commission', files=options)
@ -409,8 +413,22 @@ class Machine(model_base.ResourceBase):
for k, v in kwargs.items():
power_params['power_parameters_' + k] = v
self.logger.debug("Updating node %s power parameters: %s" %
(self.hostname, str(power_params)))
self.logger.debug(
"Updating node %s power parameters: %s"
% (
self.hostname,
str(
{
**power_params,
**{
k: "<redacted>"
for k in power_params
if k in ["power_parameters_power_pass"]
},
}
),
)
)
resp = self.api_client.put(url, files=power_params)
if resp.status_code == 200:
@ -443,11 +461,13 @@ class Machine(model_base.ResourceBase):
"Failed updating power parameters MAAS url {} - return code {}\n"
.format(url, resp.status_code.resp.text))
def update_identity(self, n, domain="local"):
def update_identity(self, n, domain="local", use_node_oob_params=False):
"""Update this node's identity based on the Node object ``n``
:param objects.Node n: The Node object to use as reference
:param str domain: The DNS domain to register this node under
:param bool use_node_oob_params: If true, overwrite the discovered OOB params (type and creds)
with those in the Node object. Applies to compatible types (i.e. ipmi and redfish)
"""
try:
self.hostname = n.name
@ -462,6 +482,21 @@ class Machine(model_base.ResourceBase):
'virsh',
power_address=oob_params.get('libvirt_uri'),
power_id=n.name)
elif use_node_oob_params and (n.oob_type == "ipmi" or n.oob_type == "redfish"):
self.logger.debug(
"Updating node {} MaaS power parameters for {}.".format(
n.name, n.oob_type
)
)
oob_params = n.oob_parameters
oob_network = oob_params.get("network")
oob_address = n.get_network_address(oob_network)
self.set_power_parameters(
n.oob_type,
power_address=oob_address,
power_user=oob_params.get("account"),
power_pass=oob_params.get("credential"),
)
self.logger.debug("Updated MaaS resource %s hostname to %s" %
(self.resource_id, n.name))
except Exception as ex: