diff --git a/drydock_provisioner/control/bootaction.py b/drydock_provisioner/control/bootaction.py index dc82a98f..67fd334a 100644 --- a/drydock_provisioner/control/bootaction.py +++ b/drydock_provisioner/control/bootaction.py @@ -163,6 +163,8 @@ class BootactionAssetsResource(StatefulResource): try: task = self.state_manager.get_task(ba_ctx['task_id']) + self.logger.debug("Loading design for task %s from design ref %s" % + (ba_ctx['task_id'], task.design_ref)) design_status, site_design = self.orchestrator.get_effective_site( task.design_ref) diff --git a/drydock_provisioner/objects/hostprofile.py b/drydock_provisioner/objects/hostprofile.py index 724d3fed..667e93f9 100644 --- a/drydock_provisioner/objects/hostprofile.py +++ b/drydock_provisioner/objects/hostprofile.py @@ -88,6 +88,9 @@ class HostProfile(base.DrydockPersistentObject, base.DrydockObject): def apply_inheritance(self, site_design): # No parent to inherit from, just apply design values # and return + if self.source == hd_fields.ModelSource.Compiled: + return + if self.parent_profile is None: self.source = hd_fields.ModelSource.Compiled return diff --git a/drydock_provisioner/orchestrator/orchestrator.py b/drydock_provisioner/orchestrator/orchestrator.py index 9b81bd4e..af49fa5a 100644 --- a/drydock_provisioner/orchestrator/orchestrator.py +++ b/drydock_provisioner/orchestrator/orchestrator.py @@ -554,7 +554,12 @@ class Orchestrator(object): identity_key = None + self.logger.debug( + "Creating boot action context for node %s" % nodename) + for ba in site_design.bootactions: + self.logger.debug( + "Boot actions target nodes: %s" % ba.target_nodes) if nodename in ba.target_nodes: if identity_key is None: identity_key = os.urandom(32) diff --git a/tests/integration/postgres/test_action_prepare_nodes.py b/tests/integration/postgres/test_action_prepare_nodes.py index c5e28579..263e24a4 100644 --- a/tests/integration/postgres/test_action_prepare_nodes.py +++ b/tests/integration/postgres/test_action_prepare_nodes.py @@ -59,7 +59,7 @@ class TestActionPrepareNodes(object): # check that the PrepareNodes action was split # with 2 nodes in the definition - assert len(task.subtask_id_list) == 2 + assert len(task.subtask_id_list) == 3 for st_id in task.subtask_id_list: st = drydock_state.get_task(st_id) diff --git a/tests/integration/postgres/test_bootaction_context.py b/tests/integration/postgres/test_bootaction_context.py new file mode 100644 index 00000000..0e9cbf14 --- /dev/null +++ b/tests/integration/postgres/test_bootaction_context.py @@ -0,0 +1,73 @@ +# 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. +"""Generic testing for the orchestrator.""" +import pytest +import tarfile +import io +import falcon + +from falcon import testing + +import drydock_provisioner.objects.fields as hd_fields + +from drydock_provisioner.control.api import start_api + + +class TestBootActionContext(object): + def test_bootaction_context(self, falcontest, seed_bootaction_multinode): + """Test that the API will return a boot action context""" + for n, c in seed_bootaction_multinode.items(): + url = "/api/v1.0/bootactions/nodes/%s/units" % n + auth_hdr = {'X-Bootaction-Key': "%s" % c['identity_key']} + + result = falcontest.simulate_get(url, headers=auth_hdr) + + assert result.status == falcon.HTTP_200 + + fileobj = io.BytesIO(result.content) + t = tarfile.open(mode='r:gz', fileobj=fileobj) + t.close() + + @pytest.fixture() + def seed_bootaction_multinode(self, blank_state, deckhand_orchestrator, + input_files, mock_get_build_data): + """Add a task and boot action to the database for testing.""" + input_file = input_files.join("deckhand_fullsite.yaml") + design_ref = "file://%s" % input_file + test_task = deckhand_orchestrator.create_task( + action=hd_fields.OrchestratorAction.Noop, design_ref=design_ref) + + ba_ctx = dict() + + design_status, design_data = deckhand_orchestrator.get_effective_site( + design_ref) + + for n in design_data.baremetal_nodes: + id_key = deckhand_orchestrator.create_bootaction_context( + n.name, test_task) + node_ctx = dict( + task_id=test_task.get_id(), identity_key=id_key.hex()) + ba_ctx[n.name] = node_ctx + + return ba_ctx + + @pytest.fixture() + def falcontest(self, drydock_state, deckhand_ingester, + deckhand_orchestrator, mock_get_build_data): + """Create a test harness for the the Falcon API framework.""" + return testing.TestClient( + start_api( + state_manager=drydock_state, + ingester=deckhand_ingester, + orchestrator=deckhand_orchestrator)) diff --git a/tests/integration/postgres/test_bootaction_signalling.py b/tests/integration/postgres/test_bootaction_signalling.py index cade22b3..18bce94f 100644 --- a/tests/integration/postgres/test_bootaction_signalling.py +++ b/tests/integration/postgres/test_bootaction_signalling.py @@ -29,7 +29,7 @@ class TestBootActionSignal(object): deckhand_orchestrator.create_bootaction_context("compute01", task) - # In the fullsite YAML, node 'compute01' is assigned two + # In the fullsite YAML, node 'controller01' is assigned two # bootactions - one with signaling enabled, one disabled. # Validate these counts @@ -54,4 +54,4 @@ class TestBootActionSignal(object): design_status, design_data = deckhand_orchestrator.get_effective_site( design_ref=design_ref) - assert len(design_data.bootactions) == 2 + assert len(design_data.bootactions) == 3 diff --git a/tests/unit/test_bootaction_scoping.py b/tests/unit/test_bootaction_scoping.py index 5da15c41..8cd2adf1 100644 --- a/tests/unit/test_bootaction_scoping.py +++ b/tests/unit/test_bootaction_scoping.py @@ -53,5 +53,5 @@ class TestClass(object): for ba in design_data.bootactions: if ba.get_id() == 'hw_filtered': - assert 'compute01' in ba.target_nodes assert 'controller01' not in ba.target_nodes + assert 'compute01' in ba.target_nodes diff --git a/tests/unit/test_ingester.py b/tests/unit/test_ingester.py index 96cd800a..3f86a348 100644 --- a/tests/unit/test_ingester.py +++ b/tests/unit/test_ingester.py @@ -29,7 +29,7 @@ class TestClass(object): assert design_status.status == objects.fields.ValidationResult.Success assert len(design_data.host_profiles) == 2 - assert len(design_data.baremetal_nodes) == 2 + assert len(design_data.baremetal_nodes) == 3 def test_ingest_deckhand_docref_exists(self, input_files, setup, deckhand_ingester): diff --git a/tests/unit/test_param_reference.py b/tests/unit/test_param_reference.py index c944a263..862512ba 100644 --- a/tests/unit/test_param_reference.py +++ b/tests/unit/test_param_reference.py @@ -34,7 +34,7 @@ class TestKernelParameterReferences(object): design_status, design_data = orchestrator.get_effective_site( design_ref) - assert len(design_data.baremetal_nodes) == 2 + assert len(design_data.baremetal_nodes) == 3 node = design_data.get_baremetal_node("compute01") diff --git a/tests/unit/test_validation_rule_storage_sizing.py b/tests/unit/test_validation_rule_storage_sizing.py index 2bc4aa86..fce4f5ef 100644 --- a/tests/unit/test_validation_rule_storage_sizing.py +++ b/tests/unit/test_validation_rule_storage_sizing.py @@ -59,7 +59,7 @@ class TestStorageSizing(object): '(Storage partition)|(Logical Volume) .+ size is < 0') regex_1 = re.compile('greater than 99%') - assert len(message_list) == 6 + assert len(message_list) == 8 for msg in message_list: msg = msg.to_dict() LOG.debug(msg) diff --git a/tests/yaml_samples/deckhand_fullsite.yaml b/tests/yaml_samples/deckhand_fullsite.yaml index 92185300..8e1fa785 100644 --- a/tests/yaml_samples/deckhand_fullsite.yaml +++ b/tests/yaml_samples/deckhand_fullsite.yaml @@ -360,6 +360,27 @@ data: metadata: rack: rack2 --- +schema: 'drydock/BaremetalNode/v1' +metadata: + schema: 'metadata/Document/v1' + name: compute02 + storagePolicy: 'cleartext' + labels: + application: 'drydock' +data: + host_profile: k8-node + addressing: + - network: pxe + address: dhcp + - network: mgmt + address: 172.16.1.23 + - network: private + address: 172.16.2.23 + - network: oob + address: 172.16.100.23 + metadata: + rack: rack3 +--- schema: 'drydock/HardwareProfile/v1' metadata: schema: 'metadata/Document/v1' @@ -473,4 +494,48 @@ data: - base64_decode - utf8_decode - template +--- +schema: 'drydock/BootAction/v1' +metadata: + schema: 'metadata/Document/v1' + name: hw_filtered2 + storagePolicy: 'cleartext' + labels: + application: 'drydock' +data: + node_filter: + filter_set_type: 'union' + filter_set: + - filter_type: 'union' + node_names: + - 'compute02' + assets: + - path: /var/tmp/hello.sh + type: file + permissions: '555' + data: |- + IyEvYmluL2Jhc2gKCmVjaG8gJ0hlbGxvIFdvcmxkISAtZnJvbSB7eyBub2RlLmhvc3RuYW1lIH19 + Jwo= + data_pipeline: + - base64_decode + - utf8_decode + - template + - path: /lib/systemd/system/hello.service + type: unit + permissions: '600' + data: |- + W1VuaXRdCkRlc2NyaXB0aW9uPUhlbGxvIFdvcmxkCgpbU2VydmljZV0KVHlwZT1vbmVzaG90CkV4 + ZWNTdGFydD0vdmFyL3RtcC9oZWxsby5zaAoKW0luc3RhbGxdCldhbnRlZEJ5PW11bHRpLXVzZXIu + dGFyZ2V0Cg== + data_pipeline: + - base64_decode + - utf8_decode + - path: /var/tmp/designref.sh + type: file + permissions: '500' + data: e3sgYWN0aW9uLmRlc2lnbl9yZWYgfX0K + data_pipeline: + - base64_decode + - utf8_decode + - template ...