ExtractProvisionedNode - include removed_rsrc
Get the removed_rsrc_list for each ResourceGroup in the stack. When building the instances list, add entries with 'provisioned': false if the current index is in removed_rsrc_list and no replacement using the same hostname exist. We no longer sort entries from AnsibleHostVarsMap, I think sorting might actually be problematic in a corner case where HostnameMap was used to give nodes non-sort friendly names like: overcloud-controller-0: non overcloud-controller-1: sort overcloud-controller-2: friendly Sorting ^^ would result: overcloud-controller-0: friendly overcloud-controller-1: non overcloud-controller-2: sort Resolves: RHBZ#2238349 Change-Id: I30d5ac4921af584b2a234880aafa20bbcaea052d
This commit is contained in:
parent
b6fb1e58b1
commit
f3599d0663
@ -771,14 +771,14 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
}, {
|
||||
'output_key': 'AnsibleHostVarsMap',
|
||||
'output_value': {
|
||||
'Compute': [
|
||||
'overcloud-novacompute-0'
|
||||
],
|
||||
'Controller': [
|
||||
'overcloud-controller-0',
|
||||
'overcloud-controller-1',
|
||||
'overcloud-controller-2'
|
||||
],
|
||||
'Compute': {
|
||||
'overcloud-novacompute-0': {},
|
||||
},
|
||||
'Controller': {
|
||||
'overcloud-controller-0': {},
|
||||
'overcloud-controller-1': {},
|
||||
'overcloud-controller-2': {},
|
||||
},
|
||||
}
|
||||
}, {
|
||||
'output_key': 'RoleNetIpMap',
|
||||
@ -802,6 +802,10 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
}]
|
||||
}
|
||||
|
||||
self.resource = mock.Mock()
|
||||
self.resource.attributes = dict()
|
||||
self.resource.attributes['removed_rsrc_list'] = []
|
||||
|
||||
self.nodes = [
|
||||
mock.Mock(),
|
||||
mock.Mock(),
|
||||
@ -925,9 +929,11 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
|
||||
def test_extract(self):
|
||||
stack = mock.Mock()
|
||||
stack.stack_name = 'overcloud'
|
||||
stack.to_dict.return_value = self.stack_dict
|
||||
stack.environment.return_value = {}
|
||||
self.orchestration.stacks.get.return_value = stack
|
||||
self.orchestration.resources.get.return_value = self.resource
|
||||
|
||||
self.baremetal.node.list.return_value = self.nodes
|
||||
argslist = ['--output', self.extract_file.name,
|
||||
@ -1001,6 +1007,7 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
|
||||
def test_extract_ips_from_pool(self):
|
||||
stack = mock.Mock()
|
||||
stack.stack_name = 'overcloud'
|
||||
stack.to_dict.return_value = self.stack_dict
|
||||
stack.environment.return_value = {
|
||||
'parameter_defaults': {
|
||||
@ -1011,6 +1018,7 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
}
|
||||
}
|
||||
self.orchestration.stacks.get.return_value = stack
|
||||
self.orchestration.resources.get.return_value = self.resource
|
||||
|
||||
self.baremetal.node.list.return_value = self.nodes
|
||||
argslist = ['--roles-file', self.roles_file.name,
|
||||
@ -1131,6 +1139,7 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
}
|
||||
}
|
||||
self.orchestration.stacks.get.return_value = stack
|
||||
self.orchestration.resources.get.return_value = self.resource
|
||||
|
||||
self.baremetal.node.list.return_value = self.nodes
|
||||
|
||||
@ -1229,6 +1238,7 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
'outputs': []
|
||||
}
|
||||
stack = mock.Mock()
|
||||
stack.stack_name = 'overcloud'
|
||||
stack.to_dict.return_value = stack_dict
|
||||
self.orchestration.stacks.get.return_value = stack
|
||||
|
||||
@ -1273,14 +1283,14 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
}, {
|
||||
'output_key': 'AnsibleHostVarsMap',
|
||||
'output_value': {
|
||||
'Compute': [
|
||||
'overcloud-novacompute-0'
|
||||
],
|
||||
'Controller': [
|
||||
'overcloud-controller-0',
|
||||
'overcloud-controller-1',
|
||||
'overcloud-controller-2'
|
||||
],
|
||||
'Compute': {
|
||||
'overcloud-novacompute-0': {}
|
||||
},
|
||||
'Controller': {
|
||||
'overcloud-controller-0': {},
|
||||
'overcloud-controller-1': {},
|
||||
'overcloud-controller-2': {},
|
||||
},
|
||||
}
|
||||
}, {
|
||||
'output_key': 'RoleNetIpMap',
|
||||
@ -1303,6 +1313,8 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
stack.to_dict.return_value = stack_dict
|
||||
stack.environment.return_value = {}
|
||||
self.orchestration.stacks.get.return_value = stack
|
||||
self.orchestration.resources.get.return_value = self.resource
|
||||
|
||||
self.baremetal.node.list.return_value = self.nodes
|
||||
self.network.find_network.side_effect = [
|
||||
self.ctlplane_net, None,
|
||||
@ -1377,3 +1389,112 @@ class TestExtractProvisionedNode(test_utils.TestCommand):
|
||||
'name': 'bm-2-uuid',
|
||||
}],
|
||||
}], yaml.safe_load(result))
|
||||
|
||||
def test_extract_removed_resources(self):
|
||||
roles_data = [{'name': 'Controller',
|
||||
'default_route_networks': ['External'],
|
||||
'networks_skip_config': ['Tenant']}]
|
||||
networks_data = []
|
||||
stack = mock.Mock()
|
||||
stack.stack_name = 'overcloud'
|
||||
stack_dict = {
|
||||
'parameters': {
|
||||
'ControllerHostnameFormat': '%stackname%-controller-%index%',
|
||||
'ControllerNetworkConfigTemplate': 'templates/controller.j2'
|
||||
},
|
||||
'outputs': [{
|
||||
'output_key': 'TripleoHeatTemplatesJinja2RenderingDataSources',
|
||||
'output_value': {
|
||||
'roles_data': roles_data,
|
||||
'networks_data': networks_data,
|
||||
}
|
||||
}, {
|
||||
'output_key': 'AnsibleHostVarsMap',
|
||||
'output_value': {
|
||||
'Controller': {
|
||||
'overcloud-controller-0': {},
|
||||
'overcloud-controller-2': {},
|
||||
'overcloud-controller-3': {},
|
||||
},
|
||||
}
|
||||
}, {
|
||||
'output_key': 'RoleNetIpMap',
|
||||
'output_value': {
|
||||
'Controller': {
|
||||
'ctlplane': ['192.168.25.21',
|
||||
'192.168.25.25',
|
||||
'192.168.25.28'],
|
||||
'external': ['10.0.0.199',
|
||||
'10.0.0.197',
|
||||
'10.0.0.191'],
|
||||
'internal_api': ['172.17.0.37',
|
||||
'172.17.0.33',
|
||||
'172.17.0.39'],
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
stack.to_dict.return_value = stack_dict
|
||||
stack.environment.return_value = {}
|
||||
self.orchestration.stacks.get.return_value = stack
|
||||
resource = mock.Mock()
|
||||
resource.attributes = dict()
|
||||
resource.attributes['removed_rsrc_list'] = ['1']
|
||||
self.orchestration.resources.get.return_value = resource
|
||||
nodes = [mock.Mock(), mock.Mock(), mock.Mock()]
|
||||
nodes[0].name = 'bm-0'
|
||||
nodes[0].uuid = 'bm-0-uuid'
|
||||
nodes[0].resource_class = 'controller'
|
||||
nodes[1].name = 'bm-2'
|
||||
nodes[1].uuid = 'bm-2-uuid'
|
||||
nodes[1].resource_class = 'controller'
|
||||
nodes[2].name = 'bm-3'
|
||||
nodes[2].uuid = 'bm-3-uuid'
|
||||
nodes[2].resource_class = None
|
||||
|
||||
nodes[0].instance_info = {'display_name': 'overcloud-controller-0'}
|
||||
nodes[1].instance_info = {'display_name': 'overcloud-controller-2'}
|
||||
nodes[2].instance_info = {'display_name': 'overcloud-controller-3'}
|
||||
|
||||
self.baremetal.node.list.return_value = nodes
|
||||
|
||||
self.network.find_network.side_effect = [
|
||||
# controller-0
|
||||
self.ctlplane_net, self.external_net, self.internal_api_net,
|
||||
# controller-2
|
||||
self.ctlplane_net, self.external_net, self.internal_api_net,
|
||||
# controller-3
|
||||
self.ctlplane_net, self.external_net, self.internal_api_net,
|
||||
]
|
||||
self.network.get_subnet.side_effect = [
|
||||
# controller-0
|
||||
self.ctlplane_a, self.external_a, self.int_api_a,
|
||||
# controller-2
|
||||
self.ctlplane_a, self.external_a, self.int_api_a,
|
||||
# controller-3
|
||||
self.ctlplane_a, self.external_a, self.int_api_a,
|
||||
]
|
||||
|
||||
argslist = ['--output', self.extract_file.name, '--yes']
|
||||
self.app.command_options = argslist
|
||||
verifylist = [('output', self.extract_file.name), ('yes', True)]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
result = self.cmd.app.stdout.make_string()
|
||||
self.assertEqual(
|
||||
[
|
||||
{'hostname': 'overcloud-controller-0',
|
||||
'name': 'bm-0-uuid',
|
||||
'resource_class': 'controller'},
|
||||
{'hostname': 'overcloud-controller-1',
|
||||
'provisioned': False},
|
||||
{'hostname': 'overcloud-controller-2',
|
||||
'name': 'bm-2-uuid',
|
||||
'resource_class': 'controller'},
|
||||
{'hostname': 'overcloud-controller-3',
|
||||
'name': 'bm-3-uuid'}
|
||||
],
|
||||
yaml.safe_load(result)[0]['instances']
|
||||
)
|
||||
|
@ -1091,6 +1091,19 @@ def get_role_net_ip_map(working_dir):
|
||||
'RoleNetIpMap', working_dir)
|
||||
|
||||
|
||||
def get_role_removed_rsrc_list(orchestration_client, stack_id, role_name):
|
||||
res = orchestration_client.resources.get(stack_id, role_name)
|
||||
|
||||
return res.attributes.get('removed_rsrc_list', [])
|
||||
|
||||
|
||||
def generate_hostname(hostname_format, stack_name, index):
|
||||
|
||||
return hostname_format.replace(
|
||||
'%stackname%', stack_name).replace(
|
||||
'%index%', str(index))
|
||||
|
||||
|
||||
def get_stack(orchestration_client, stack_name):
|
||||
"""Get the ID for the current deployed overcloud stack if it exists.
|
||||
|
||||
|
@ -749,10 +749,31 @@ class ExtractProvisionedNode(command.Command):
|
||||
'networks_skip_config')
|
||||
|
||||
# Add individual instances
|
||||
removed_rsrc_list = oooutils.get_role_removed_rsrc_list(
|
||||
self.orchestration_client, stack.id, role_name)
|
||||
ips_from_pool = parameter_defaults.get(
|
||||
'{}IPs'.format(role_name), {})
|
||||
instances = role['instances'] = []
|
||||
for idx, entry in enumerate(sorted(entries)):
|
||||
entry_names = list(entries.keys())
|
||||
for idx in range(len(entries) + len(removed_rsrc_list)):
|
||||
try:
|
||||
entry = entry_names[idx]
|
||||
except IndexError:
|
||||
# In case of scale down removed_rsrc_list can cause
|
||||
# iteration out of range. There should be no need to add
|
||||
# unprovisioned entries at the end of instances list.
|
||||
break
|
||||
|
||||
# Insert unprovisioned entry if removed node was not replaced
|
||||
# by a node re-using the hostname via HostnameMap.
|
||||
# If the hostname was re-used we should safely be able to re-
|
||||
# use the original index in ephemeral heat.
|
||||
gen_name = oooutils.generate_hostname(
|
||||
hostname_format, stack.stack_name, idx)
|
||||
if str(idx) in removed_rsrc_list and gen_name not in entries:
|
||||
instance = {'hostname': gen_name, 'provisioned': False}
|
||||
instances.append(instance)
|
||||
|
||||
instance = {'hostname': entry}
|
||||
|
||||
if entry in hostname_node_map:
|
||||
|
Loading…
Reference in New Issue
Block a user