[443514] Set domain for nodes during deployment

- Resolve the FQDN of node based on the DNS domain of the primary
  network
- When identifying the node in MAAS, set the hostname and the domain
  for the node

Change-Id: I1fc5d89e07784ae8168461bcf4ffe400956616f9
This commit is contained in:
Scott Hussey 2018-08-03 07:57:06 -05:00
parent e2b3e8ee8e
commit 89ce941202
4 changed files with 107 additions and 3 deletions

View File

@ -1042,7 +1042,8 @@ class IdentifyNode(BaseMaasAction):
for n in nodes: for n in nodes:
try: try:
machine = machine_list.identify_baremetal_node(n) machine = machine_list.identify_baremetal_node(n,
domain=n.get_domain(site_design))
if machine is not None: if machine is not None:
self.task.success(focus=n.get_id()) self.task.success(focus=n.get_id())
self.task.add_status_msg( self.task.add_status_msg(

View File

@ -47,8 +47,9 @@ class Machine(model_base.ResourceBase):
'owner_data', 'owner_data',
'block_devices', 'block_devices',
'volume_groups', 'volume_groups',
'domain'
] ]
json_fields = ['hostname', 'power_type'] json_fields = ['hostname', 'power_type', 'domain']
def __init__(self, api_client, **kwargs): def __init__(self, api_client, **kwargs):
super(Machine, self).__init__(api_client, **kwargs) super(Machine, self).__init__(api_client, **kwargs)
@ -533,7 +534,7 @@ class Machines(model_base.ResourceCollectionBase):
return node return node
def identify_baremetal_node(self, node_model, update_name=True): def identify_baremetal_node(self, node_model, update_name=True, domain="local"):
"""Find MaaS node resource matching Drydock BaremetalNode. """Find MaaS node resource matching Drydock BaremetalNode.
Search all the defined MaaS Machines and attempt to match Search all the defined MaaS Machines and attempt to match
@ -583,6 +584,7 @@ class Machines(model_base.ResourceCollectionBase):
if maas_node.hostname != node_model.name and update_name: if maas_node.hostname != node_model.name and update_name:
try: try:
maas_node.hostname = node_model.name maas_node.hostname = node_model.name
maas_node.domain = domain
maas_node.update() maas_node.update()
if node_model.oob_type == 'libvirt': if node_model.oob_type == 'libvirt':
self.logger.debug( self.logger.debug(

View File

@ -94,6 +94,41 @@ class BaremetalNode(drydock_provisioner.objects.hostprofile.HostProfile):
return return
def get_domain(self, site_design):
"""Return the domain for this node.
The domain for this is the DNS domain of the primary network or local.
:param SiteDesign site_design: A instance containing definitions for the networks
this node is attached to.
"""
try:
pn = site_design.get_network(self.primary_network)
domain = pn.dns_domain or "local"
except errors.DesignError as dex:
self.logger.debug("Primary network not found, use domain 'local'.")
domain = "local"
except AttributeError as aex:
self.logger.debug("Primary network does not define a domain, use domain 'local'.")
domain = "local"
return domain
def get_fqdn(self, site_design):
"""Returns the FQDN for this node.
The FQDN for this node is composed of the node hostname ``self.name`` appended
with the domain name of the primary network if defined. If the primary network
does not define a domain name, the domain is ``local``.
:param site_design: A SiteDesign instance containing definitions for the networks
the node is attached to.
"""
hostname = self.name
domain = self.get_domain(site_design)
return "{}.{}".format(hostname, domain)
def resolve_kernel_params(self, site_design): def resolve_kernel_params(self, site_design):
"""Check if any kernel parameter values are supported references.""" """Check if any kernel parameter values are supported references."""
if not self.hardware_profile: if not self.hardware_profile:

View File

@ -0,0 +1,66 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Test node model hostname and FQDN."""
import drydock_provisioner.objects as objects
class TestNodeNaming(object):
def test_node_fqdn(self, deckhand_orchestrator, input_files, setup):
"""Test fqdn rendering."""
input_file = input_files.join("deckhand_fullsite.yaml")
design_ref = "file://%s" % str(input_file)
design_status, design_data = deckhand_orchestrator.get_effective_site(
design_ref)
assert design_status.status == objects.fields.ValidationResult.Success
# From the sample YAML, the domain assigned to the 'mgmt' network
# is 'mgmt.sitename.example.com'. This is the primary network for
# 'controller01'
nodename = 'controller01'
expected_fqdn = '{}.{}'.format(nodename, 'mgmt.sitename.example.com')
node_model = design_data.get_baremetal_node(nodename)
assert node_model
assert node_model.get_fqdn(design_data) == expected_fqdn
def test_node_domain(self, deckhand_orchestrator, input_files, setup):
"""Test domain rendering."""
input_file = input_files.join("deckhand_fullsite.yaml")
design_ref = "file://%s" % str(input_file)
design_status, design_data = deckhand_orchestrator.get_effective_site(
design_ref)
assert design_status.status == objects.fields.ValidationResult.Success
# From the sample YAML, the domain assigned to the 'mgmt' network
# is 'mgmt.sitename.example.com'. This is the primary network for
# 'controller01'
node_name = 'controller01'
expected_domain = 'mgmt.sitename.example.com'
node_model = design_data.get_baremetal_node(node_name)
assert node_model
assert node_model.get_domain(design_data) == expected_domain