From c06e2c9baffedc4e2c31dd2b8fa842ff7faf373a Mon Sep 17 00:00:00 2001 From: Dmitry Tantsur Date: Mon, 10 Sep 2018 15:04:37 +0200 Subject: [PATCH] Allow overriding traits in provision_node (similar to capabilities) Change-Id: If6cfba9773dd2b5896d359d2bd1aa12f4062cfdf Story: #2003685 Task: #26356 --- metalsmith/_provisioner.py | 8 ++++- metalsmith/test/test_provisioner.py | 45 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/metalsmith/_provisioner.py b/metalsmith/_provisioner.py index 7e34985..62f1815 100644 --- a/metalsmith/_provisioner.py +++ b/metalsmith/_provisioner.py @@ -196,7 +196,7 @@ class Provisioner(object): def provision_node(self, node, image, nics=None, root_disk_size=None, config=None, hostname=None, netboot=False, - capabilities=None, wait=None): + capabilities=None, traits=None, wait=None): """Provision the node with the given image. Example:: @@ -227,6 +227,10 @@ class Provisioner(object): overwrites the capabilities set by :meth:`reserve_node`. Note that the capabilities are not checked against the ones provided by the node - use :meth:`reserve_node` for that. + :param traits: Requested traits of the node. If present, overwrites + the traits set by :meth:`reserve_node`. Note that the traits are + not checked against the ones provided by the node - use + :meth:`reserve_node` for that. :param wait: How many seconds to wait for the deployment to finish, None to return immediately. :return: :py:class:`metalsmith.Instance` object with the current @@ -270,6 +274,8 @@ class Provisioner(object): '/extra/%s' % _ATTACHED_PORTS: attached_ports, '/instance_info/%s' % _os_api.HOSTNAME_FIELD: hostname} updates.update(image._node_updates(self.connection)) + if traits is not None: + updates['/instance_info/traits'] = traits LOG.debug('Updating node %(node)s with %(updates)s', {'node': _utils.log_node(node), 'updates': updates}) diff --git a/metalsmith/test/test_provisioner.py b/metalsmith/test/test_provisioner.py index 56fceb2..e36d943 100644 --- a/metalsmith/test/test_provisioner.py +++ b/metalsmith/test/test_provisioner.py @@ -675,6 +675,51 @@ abcd image self.assertFalse(self.api.release_node.called) self.assertFalse(self.conn.network.delete_port.called) + def test_with_traits(self): + inst = self.pr.provision_node(self.node, 'image', + [{'network': 'network'}], + traits=['1', '2']) + self.updates['/instance_info/traits'] = ['1', '2'] + + self.assertEqual(inst.uuid, self.node.uuid) + self.assertEqual(inst.node, self.node) + + self.conn.network.create_port.assert_called_once_with( + network_id=self.conn.network.find_network.return_value.id) + self.api.attach_port_to_node.assert_called_once_with( + self.node.uuid, self.conn.network.create_port.return_value.id) + self.api.update_node.assert_called_once_with(self.node, self.updates) + self.api.validate_node.assert_called_once_with(self.node, + validate_deploy=True) + self.api.node_action.assert_called_once_with(self.node, 'active', + configdrive=mock.ANY) + self.assertFalse(self.wait_mock.called) + self.assertFalse(self.api.release_node.called) + self.assertFalse(self.conn.network.delete_port.called) + + def test_override_existing_traits(self): + self.node.traits = ['42'] + inst = self.pr.provision_node(self.node, 'image', + [{'network': 'network'}], + traits=['1', '2']) + self.updates['/instance_info/traits'] = ['1', '2'] + + self.assertEqual(inst.uuid, self.node.uuid) + self.assertEqual(inst.node, self.node) + + self.conn.network.create_port.assert_called_once_with( + network_id=self.conn.network.find_network.return_value.id) + self.api.attach_port_to_node.assert_called_once_with( + self.node.uuid, self.conn.network.create_port.return_value.id) + self.api.update_node.assert_called_once_with(self.node, self.updates) + self.api.validate_node.assert_called_once_with(self.node, + validate_deploy=True) + self.api.node_action.assert_called_once_with(self.node, 'active', + configdrive=mock.ANY) + self.assertFalse(self.wait_mock.called) + self.assertFalse(self.api.release_node.called) + self.assertFalse(self.conn.network.delete_port.called) + def test_with_wait(self): self.conn.network.find_port.return_value = mock.Mock( spec=['fixed_ips'],