diff --git a/drydock_provisioner/drivers/node/maasdriver/actions/node.py b/drydock_provisioner/drivers/node/maasdriver/actions/node.py index cab39191..57de8bce 100644 --- a/drydock_provisioner/drivers/node/maasdriver/actions/node.py +++ b/drydock_provisioner/drivers/node/maasdriver/actions/node.py @@ -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( diff --git a/drydock_provisioner/objects/node.py b/drydock_provisioner/objects/node.py index ae4a5b31..e782c05f 100644 --- a/drydock_provisioner/objects/node.py +++ b/drydock_provisioner/objects/node.py @@ -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): diff --git a/drydock_provisioner/orchestrator/orchestrator.py b/drydock_provisioner/orchestrator/orchestrator.py index e4de73a0..b5deb7cd 100644 --- a/drydock_provisioner/orchestrator/orchestrator.py +++ b/drydock_provisioner/orchestrator/orchestrator.py @@ -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 diff --git a/requirements-direct.txt b/requirements-direct.txt index 88172fcf..8465992e 100644 --- a/requirements-direct.txt +++ b/requirements-direct.txt @@ -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 diff --git a/requirements-lock.txt b/requirements-lock.txt index 006f6e41..90dbe01d 100644 --- a/requirements-lock.txt +++ b/requirements-lock.txt @@ -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 diff --git a/tests/conftest.py b/tests/conftest.py index e764533a..4a9808e4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -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="") + 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 diff --git a/tests/integration/postgres/test_action_prepare_nodes.py b/tests/integration/postgres/test_action_prepare_nodes.py index ed1f4a61..40077d96 100644 --- a/tests/integration/postgres/test_action_prepare_nodes.py +++ b/tests/integration/postgres/test_action_prepare_nodes.py @@ -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'] diff --git a/tests/integration/postgres/test_api_bootaction.py b/tests/integration/postgres/test_api_bootaction.py index 56a3dd88..acc3802b 100644 --- a/tests/integration/postgres/test_api_bootaction.py +++ b/tests/integration/postgres/test_api_bootaction.py @@ -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( diff --git a/tests/integration/postgres/test_bootaction_signalling.py b/tests/integration/postgres/test_bootaction_signalling.py index 9f5df2d0..81803154 100644 --- a/tests/integration/postgres/test_bootaction_signalling.py +++ b/tests/integration/postgres/test_bootaction_signalling.py @@ -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) diff --git a/tests/integration/postgres/test_orch_generic.py b/tests/integration/postgres/test_orch_generic.py index 950cb0fe..afdfc567 100644 --- a/tests/integration/postgres/test_orch_generic.py +++ b/tests/integration/postgres/test_orch_generic.py @@ -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) diff --git a/tests/unit/test_api_validation.py b/tests/unit/test_api_validation.py index 2fd37bd0..974cc699 100644 --- a/tests/unit/test_api_validation.py +++ b/tests/unit/test_api_validation.py @@ -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() diff --git a/tests/unit/test_bootaction_scoping.py b/tests/unit/test_bootaction_scoping.py index 4296478e..67e626e1 100644 --- a/tests/unit/test_bootaction_scoping.py +++ b/tests/unit/test_bootaction_scoping.py @@ -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") diff --git a/tests/unit/test_node_logicalnames.py b/tests/unit/test_node_logicalnames.py new file mode 100644 index 00000000..3ec01e1c --- /dev/null +++ b/tests/unit/test_node_logicalnames.py @@ -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 = """ + + + + + + + + Rack Mount Chassis + PowerEdge R720xd (SKU=NotProvided;ModelName=PowerEdge R720xd) + Dell Inc. + 6H5LBY1 + 64 + + + + + + + + SMBIOS version 2.7 + DMI version 2.7 + 32-bit processes + + + + PCI bridge + Xeon E5/Core i7 IIO PCI Express Root Port 2a + Intel Corporation + 2 + pci@0000:00:02.0 + 07 + 32 + 33000000 + + + + + + Message Signalled Interrupts + PCI Express + Power Management + + bus mastering + PCI capabilities listing + + + + + + Ethernet interface + I350 Gigabit Network Connection + Intel Corporation + 0 + pci@0000:00:03.0 + eno1 + 01 + b8:ca:3a:65:7d:d8 + 1000000000 + 1000000000 + 32 + 33000000 + + + + + SCSI Disk + PERC H710P + DELL + 2.0.0 + scsi@2:0.0.0 + /dev/sda + 8:0 + 3.13 + 0044016c12771be71900034cfba0a38c + 299439751168 + + + +""" + 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' diff --git a/tests/unit/test_validate_design.py b/tests/unit/test_validate_design.py index 3a71e813..d0269fff 100644 --- a/tests/unit/test_validate_design.py +++ b/tests/unit/test_validate_design.py @@ -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") diff --git a/tests/unit/test_validation_rule_boot_storage.py b/tests/unit/test_validation_rule_boot_storage.py index 08a117e6..92d8b89e 100644 --- a/tests/unit/test_validation_rule_boot_storage.py +++ b/tests/unit/test_validation_rule_boot_storage.py @@ -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) diff --git a/tests/unit/test_validation_rule_storage_partitioning.py b/tests/unit/test_validation_rule_storage_partitioning.py index 78200ec1..9bfa92fe 100644 --- a/tests/unit/test_validation_rule_storage_partitioning.py +++ b/tests/unit/test_validation_rule_storage_partitioning.py @@ -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) diff --git a/tests/unit/test_validation_rule_storage_sizing.py b/tests/unit/test_validation_rule_storage_sizing.py index f91ebc69..ac6d0c0a 100644 --- a/tests/unit/test_validation_rule_storage_sizing.py +++ b/tests/unit/test_validation_rule_storage_sizing.py @@ -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) diff --git a/tests/unit/test_validation_rule_valid_platform.py b/tests/unit/test_validation_rule_valid_platform.py index 569188f4..3c3091fc 100644 --- a/tests/unit/test_validation_rule_valid_platform.py +++ b/tests/unit/test_validation_rule_valid_platform.py @@ -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")