From 611e98de3fb929985cb977303dc7fcffa52c45b1 Mon Sep 17 00:00:00 2001 From: Phil Sphicas Date: Sun, 25 Jul 2021 02:49:50 +0000 Subject: [PATCH] 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: https://github.com/maas/maas/commit/8842d0bfd3fc77d7087310dae06f3ae9538c4275 Change-Id: I24d3bc3b1cc94907d73bc247de3fc06dd4750ab1 --- doc/source/_static/drydock.conf.sample | 33 ++++++++++++++ etc/drydock/drydock.conf.sample | 22 +++++++-- .../drivers/node/maasdriver/actions/node.py | 10 ++++- .../drivers/node/maasdriver/driver.py | 10 +++++ .../drivers/node/maasdriver/models/machine.py | 45 ++++++++++++++++--- 5 files changed, 109 insertions(+), 11 deletions(-) diff --git a/doc/source/_static/drydock.conf.sample b/doc/source/_static/drydock.conf.sample index b0c17d54..fdf4c39a 100644 --- a/doc/source/_static/drydock.conf.sample +++ b/doc/source/_static/drydock.conf.sample @@ -55,6 +55,9 @@ # Authentication URL (string value) #auth_url = +# Scope for system operations (string value) +#system_scope = + # Domain ID to scope to (string value) #domain_id = @@ -295,6 +298,14 @@ # The URL for accessing MaaS API (string value) #maas_api_url = +# 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] # diff --git a/etc/drydock/drydock.conf.sample b/etc/drydock/drydock.conf.sample index e271d5fa..fdf4c39a 100644 --- a/etc/drydock/drydock.conf.sample +++ b/etc/drydock/drydock.conf.sample @@ -55,6 +55,9 @@ # Authentication URL (string value) #auth_url = +# Scope for system operations (string value) +#system_scope = + # Domain ID to scope to (string value) #domain_id = @@ -295,6 +298,14 @@ # The URL for accessing MaaS API (string value) #maas_api_url = +# 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) diff --git a/python/drydock_provisioner/drivers/node/maasdriver/actions/node.py b/python/drydock_provisioner/drivers/node/maasdriver/actions/node.py index 6814b692..0ff5a641 100644 --- a/python/drydock_provisioner/drivers/node/maasdriver/actions/node.py +++ b/python/drydock_provisioner/drivers/node/maasdriver/actions/node.py @@ -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 diff --git a/python/drydock_provisioner/drivers/node/maasdriver/driver.py b/python/drydock_provisioner/drivers/node/maasdriver/driver.py index be604697..a37085da 100644 --- a/python/drydock_provisioner/drivers/node/maasdriver/driver.py +++ b/python/drydock_provisioner/drivers/node/maasdriver/driver.py @@ -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, diff --git a/python/drydock_provisioner/drivers/node/maasdriver/models/machine.py b/python/drydock_provisioner/drivers/node/maasdriver/models/machine.py index 1bac0269..4a2cf3ba 100644 --- a/python/drydock_provisioner/drivers/node/maasdriver/models/machine.py +++ b/python/drydock_provisioner/drivers/node/maasdriver/models/machine.py @@ -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: "" + 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: