Gets a dictionary of device aliases to logicalnames for the site_design.
Change-Id: I9c5ec6d4dd3ac0114fc6d866a7dd8033b7807b15
This commit is contained in:
parent
e7f630651f
commit
8939447669
@ -1001,9 +1001,12 @@ class ApplyNodeNetworking(BaseMaasAction):
|
||||
ctx=n.name,
|
||||
ctx_type='node')
|
||||
hw_iface_list = i.get_hw_slaves()
|
||||
hw_iface_logicalname_list = []
|
||||
for hw_iface in hw_iface_list:
|
||||
hw_iface_logicalname_list.append(n.get_logicalname(hw_iface))
|
||||
iface = machine.interfaces.create_bond(
|
||||
device_name=i.device_name,
|
||||
parent_names=hw_iface_list,
|
||||
parent_names=hw_iface_logicalname_list,
|
||||
mtu=nl.mtu,
|
||||
fabric=fabric.resource_id,
|
||||
mode=nl.bonding_mode,
|
||||
@ -1012,7 +1015,6 @@ class ApplyNodeNetworking(BaseMaasAction):
|
||||
updelay=nl.bonding_up_delay,
|
||||
lacp_rate=nl.bonding_peer_rate,
|
||||
hash_policy=nl.bonding_xmit_hash)
|
||||
self.task.success(focus=n.name)
|
||||
else:
|
||||
msg = "Network link %s indicates bonding, " \
|
||||
"interface %s has less than 2 slaves." % \
|
||||
@ -1059,8 +1061,7 @@ class ApplyNodeNetworking(BaseMaasAction):
|
||||
hw_iface = i.get_hw_slaves()[0]
|
||||
# TODO(sh8121att): HardwareProfile device alias integration
|
||||
iface = machine.get_network_interface(
|
||||
hw_iface)
|
||||
self.task.success(focus=n.name)
|
||||
n.get_logicalname(hw_iface))
|
||||
|
||||
if iface is None:
|
||||
msg = "Interface %s not found on node %s, skipping configuration" % (
|
||||
@ -1448,7 +1449,7 @@ class ApplyNodeStorage(BaseMaasAction):
|
||||
storage_layout = dict()
|
||||
if isinstance(root_block, hostprofile.HostPartition):
|
||||
storage_layout['layout_type'] = 'flat'
|
||||
storage_layout['root_device'] = root_dev.name
|
||||
storage_layout['root_device'] = n.get_logicalname(root_dev.name)
|
||||
storage_layout['root_size'] = root_block.size
|
||||
elif isinstance(root_block, hostprofile.HostVolume):
|
||||
storage_layout['layout_type'] = 'lvm'
|
||||
@ -1460,8 +1461,7 @@ class ApplyNodeStorage(BaseMaasAction):
|
||||
msg=msg, error=True, ctx=n.name, ctx_type='node')
|
||||
self.task.failure(focus=n.get_id())
|
||||
continue
|
||||
storage_layout['root_device'] = root_dev.physical_devices[
|
||||
0]
|
||||
storage_layout['root_device'] = n.get_logicalname(root_dev.physical_devices[0])
|
||||
storage_layout['root_lv_size'] = root_block.size
|
||||
storage_layout['root_lv_name'] = root_block.name
|
||||
storage_layout['root_vg_name'] = root_dev.name
|
||||
@ -1479,24 +1479,24 @@ class ApplyNodeStorage(BaseMaasAction):
|
||||
|
||||
for d in n.storage_devices:
|
||||
maas_dev = machine.block_devices.singleton({
|
||||
'name': d.name
|
||||
'name': n.get_logicalname(d.name)
|
||||
})
|
||||
if maas_dev is None:
|
||||
self.logger.warning("Dev %s not found on node %s" %
|
||||
(d.name, n.name))
|
||||
self.logger.warning("Dev %s (%s) not found on node %s" %
|
||||
(d.name, n.get_logicalname(d.name), n.name))
|
||||
continue
|
||||
|
||||
if d.volume_group is not None:
|
||||
self.logger.debug("Adding dev %s to volume group %s" %
|
||||
(d.name, d.volume_group))
|
||||
self.logger.debug("Adding dev %s (%s) to volume group %s" %
|
||||
(d.name, n.get_logicalname(d.name), d.volume_group))
|
||||
if d.volume_group not in vg_devs:
|
||||
vg_devs[d.volume_group] = {'b': [], 'p': []}
|
||||
vg_devs[d.volume_group]['b'].append(
|
||||
maas_dev.resource_id)
|
||||
continue
|
||||
|
||||
self.logger.debug("Partitioning dev %s on node %s" %
|
||||
(d.name, n.name))
|
||||
self.logger.debug("Partitioning dev %s (%s) on node %s" %
|
||||
(d.name, n.get_logicalname(d.name), n.name))
|
||||
for p in d.partitions:
|
||||
if p.is_sys():
|
||||
self.logger.debug(
|
||||
@ -1510,8 +1510,9 @@ class ApplyNodeStorage(BaseMaasAction):
|
||||
self.maas_client, size=size, bootable=p.bootable)
|
||||
if p.part_uuid is not None:
|
||||
part.uuid = p.part_uuid
|
||||
msg = "Creating partition %s on dev %s" % (p.name,
|
||||
d.name)
|
||||
msg = "Creating partition %s on dev %s (%s)" % (p.name,
|
||||
d.name,
|
||||
n.get_logicalname(d.name))
|
||||
self.logger.debug(msg)
|
||||
part = maas_dev.create_partition(part)
|
||||
self.task.add_status_msg(
|
||||
|
@ -16,8 +16,12 @@
|
||||
#
|
||||
"""Drydock model of a baremetal node."""
|
||||
|
||||
from defusedxml.ElementTree import fromstring
|
||||
import logging
|
||||
from oslo_versionedobjects import fields as ovo_fields
|
||||
|
||||
import drydock_provisioner.config as config
|
||||
import drydock_provisioner.error as errors
|
||||
import drydock_provisioner.objects as objects
|
||||
import drydock_provisioner.objects.hostprofile
|
||||
import drydock_provisioner.objects.base as base
|
||||
@ -39,20 +43,24 @@ class BaremetalNode(drydock_provisioner.objects.hostprofile.HostProfile):
|
||||
# the same set of CIs
|
||||
def __init__(self, **kwargs):
|
||||
super(BaremetalNode, self).__init__(**kwargs)
|
||||
self.logicalnames = {}
|
||||
self.logger = logging.getLogger(
|
||||
config.config_mgr.conf.logging.global_logger_name)
|
||||
|
||||
# Compile the applied version of this model sourcing referenced
|
||||
# data from the passed site design
|
||||
def compile_applied_model(self, site_design):
|
||||
def compile_applied_model(self, site_design, state_manager):
|
||||
self.apply_host_profile(site_design)
|
||||
self.apply_hardware_profile(site_design)
|
||||
self.source = hd_fields.ModelSource.Compiled
|
||||
self.apply_logicalnames(site_design, state_manager)
|
||||
return
|
||||
|
||||
def apply_host_profile(self, site_design):
|
||||
self.apply_inheritance(site_design)
|
||||
return
|
||||
|
||||
# Translate device alises to physical selectors and copy
|
||||
# Translate device aliases to physical selectors and copy
|
||||
# other hardware attributes into this object
|
||||
def apply_hardware_profile(self, site_design):
|
||||
if self.hardware_profile is None:
|
||||
@ -112,6 +120,64 @@ class BaremetalNode(drydock_provisioner.objects.hostprofile.HostProfile):
|
||||
return (sd, p)
|
||||
return (None, None)
|
||||
|
||||
def _apply_logicalname(self, xml_root, alias_name, bus_type, address):
|
||||
"""Given xml_data, checks for a matching businfo and returns the logicalname
|
||||
|
||||
:param xml_root: Parsed ElementTree, it is searched for the logicalname.
|
||||
:param alias_name: String value of the current device alias, it is returned
|
||||
if a logicalname is not found.
|
||||
:param bus_type: String value that is used to find the logicalname.
|
||||
:param address: String value that is used to find the logicalname.
|
||||
:return: String value of the logicalname or the alias_name if logicalname is not found.
|
||||
"""
|
||||
nodes = xml_root.findall(".//node[businfo='" + bus_type + "@" + address + "'].logicalname")
|
||||
if len(nodes) >= 1 and nodes[0].text:
|
||||
# TODO (as1452): log.info() when more than one result after the logger refactor.
|
||||
for logicalname in reversed(nodes[0].text.split("/")):
|
||||
self.logger.debug("Logicalname build dict: alias_name = %s, bus_type = %s, address = %s, "
|
||||
"to logicalname = %s" % (alias_name, bus_type, address, logicalname))
|
||||
return logicalname
|
||||
self.logger.debug("Logicalname build dict: alias_name = %s, bus_type = %s, address = %s, not found" %
|
||||
(alias_name, bus_type, address))
|
||||
return alias_name
|
||||
|
||||
def apply_logicalnames(self, site_design, state_manager):
|
||||
"""Gets the logicalnames for devices from lshw.
|
||||
|
||||
:param site_design: SiteDesign object.
|
||||
:param state_manager: DrydockState object.
|
||||
:return: Returns sets a dictionary of aliases that map to logicalnames in self.logicalnames.
|
||||
"""
|
||||
logicalnames = {}
|
||||
|
||||
results = state_manager.get_build_data(node_name=self.get_name(), latest=True)
|
||||
xml_data = None
|
||||
for result in results:
|
||||
if result.generator == "lshw":
|
||||
xml_data = result.data_element
|
||||
break
|
||||
|
||||
if xml_data:
|
||||
xml_root = fromstring(xml_data)
|
||||
for hardware_profile in site_design.hardware_profiles:
|
||||
for device in hardware_profile.devices:
|
||||
logicalname = self._apply_logicalname(xml_root, device.alias, device.bus_type,
|
||||
device.address)
|
||||
logicalnames[device.alias] = logicalname
|
||||
else:
|
||||
raise errors.BuildDataError("No Build Data found for node_name %s" % (self.get_name()))
|
||||
|
||||
self.logicalnames = logicalnames
|
||||
|
||||
def get_logicalname(self, alias):
|
||||
"""Gets the logicalname from self.logicalnames for an alias or returns the alias if not in the dictionary.
|
||||
"""
|
||||
if (self.logicalnames and self.logicalnames.get(alias)):
|
||||
self.logger.debug("Logicalname input = %s with output %s." % (alias, self.logicalnames[alias]))
|
||||
return self.logicalnames[alias]
|
||||
else:
|
||||
self.logger.debug("Logicalname input = %s not in logicalnames dictionary." % alias)
|
||||
return alias
|
||||
|
||||
@base.DrydockObjectRegistry.register
|
||||
class BaremetalNodeList(base.DrydockObjectListBase, base.DrydockObject):
|
||||
|
@ -244,17 +244,19 @@ class Orchestrator(object):
|
||||
def compute_model_inheritance(self, site_design):
|
||||
"""Compute inheritance of the design model.
|
||||
|
||||
Given a fully populated Site model, compute the effecitve
|
||||
Given a fully populated Site model, compute the effective
|
||||
design by applying inheritance and references
|
||||
"""
|
||||
try:
|
||||
nodes = site_design.baremetal_nodes
|
||||
for n in nodes or []:
|
||||
n.compile_applied_model(site_design)
|
||||
n.compile_applied_model(site_design, state_manager=self.state_manager)
|
||||
except AttributeError:
|
||||
self.logger.debug(
|
||||
"Model inheritance skipped, no node definitions in site design."
|
||||
)
|
||||
except errors.BuildDataError:
|
||||
self.logger.info("No Build Data found.")
|
||||
|
||||
return
|
||||
|
||||
|
@ -21,3 +21,4 @@ psycopg2==2.7.3.1
|
||||
jsonschema==2.6.0
|
||||
jinja2==2.9.6
|
||||
ulid2==0.1.1
|
||||
defusedxml===0.5.0
|
||||
|
@ -1,18 +1,19 @@
|
||||
alembic==0.8.2
|
||||
amqp==2.2.2
|
||||
Babel==2.5.1
|
||||
Babel==2.5.3
|
||||
bson==0.4.7
|
||||
cachetools==2.0.1
|
||||
certifi==2017.11.5
|
||||
chardet==3.0.4
|
||||
click==6.7
|
||||
contextlib2==0.5.5
|
||||
debtcollector==1.18.0
|
||||
debtcollector==1.19.0
|
||||
defusedxml==0.5.0
|
||||
enum-compat==0.0.2
|
||||
eventlet==0.20.0
|
||||
falcon==1.3.0
|
||||
falcon==1.4.1
|
||||
fasteners==0.14.1
|
||||
futurist==1.4.0
|
||||
futurist==1.6.0
|
||||
greenlet==0.4.12
|
||||
idna==2.6
|
||||
iso8601==0.1.11
|
||||
@ -24,26 +25,26 @@ kombu==4.1.0
|
||||
Mako==1.0.7
|
||||
MarkupSafe==1.0
|
||||
monotonic==1.4
|
||||
msgpack-python==0.4.8
|
||||
msgpack-python==0.5.1
|
||||
netaddr==0.7.19
|
||||
netifaces==0.10.6
|
||||
oauthlib==2.0.6
|
||||
oslo.concurrency==3.23.0
|
||||
oslo.concurrency==3.25.0
|
||||
oslo.config==3.16.0
|
||||
oslo.context==2.19.3
|
||||
oslo.i18n==3.18.0
|
||||
oslo.log==3.33.0
|
||||
oslo.messaging==5.33.1
|
||||
oslo.middleware==3.32.1
|
||||
oslo.context==2.20.0
|
||||
oslo.i18n==3.19.0
|
||||
oslo.log==3.36.0
|
||||
oslo.messaging==5.35.0
|
||||
oslo.middleware==3.34.0
|
||||
oslo.policy==1.22.1
|
||||
oslo.serialization==2.21.2
|
||||
oslo.service==1.27.0
|
||||
oslo.utils==3.31.0
|
||||
oslo.serialization==2.23.0
|
||||
oslo.service==1.29.0
|
||||
oslo.utils==3.35.0
|
||||
oslo.versionedobjects==1.23.0
|
||||
Paste==2.0.3
|
||||
PasteDeploy==1.5.2
|
||||
pbr==3.1.1
|
||||
pika==0.11.0
|
||||
pika==0.11.2
|
||||
pika-pool==0.1.3
|
||||
pip==9.0.1
|
||||
positional==1.2.1
|
||||
@ -53,11 +54,10 @@ PTable==0.9.2
|
||||
pycadf==2.6.0
|
||||
pycrypto==2.6.1
|
||||
pyghmi==1.0.18
|
||||
pyinotify==0.9.6
|
||||
pyparsing==2.2.0
|
||||
python-dateutil==2.6.1
|
||||
python-editor==1.0.3
|
||||
python-keystoneclient==3.13.0
|
||||
python-keystoneclient==3.14.0
|
||||
python-mimeparse==1.6.0
|
||||
pytz==2017.3
|
||||
PyYAML==3.12
|
||||
@ -65,16 +65,16 @@ repoze.lru==0.7
|
||||
requests==2.18.4
|
||||
rfc3986==1.1.0
|
||||
Routes==2.4.1
|
||||
setuptools==36.7.2
|
||||
setuptools==38.4.0
|
||||
six==1.11.0
|
||||
SQLAlchemy==1.1.14
|
||||
statsd==3.2.1
|
||||
stevedore==1.27.1
|
||||
tenacity==4.7.0
|
||||
statsd==3.2.2
|
||||
stevedore==1.28.0
|
||||
tenacity==4.8.0
|
||||
ulid2==0.1.1
|
||||
urllib3==1.22
|
||||
uWSGI==2.0.15
|
||||
vine==1.1.4
|
||||
WebOb==1.7.3
|
||||
WebOb==1.7.4
|
||||
wheel==0.30.0
|
||||
wrapt==1.10.11
|
||||
|
@ -15,6 +15,7 @@
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from unittest.mock import Mock
|
||||
|
||||
import drydock_provisioner.config as config
|
||||
import drydock_provisioner.objects as objects
|
||||
@ -128,3 +129,20 @@ def setup_logging():
|
||||
ch = logging.StreamHandler()
|
||||
ch.setFormatter(formatter)
|
||||
logger.addHandler(ch)
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def mock_get_build_data(drydock_state):
|
||||
def side_effect(**kwargs):
|
||||
build_data = objects.BuildData(
|
||||
node_name="test",
|
||||
task_id="tid",
|
||||
generator="lshw",
|
||||
data_format="text/plain",
|
||||
data_element="<mocktest></mocktest>")
|
||||
return [build_data]
|
||||
drydock_state.real_get_build_data = drydock_state.get_build_data
|
||||
drydock_state.get_build_data = Mock(side_effect=side_effect)
|
||||
|
||||
yield
|
||||
drydock_state.get_build_data = Mock(wraps=None, side_effect=None)
|
||||
drydock_state.get_build_data = drydock_state.real_get_build_data
|
||||
|
@ -20,7 +20,7 @@ from drydock_provisioner.orchestrator.actions.orchestrator import PrepareNodes
|
||||
|
||||
class TestActionPrepareNodes(object):
|
||||
def test_preparenodes(self, mocker, input_files, deckhand_ingester, setup,
|
||||
drydock_state):
|
||||
drydock_state, mock_get_build_data):
|
||||
mock_images = mocker.patch("drydock_provisioner.drivers.node.driver.NodeDriver"
|
||||
".get_available_images")
|
||||
mock_images.return_value = ['xenial']
|
||||
|
@ -66,7 +66,8 @@ class TestClass(object):
|
||||
assert result.status == falcon.HTTP_403
|
||||
|
||||
@pytest.fixture()
|
||||
def seed_bootaction(self, blank_state, yaml_orchestrator, input_files):
|
||||
def seed_bootaction(self, blank_state, yaml_orchestrator, input_files,
|
||||
mock_get_build_data):
|
||||
"""Add a task and boot action to the database for testing."""
|
||||
input_file = input_files.join("fullsite.yaml")
|
||||
design_ref = "file://%s" % input_file
|
||||
@ -83,7 +84,8 @@ class TestClass(object):
|
||||
return ba_ctx
|
||||
|
||||
@pytest.fixture()
|
||||
def falcontest(self, drydock_state, yaml_ingester, yaml_orchestrator):
|
||||
def falcontest(self, drydock_state, yaml_ingester, yaml_orchestrator,
|
||||
mock_get_build_data):
|
||||
"""Create a test harness for the the Falcon API framework."""
|
||||
return testing.TestClient(
|
||||
start_api(
|
||||
|
@ -18,7 +18,7 @@ from drydock_provisioner.objects import fields as hd_fields
|
||||
|
||||
class TestBootActionSignal(object):
|
||||
def test_bootaction_signal_disable(self, deckhand_orchestrator,
|
||||
drydock_state, input_files):
|
||||
drydock_state, input_files, mock_get_build_data):
|
||||
"""Test that disabled signaling omits a status entry in the DB."""
|
||||
input_file = input_files.join("deckhand_fullsite.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
@ -21,7 +21,7 @@ import drydock_provisioner.objects.fields as hd_fields
|
||||
|
||||
class TestClass(object):
|
||||
def test_task_complete(self, yaml_ingester, input_files, setup,
|
||||
blank_state):
|
||||
blank_state, mock_get_build_data):
|
||||
input_file = input_files.join("fullsite.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
||||
|
@ -24,7 +24,8 @@ import falcon
|
||||
|
||||
|
||||
class TestValidationApi(object):
|
||||
def test_post_validation_resp(self, input_files, falcontest):
|
||||
def test_post_validation_resp(self, input_files, falcontest, drydock_state,
|
||||
mock_get_build_data):
|
||||
|
||||
input_file = input_files.join("deckhand_fullsite.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
@ -81,7 +82,7 @@ class TestValidationApi(object):
|
||||
|
||||
assert result.status == falcon.HTTP_400
|
||||
|
||||
def test_invalid_post_resp(self, input_files, falcontest):
|
||||
def test_invalid_post_resp(self, input_files, falcontest, drydock_state, mock_get_build_data):
|
||||
input_file = input_files.join("invalid_validation.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
||||
@ -105,7 +106,7 @@ class TestValidationApi(object):
|
||||
|
||||
@pytest.fixture()
|
||||
def falcontest(self, drydock_state, deckhand_ingester,
|
||||
deckhand_orchestrator):
|
||||
deckhand_orchestrator, mock_get_build_data):
|
||||
"""Create a test harness for the the Falcon API framework."""
|
||||
policy.policy_engine = policy.DrydockPolicy()
|
||||
policy.policy_engine.register_policy()
|
||||
|
@ -17,7 +17,8 @@ import drydock_provisioner.objects as objects
|
||||
|
||||
class TestClass(object):
|
||||
def test_bootaction_scoping_blankfilter(self, input_files,
|
||||
deckhand_orchestrator):
|
||||
deckhand_orchestrator, drydock_state,
|
||||
mock_get_build_data):
|
||||
"""Test a boot action with no node filter scopes correctly."""
|
||||
input_file = input_files.join("deckhand_fullsite.yaml")
|
||||
|
||||
@ -36,7 +37,8 @@ class TestClass(object):
|
||||
assert 'controller01' in ba.target_nodes
|
||||
|
||||
def test_bootaction_scoping_unionfilter(self, input_files,
|
||||
deckhand_orchestrator):
|
||||
deckhand_orchestrator, drydock_state,
|
||||
mock_get_build_data):
|
||||
"""Test a boot action with a union node filter scopes correctly."""
|
||||
input_file = input_files.join("deckhand_fullsite.yaml")
|
||||
|
||||
|
158
tests/unit/test_node_logicalnames.py
Normal file
158
tests/unit/test_node_logicalnames.py
Normal file
@ -0,0 +1,158 @@
|
||||
# Copyright 2017 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.
|
||||
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
|
||||
import drydock_provisioner.objects as objects
|
||||
import drydock_provisioner.error as errors
|
||||
|
||||
|
||||
class TestClass(object):
|
||||
def test_apply_logicalnames_exception(self, input_files, deckhand_orchestrator,
|
||||
drydock_state, mock_get_build_data):
|
||||
"""Test node apply_logicalnames to get an exception"""
|
||||
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)
|
||||
|
||||
def side_effect(**kwargs):
|
||||
return []
|
||||
drydock_state.get_build_data = Mock(side_effect=side_effect)
|
||||
|
||||
nodes = design_data.baremetal_nodes
|
||||
with pytest.raises(errors.BuildDataError):
|
||||
for n in nodes or []:
|
||||
n.apply_logicalnames(design_data, state_manager=drydock_state)
|
||||
|
||||
def test_apply_logicalnames_success(self, input_files, deckhand_orchestrator,
|
||||
drydock_state, mock_get_build_data):
|
||||
"""Test node apply_logicalnames to get the proper dictionary"""
|
||||
input_file = input_files.join("deckhand_fullsite.yaml")
|
||||
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
||||
xml_example = """
|
||||
<?xml version="1.0" standalone="yes" ?>
|
||||
<!-- generated by lshw-B.02.17 -->
|
||||
<!-- GCC 5.4.0 20160609 -->
|
||||
<!-- Linux 4.4.0-104-generic #127-Ubuntu SMP Mon Dec 11 12:16:42 UTC 2017 x86_64 -->
|
||||
<!-- GNU libc 2 (glibc 2.23) -->
|
||||
<list>
|
||||
<node id="cab23-r720-16" claimed="true" class="system" handle="DMI:0100">
|
||||
<description>Rack Mount Chassis</description>
|
||||
<product>PowerEdge R720xd (SKU=NotProvided;ModelName=PowerEdge R720xd)</product>
|
||||
<vendor>Dell Inc.</vendor>
|
||||
<serial>6H5LBY1</serial>
|
||||
<width units="bits">64</width>
|
||||
<configuration>
|
||||
<setting id="boot" value="normal" />
|
||||
<setting id="chassis" value="rackmount" />
|
||||
<setting id="sku" value="SKU=NotProvided;ModelName=PowerEdge R720xd" />
|
||||
<setting id="uuid" value="44454C4C-4800-1035-804C-B6C04F425931" />
|
||||
</configuration>
|
||||
<capabilities>
|
||||
<capability id="smbios-2.7">SMBIOS version 2.7</capability>
|
||||
<capability id="dmi-2.7">DMI version 2.7</capability>
|
||||
<capability id="vsyscall32">32-bit processes</capability>
|
||||
</capabilities>
|
||||
<node id="core" claimed="true" class="bus" handle="DMI:0200">
|
||||
<node id="pci:1" claimed="true" class="bridge" handle="PCIBUS:0000:03">
|
||||
<description>PCI bridge</description>
|
||||
<product>Xeon E5/Core i7 IIO PCI Express Root Port 2a</product>
|
||||
<vendor>Intel Corporation</vendor>
|
||||
<physid>2</physid>
|
||||
<businfo>pci@0000:00:02.0</businfo>
|
||||
<version>07</version>
|
||||
<width units="bits">32</width>
|
||||
<clock units="Hz">33000000</clock>
|
||||
<configuration>
|
||||
<setting id="driver" value="pcieport" />
|
||||
</configuration>
|
||||
<capabilities>
|
||||
<capability id="pci" />
|
||||
<capability id="msi">Message Signalled Interrupts</capability>
|
||||
<capability id="pciexpress">PCI Express</capability>
|
||||
<capability id="pm">Power Management</capability>
|
||||
<capability id="normal_decode" />
|
||||
<capability id="bus_master">bus mastering</capability>
|
||||
<capability id="cap_list">PCI capabilities listing</capability>
|
||||
</capabilities>
|
||||
<resources>
|
||||
<resource type="irq" value="26" />
|
||||
</resources>
|
||||
<node id="network:0" claimed="true" class="network" handle="PCI:0000:00:03.0">
|
||||
<description>Ethernet interface</description>
|
||||
<product>I350 Gigabit Network Connection</product>
|
||||
<vendor>Intel Corporation</vendor>
|
||||
<physid>0</physid>
|
||||
<businfo>pci@0000:00:03.0</businfo>
|
||||
<logicalname>eno1</logicalname>
|
||||
<version>01</version>
|
||||
<serial>b8:ca:3a:65:7d:d8</serial>
|
||||
<size units="bit/s">1000000000</size>
|
||||
<capacity>1000000000</capacity>
|
||||
<width units="bits">32</width>
|
||||
<clock units="Hz">33000000</clock>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node id="disk:0" claimed="true" class="disk" handle="SCSI:00:02:00:00">
|
||||
<description>SCSI Disk</description>
|
||||
<product>PERC H710P</product>
|
||||
<vendor>DELL</vendor>
|
||||
<physid>2.0.0</physid>
|
||||
<businfo>scsi@2:0.0.0</businfo>
|
||||
<logicalname>/dev/sda</logicalname>
|
||||
<dev>8:0</dev>
|
||||
<version>3.13</version>
|
||||
<serial>0044016c12771be71900034cfba0a38c</serial>
|
||||
<size units="bytes">299439751168</size>
|
||||
</node>
|
||||
</node>
|
||||
</list>
|
||||
"""
|
||||
xml_example = xml_example.replace('\n', '')
|
||||
|
||||
def side_effect(**kwargs):
|
||||
build_data = objects.BuildData(
|
||||
node_name="controller01",
|
||||
task_id="tid",
|
||||
generator="lshw",
|
||||
data_format="text/plain",
|
||||
data_element=xml_example)
|
||||
return [build_data]
|
||||
drydock_state.get_build_data = Mock(side_effect=side_effect)
|
||||
|
||||
design_status, design_data = deckhand_orchestrator.get_effective_site(
|
||||
design_ref)
|
||||
|
||||
nodes = design_data.baremetal_nodes
|
||||
nodes[0].apply_logicalnames(design_data, state_manager=drydock_state)
|
||||
|
||||
expected = {'primary_boot': 'sda', 'prim_nic02': 'prim_nic02', 'prim_nic01': 'eno1'}
|
||||
# Tests the whole dictionary
|
||||
assert nodes[0].logicalnames == expected
|
||||
# Makes sure the path and / are both removed from primary_boot
|
||||
assert nodes[0].logicalnames['primary_boot'] == 'sda'
|
||||
assert nodes[0].get_logicalname('primary_boot') == 'sda'
|
||||
# A simple logicalname
|
||||
assert nodes[0].logicalnames['prim_nic01'] == 'eno1'
|
||||
assert nodes[0].get_logicalname('prim_nic01') == 'eno1'
|
||||
# Logicalname is not found, returns the alias
|
||||
assert nodes[0].logicalnames['prim_nic02'] == 'prim_nic02'
|
||||
assert nodes[0].get_logicalname('prim_nic02') == 'prim_nic02'
|
@ -19,7 +19,7 @@ from drydock_provisioner.orchestrator.validations.validator import Validator
|
||||
|
||||
class TestDesignValidator(object):
|
||||
def test_validate_design(self, deckhand_ingester, drydock_state,
|
||||
input_files):
|
||||
input_files, mock_get_build_data):
|
||||
"""Test the basic validation engine."""
|
||||
|
||||
input_file = input_files.join("deckhand_fullsite.yaml")
|
||||
|
@ -21,7 +21,7 @@ from drydock_provisioner.orchestrator.validations.validator import Validator
|
||||
|
||||
class TestRationalBootStorage(object):
|
||||
def test_boot_storage_rational(self, deckhand_ingester, drydock_state,
|
||||
input_files):
|
||||
input_files, mock_get_build_data):
|
||||
|
||||
input_file = input_files.join("validation.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
@ -39,7 +39,7 @@ class TestRationalBootStorage(object):
|
||||
assert len(message_list) == 1
|
||||
|
||||
def test_invalid_boot_storage_small(self, deckhand_ingester, drydock_state,
|
||||
input_files):
|
||||
input_files, mock_get_build_data):
|
||||
|
||||
input_file = input_files.join("invalid_boot_storage_small.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
@ -56,7 +56,7 @@ class TestRationalNetworkTrunking(object):
|
||||
assert msg.get('error') is False
|
||||
|
||||
def test_invalid_storage_partitioning(self, deckhand_ingester,
|
||||
drydock_state, input_files):
|
||||
drydock_state, input_files, mock_get_build_data):
|
||||
input_file = input_files.join("invalid_validation.yaml")
|
||||
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
@ -39,7 +39,7 @@ class TestStorageSizing(object):
|
||||
assert msg.get('error') is False
|
||||
|
||||
def test_invalid_storage_sizing(self, deckhand_ingester, drydock_state,
|
||||
input_files):
|
||||
input_files, mock_get_build_data):
|
||||
|
||||
input_file = input_files.join("invalid_validation.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
@ -21,7 +21,7 @@ from drydock_provisioner.orchestrator.validations.validator import Validator
|
||||
|
||||
class TestValidPlatform(object):
|
||||
def test_valid_platform(self, mocker, deckhand_ingester, drydock_state,
|
||||
input_files):
|
||||
input_files, mock_get_build_data):
|
||||
mock_images = mocker.patch(
|
||||
"drydock_provisioner.drivers.node.maasdriver.driver."
|
||||
"MaasNodeDriver.get_available_images")
|
||||
|
Loading…
x
Reference in New Issue
Block a user