Match hostname when doing node delete
``overcloud node delete`` at present matches the provided nova instance ids with existing severs to build the heat blacklist. This patch would allow users to also use hostnames when deleting nodes. This will work with deployed servers and scale_playbook.yaml that matches host pattern. Partial-Bug: #1869089 Depends-On: https://review.opendev.org/727696 Change-Id: I3066689facc169125ade29156190cb98910f32b8 (cherry picked from commitbe7c90e30c
) (cherry picked from commit56c0fd5caf
)
This commit is contained in:
parent
c782d68884
commit
927583ded3
@ -120,20 +120,37 @@ class ScaleDownAction(templates.ProcessTemplatesAction):
|
||||
|
||||
return stack_params
|
||||
|
||||
def _match_hostname(self, heatclient, instance_list, res, stack_name):
|
||||
type_patterns = ['DeployedServer', 'Server']
|
||||
if any(res.resource_type.endswith(x) for x in type_patterns):
|
||||
res_details = heatclient.resources.get(
|
||||
stack_name, res.resource_name)
|
||||
if 'name' in res_details.attributes:
|
||||
try:
|
||||
instance_list.remove(res_details.attributes['name'])
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
return False
|
||||
|
||||
def run(self, context):
|
||||
heatclient = self.get_orchestration_client(context)
|
||||
resources = heatclient.resources.list(self.container, nested_depth=5)
|
||||
resources_by_role = collections.defaultdict(list)
|
||||
instance_list = list(self.nodes)
|
||||
for res in resources:
|
||||
try:
|
||||
instance_list.remove(res.physical_resource_id)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
for res in resources:
|
||||
stack_name, stack_id = next(
|
||||
x['href'] for x in res.links if
|
||||
x['rel'] == 'stack').rsplit('/', 2)[1:]
|
||||
|
||||
try:
|
||||
instance_list.remove(res.physical_resource_id)
|
||||
except ValueError:
|
||||
if not self._match_hostname(
|
||||
heatclient, instance_list, res, stack_name):
|
||||
continue
|
||||
|
||||
# get resource to remove from resource group (it's parent resource
|
||||
# of nova server)
|
||||
role_resource = next(x for x in resources if
|
||||
|
@ -72,7 +72,7 @@ class ScaleDownActionTest(base.TestCase):
|
||||
'a959ac7d6a4a475daf2428df315c41ef/'
|
||||
'stacks/overcloud/124'}],
|
||||
logical_resource_id='node0',
|
||||
physical_resource_id='123',
|
||||
physical_resource_id='124',
|
||||
resource_type='OS::TripleO::Compute',
|
||||
parent_resource='Compute',
|
||||
resource_name='node0',
|
||||
@ -129,7 +129,7 @@ class ScaleDownActionTest(base.TestCase):
|
||||
|
||||
# Test
|
||||
action = scale.ScaleDownAction(
|
||||
constants.STACK_TIMEOUT_DEFAULT, ['resource_id'], 'stack')
|
||||
constants.STACK_TIMEOUT_DEFAULT, ['124'], 'stack')
|
||||
action.run(mock_ctx)
|
||||
|
||||
heatclient.stacks.validate.assert_called_once_with(
|
||||
@ -152,3 +152,119 @@ class ScaleDownActionTest(base.TestCase):
|
||||
"stack",
|
||||
"tripleo.parameters.get"
|
||||
)
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_delete')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('heatclient.common.template_utils.'
|
||||
'process_multiple_environments_and_files')
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run_with_hostmatch(self, mock_get_object_client,
|
||||
mock_get_template_contents, mock_env_files,
|
||||
mock_get_heat_client, mock_cache):
|
||||
|
||||
mock_env_files.return_value = ({}, {})
|
||||
heatclient = mock.MagicMock()
|
||||
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='resource_id',
|
||||
resource_type='OS::Heat::ResourceGroup',
|
||||
resource_name='Compute'
|
||||
),
|
||||
mock.MagicMock(
|
||||
links=[{'rel': 'stack',
|
||||
'href': 'http://192.0.2.1:8004/v1/'
|
||||
'a959ac7d6a4a475daf2428df315c41ef/'
|
||||
'stacks/overcloud/124'}],
|
||||
logical_resource_id='node0',
|
||||
physical_resource_id='124',
|
||||
resource_type='OS::TripleO::ComputeServer',
|
||||
parent_resource='Compute',
|
||||
resource_name='node0',
|
||||
)
|
||||
]
|
||||
heatclient.resources.get.return_value = mock.MagicMock(
|
||||
attributes={'name': 'node0'})
|
||||
heatclient.stacks.get.return_value = mock_stack()
|
||||
heatclient.stacks.validate.return_value = {}
|
||||
mock_get_heat_client.return_value = heatclient
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': 'overcloud',
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
mock_roles = yaml.safe_dump([{"name": "foo"}])
|
||||
mock_network = yaml.safe_dump([{'enabled': False}])
|
||||
mock_exclude = yaml.safe_dump({"name": "foo"})
|
||||
swift.get_object.side_effect = (
|
||||
({}, mock_env),
|
||||
({}, mock_env),
|
||||
({}, mock_roles),
|
||||
({}, mock_network),
|
||||
({}, mock_exclude),
|
||||
({}, mock_env),
|
||||
({}, mock_env),
|
||||
({}, mock_env),
|
||||
({}, mock_roles),
|
||||
({}, mock_network),
|
||||
({}, mock_exclude),
|
||||
({}, mock_env),
|
||||
({}, mock_env),
|
||||
swiftexceptions.ClientException('atest2')
|
||||
)
|
||||
|
||||
def return_container_files(*args):
|
||||
return ('headers', [{'name': 'foo.role.j2.yaml'}])
|
||||
|
||||
swift.get_container = mock.MagicMock(
|
||||
side_effect=return_container_files)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
env = {
|
||||
'resource_registry': {
|
||||
'resources': {'*': {'*': {'UpdateDeployment': {'hooks': []}}}}
|
||||
}
|
||||
}
|
||||
|
||||
mock_get_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
})
|
||||
|
||||
# Test
|
||||
action = scale.ScaleDownAction(
|
||||
constants.STACK_TIMEOUT_DEFAULT, ['node0'], 'stack')
|
||||
result = action.run(mock_ctx)
|
||||
|
||||
heatclient.stacks.validate.assert_called_once_with(
|
||||
environment=env,
|
||||
files={},
|
||||
show_nested=True,
|
||||
template={'heat_template_version': '2016-04-30'}
|
||||
)
|
||||
|
||||
clear_list = list(['ComputeCount', 'ComputeRemovalPolicies',
|
||||
'ComputeRemovalPoliciesMode'])
|
||||
_, kwargs = heatclient.stacks.update.call_args
|
||||
self.assertEqual(set(kwargs['clear_parameters']), set(clear_list))
|
||||
self.assertEqual(kwargs['environment'], env)
|
||||
self.assertEqual(kwargs['existing'], True)
|
||||
self.assertEqual(kwargs['files'], {})
|
||||
|
||||
mock_cache.assert_called_with(
|
||||
mock_ctx,
|
||||
"stack",
|
||||
"tripleo.parameters.get"
|
||||
)
|
||||
|
||||
self.assertEqual(None, result)
|
||||
|
Loading…
Reference in New Issue
Block a user