From b941aaa48e977b02101d271598643cf3258a6e3c Mon Sep 17 00:00:00 2001 From: Dmitry Tantsur Date: Fri, 8 Mar 2019 14:29:45 +0100 Subject: [PATCH] Ensure instance_info is clean before deploy and after failure Currently stale values can be left in instance_info (and reused next time) if a deployment attempts fails. This change ensures that we: 1) Purge instance_info completely on failures 2) Only keep traits and capabilities in instance_info on deploy. Change-Id: I52a85620d9ac2f471bca6498294871f3bb16d47f (cherry picked from commit 8e7b8d3f398fd206af74708d53857154f9e8e6a1) --- metalsmith/_provisioner.py | 19 +++++++++++-------- metalsmith/test/test_provisioner.py | 3 +++ .../notes/iinfo-2014b1de4dbeca2d.yaml | 7 +++++++ 3 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/iinfo-2014b1de4dbeca2d.yaml diff --git a/metalsmith/_provisioner.py b/metalsmith/_provisioner.py index 9f2c3be..bb6b914 100644 --- a/metalsmith/_provisioner.py +++ b/metalsmith/_provisioner.py @@ -34,6 +34,7 @@ LOG = logging.getLogger(__name__) _CREATED_PORTS = 'metalsmith_created_ports' _ATTACHED_PORTS = 'metalsmith_attached_ports' +_PRESERVE_INSTANCE_INFO_KEYS = {'capabilities', 'traits'} class Provisioner(_utils.GetNodeMixin): @@ -283,7 +284,7 @@ class Provisioner(_utils.GetNodeMixin): capabilities['boot_option'] = 'netboot' if netboot else 'local' - instance_info = node.instance_info.copy() + instance_info = self._clean_instance_info(node.instance_info) instance_info['root_gb'] = root_size_gb instance_info['capabilities'] = capabilities instance_info[self.HOSTNAME_FIELD] = hostname @@ -364,6 +365,11 @@ class Provisioner(_utils.GetNodeMixin): nodes, 'active', timeout=timeout) return [_instance.Instance(self.connection, node) for node in nodes] + def _clean_instance_info(self, instance_info): + return {key: value + for key, value in instance_info.items() + if key in _PRESERVE_INSTANCE_INFO_KEYS} + def _clean_up(self, node, nics=None): if nics is None: created_ports = node.extra.get(_CREATED_PORTS, []) @@ -376,17 +382,14 @@ class Provisioner(_utils.GetNodeMixin): extra = node.extra.copy() for item in (_CREATED_PORTS, _ATTACHED_PORTS): extra.pop(item, None) - instance_info = node.instance_info.copy() - instance_info.pop(self.HOSTNAME_FIELD, None) - LOG.debug('Updating node %(node)s with instance info %(iinfo)s ' - 'and extras %(extra)s and releasing the lock', + LOG.debug('Updating node %(node)s with empty instance info (was ' + '%(iinfo)s) and extras %(extra)s and releasing the lock', {'node': _utils.log_res(node), - 'iinfo': instance_info, + 'iinfo': node.instance_info, 'extra': extra}) try: self.connection.baremetal.update_node( - node, instance_info=instance_info, extra=extra, - instance_id=None) + node, instance_info={}, extra=extra, instance_id=None) except Exception as exc: LOG.debug('Failed to clear node %(node)s extra: %(exc)s', {'node': _utils.log_res(node), 'exc': exc}) diff --git a/metalsmith/test/test_provisioner.py b/metalsmith/test/test_provisioner.py index 46bde89..2d10076 100644 --- a/metalsmith/test/test_provisioner.py +++ b/metalsmith/test/test_provisioner.py @@ -510,6 +510,9 @@ class TestProvisionNode(Base): self.image.ramdisk_id = None del self.instance_info['kernel'] del self.instance_info['ramdisk'] + # Ensure stale values clean up + self.node.instance_info['kernel'] = 'bad value' + self.node.instance_info['ramdisk'] = 'bad value' self.pr.provision_node(self.node, 'image', [{'network': 'network'}]) diff --git a/releasenotes/notes/iinfo-2014b1de4dbeca2d.yaml b/releasenotes/notes/iinfo-2014b1de4dbeca2d.yaml new file mode 100644 index 0000000..1468d24 --- /dev/null +++ b/releasenotes/notes/iinfo-2014b1de4dbeca2d.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixes stale ``instance_info`` remaining after deploy failures. + - | + Cleans up ``instance_info`` before updating it before deployment to make + sure not stale information is left there.