diff --git a/releasenotes/notes/deployed-server-clear-breakpoint-ee1a984f3366598a.yaml b/releasenotes/notes/deployed-server-clear-breakpoint-ee1a984f3366598a.yaml new file mode 100644 index 000000000..33c6c7e20 --- /dev/null +++ b/releasenotes/notes/deployed-server-clear-breakpoint-ee1a984f3366598a.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - When performing an interactive minor update with deployed-server, the + client never prompted to clear breakpoints and just ran to completion and + exited. The stack was left IN_PROGRESS. That issue has now been fixed so + that the client will prompt to clear breakpoints. diff --git a/tripleo_common/_stack_update.py b/tripleo_common/_stack_update.py index 9112d0017..5820c2728 100644 --- a/tripleo_common/_stack_update.py +++ b/tripleo_common/_stack_update.py @@ -25,6 +25,11 @@ import heatclient.exc LOG = logging.getLogger(__name__) +class DeployedServer(object): + id = None + name = None + + class StackUpdateManager(object): def __init__(self, heatclient, novaclient, stack, hook_type, nested_depth=5, hook_resource=None): @@ -182,13 +187,35 @@ class StackUpdateManager(object): name = self.server_names.get(deployment_id) if not name: if not self.servers: - self.servers = self.novaclient.servers.list() + self.servers = self._get_servers() depl = self.heatclient.software_deployments.get(deployment_id) name = next(server.name for server in self.servers if server.id == depl.server_id) self.server_names[deployment_id] = name return name + def _get_servers(self): + servers = self.novaclient.servers.list() + + # If no servers were found from Nova, we must be using split-stack, + # so we will have to interrogate Heat for the names and id's. + if not servers: + resources = self.heatclient.resources.list( + self.stack.id, nested_depth=self.nested_depth, + filters=dict(type="OS::Heat::DeployedServer")) + for res in resources: + server = DeployedServer() + stack_name, stack_id = next( + x['href'] for x in res.links if + x['rel'] == 'stack').rsplit('/', 2)[1:] + stack = self.heatclient.stacks.get(stack_id) + server.name = next(o['output_value'] for o in stack.outputs if + o['output_key'] == 'name') + server.id = res.physical_resource_id + servers.append(server) + + return servers + def _input_to_refs(self, regexp, refs): if regexp: try: diff --git a/tripleo_common/tests/test_stack_update.py b/tripleo_common/tests/test_stack_update.py index 86a12bb93..ba08b3e30 100644 --- a/tripleo_common/tests/test_stack_update.py +++ b/tripleo_common/tests/test_stack_update.py @@ -99,3 +99,44 @@ class StackUpdateManagerTest(base.TestCase): result = self.stack_update_manager._input_to_refs( ']].*', ['instance_id']) self.assertEqual(result, []) + + def test_get_servers(self): + self.stack_update_manager._get_servers() + self.novaclient.servers.list.assert_called() + + def test_get_servers_deployed_server(self): + self.novaclient.servers.list.return_value = [] + self.heatclient.resources.list.return_value = [ + mock.MagicMock( + links=[{'rel': 'stack', + 'href': 'http://192.0.2.1:8004/v1/' + 'a959ac7d6a4a475daf2428df315c41ef/' + 'stacks/overcloud/123'}], + logical_resource_id='logical_id', + physical_resource_id='controller_resource_id', + type='OS::Heat::DeployedServer' + ), + mock.MagicMock( + links=[{'rel': 'stack', + 'href': 'http://192.0.2.1:8004/v1/' + 'a959ac7d6a4a475daf2428df315c41ef/' + 'stacks/overcloud/123'}], + logical_resource_id='logical_id', + physical_resource_id='compute_resource_id', + type='OS::Heat::DeployedServer' + ) + ] + self.heatclient.stacks.get.side_effect = [ + mock.MagicMock( + outputs=[{'output_key': 'name', + 'output_value': 'overcloud-controller-0'}]), + mock.MagicMock( + outputs=[{'output_key': 'name', + 'output_value': 'overcloud-compute-0'}]), + ] + + servers = self.stack_update_manager._get_servers() + self.assertEqual(servers[0].name, 'overcloud-controller-0') + self.assertEqual(servers[0].id, 'controller_resource_id') + self.assertEqual(servers[1].name, 'overcloud-compute-0') + self.assertEqual(servers[1].id, 'compute_resource_id')