Add --skip-deploy-identifier
Add a new cli argument, --skip-deploy-identifier. The argument will eventually be passed to the tripleo-common DeployStackAction action to disable setting a unique value for the DeployIdentifier parameter, which means the SoftwareDeployment resources in the templates will only be triggered if there is an actual change to their configuration. This argument can be used to avoid always applying configuration, such as during node scale out. Removes the setting of DeployIdentifier completely from tripleoclient, as that is now handled by the tripleo-common action. Depends-On: Idb901a841846fec33d189b3c95f669b0380498ce Change-Id: I294eabe84e070367981534030b5927062f00c628
This commit is contained in:
parent
e8b0a54a30
commit
f3acb69ffc
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add a new cli argument, --skip-deploy-identifier. The argument will disable
|
||||||
|
setting a unique value for the DeployIdentifier parameter, which means the
|
||||||
|
SoftwareDeployment resources in the templates will only be triggered if
|
||||||
|
there is an actual change to their configuration. This argument can be used
|
||||||
|
to avoid always applying configuration, such as during node scale out.
|
||||||
|
This option should be used with Caution, and only if there is confidence
|
||||||
|
that the software configuration does not need to be run, such as when
|
||||||
|
scaling out certain roles.
|
|
@ -285,6 +285,101 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||||
mock_tarball.tarball_extract_to_swift_container.assert_called_with(
|
mock_tarball.tarball_extract_to_swift_container.assert_called_with(
|
||||||
clients.tripleoclient.object_store, mock.ANY, 'overcloud')
|
clients.tripleoclient.object_store, mock.ANY, 'overcloud')
|
||||||
|
|
||||||
|
@mock.patch('tripleoclient.utils.get_overcloud_endpoint', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
|
'_deploy_postconfig', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.workflows.plan_management.tarball',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleo_common.update.add_breakpoints_cleanup_into_env',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
|
'_validate_args')
|
||||||
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
|
'_create_parameters_env', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.create_tempest_deployer_input',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.write_overcloudrc', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.remove_known_hosts', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.wait_for_stack_ready',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('heatclient.common.template_utils.get_template_contents',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.check_hypervisor_stats',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('uuid.uuid1', autospec=True)
|
||||||
|
@mock.patch('time.time', autospec=True)
|
||||||
|
@mock.patch('shutil.rmtree', autospec=True)
|
||||||
|
@mock.patch('shutil.copytree', autospec=True)
|
||||||
|
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||||
|
def test_tht_deploy_skip_deploy_identifier(
|
||||||
|
self, mock_tmpdir, mock_copy, mock_rm, mock_time,
|
||||||
|
mock_uuid1,
|
||||||
|
mock_check_hypervisor_stats,
|
||||||
|
mock_get_template_contents,
|
||||||
|
wait_for_stack_ready_mock,
|
||||||
|
mock_remove_known_hosts,
|
||||||
|
mock_write_overcloudrc,
|
||||||
|
mock_create_tempest_deployer_input,
|
||||||
|
mock_create_parameters_env, mock_validate_args,
|
||||||
|
mock_breakpoints_cleanup, mock_tarball,
|
||||||
|
mock_postconfig, mock_get_overcloud_endpoint):
|
||||||
|
|
||||||
|
arglist = ['--templates', '--skip-deploy-identifier']
|
||||||
|
verifylist = [
|
||||||
|
('templates', '/usr/share/openstack-tripleo-heat-templates/'),
|
||||||
|
('skip_deploy_identifier', True)
|
||||||
|
]
|
||||||
|
|
||||||
|
mock_tmpdir.return_value = "/tmp/tht"
|
||||||
|
mock_uuid1.return_value = "uuid"
|
||||||
|
mock_time.return_value = 123456789
|
||||||
|
|
||||||
|
clients = self.app.client_manager
|
||||||
|
orchestration_client = clients.orchestration
|
||||||
|
mock_stack = fakes.create_tht_stack()
|
||||||
|
orchestration_client.stacks.get.side_effect = [None, mock.Mock()]
|
||||||
|
workflow_client = clients.workflow_engine
|
||||||
|
workflow_client.environments.get.return_value = mock.MagicMock(
|
||||||
|
variables={'environments': []})
|
||||||
|
workflow_client.action_executions.create.return_value = mock.MagicMock(
|
||||||
|
output='{"result":[]}')
|
||||||
|
|
||||||
|
def _orch_clt_create(**kwargs):
|
||||||
|
orchestration_client.stacks.get.return_value = mock_stack
|
||||||
|
|
||||||
|
orchestration_client.stacks.create.side_effect = _orch_clt_create
|
||||||
|
|
||||||
|
mock_check_hypervisor_stats.return_value = {
|
||||||
|
'count': 4,
|
||||||
|
'memory_mb': 4096,
|
||||||
|
'vcpus': 8,
|
||||||
|
}
|
||||||
|
clients.network.api.find_attr.return_value = {
|
||||||
|
"id": "network id"
|
||||||
|
}
|
||||||
|
mock_get_template_contents.return_value = [{}, "template"]
|
||||||
|
wait_for_stack_ready_mock.return_value = True
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
baremetal = clients.baremetal
|
||||||
|
baremetal.node.list.return_value = range(10)
|
||||||
|
|
||||||
|
testcase = self
|
||||||
|
|
||||||
|
def _custom_create_params_env(self, parameters):
|
||||||
|
testcase.assertTrue('DeployIdentifier' not in parameters)
|
||||||
|
parameter_defaults = {"parameter_defaults": parameters}
|
||||||
|
return parameter_defaults
|
||||||
|
|
||||||
|
mock_create_parameters_env.side_effect = _custom_create_params_env
|
||||||
|
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
execution_calls = workflow_client.executions.create.call_args_list
|
||||||
|
deploy_plan_call = execution_calls[1]
|
||||||
|
deploy_plan_call_input = deploy_plan_call[1]['workflow_input']
|
||||||
|
self.assertTrue(deploy_plan_call_input['skip_deploy_identifier'])
|
||||||
|
|
||||||
@mock.patch('tripleoclient.workflows.plan_management.tarball',
|
@mock.patch('tripleoclient.workflows.plan_management.tarball',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch("heatclient.common.event_utils.get_events", autospec=True)
|
@mock.patch("heatclient.common.event_utils.get_events", autospec=True)
|
||||||
|
@ -445,7 +540,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||||
|
|
||||||
def _fake_heat_deploy(self, stack, stack_name, template_path,
|
def _fake_heat_deploy(self, stack, stack_name, template_path,
|
||||||
parameters, environments, timeout, tht_root,
|
parameters, environments, timeout, tht_root,
|
||||||
env, update_plan_only, run_validations):
|
env, update_plan_only, run_validations,
|
||||||
|
skip_deploy_identifier):
|
||||||
assertEqual(
|
assertEqual(
|
||||||
{'parameter_defaults': {},
|
{'parameter_defaults': {},
|
||||||
'resource_registry': {
|
'resource_registry': {
|
||||||
|
@ -506,7 +602,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||||
|
|
||||||
def _fake_heat_deploy(self, stack, stack_name, template_path,
|
def _fake_heat_deploy(self, stack, stack_name, template_path,
|
||||||
parameters, environments, timeout, tht_root,
|
parameters, environments, timeout, tht_root,
|
||||||
env, update_plan_only, run_validations):
|
env, update_plan_only, run_validations,
|
||||||
|
skip_deploy_identifier):
|
||||||
# Should be no breakpoint cleanup because utils.get_stack = None
|
# Should be no breakpoint cleanup because utils.get_stack = None
|
||||||
assertEqual(
|
assertEqual(
|
||||||
{'parameter_defaults': {},
|
{'parameter_defaults': {},
|
||||||
|
@ -741,13 +838,13 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||||
self, mock_heat_deploy_func):
|
self, mock_heat_deploy_func):
|
||||||
result = self.cmd._try_overcloud_deploy_with_compat_yaml(
|
result = self.cmd._try_overcloud_deploy_with_compat_yaml(
|
||||||
'/fake/path', {}, 'overcloud', {}, ['~/overcloud-env.json'], 1,
|
'/fake/path', {}, 'overcloud', {}, ['~/overcloud-env.json'], 1,
|
||||||
{}, False, True)
|
{}, False, True, False)
|
||||||
# If it returns None it succeeded
|
# If it returns None it succeeded
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
mock_heat_deploy_func.assert_called_once_with(
|
mock_heat_deploy_func.assert_called_once_with(
|
||||||
self.cmd, {}, 'overcloud',
|
self.cmd, {}, 'overcloud',
|
||||||
'/fake/path/' + constants.OVERCLOUD_YAML_NAME, {},
|
'/fake/path/' + constants.OVERCLOUD_YAML_NAME, {},
|
||||||
['~/overcloud-env.json'], 1, '/fake/path', {}, False, True)
|
['~/overcloud-env.json'], 1, '/fake/path', {}, False, True, False)
|
||||||
|
|
||||||
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
'_heat_deploy', autospec=True)
|
'_heat_deploy', autospec=True)
|
||||||
|
@ -757,7 +854,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||||
self.assertRaises(ValueError,
|
self.assertRaises(ValueError,
|
||||||
self.cmd._try_overcloud_deploy_with_compat_yaml,
|
self.cmd._try_overcloud_deploy_with_compat_yaml,
|
||||||
'/fake/path', mock.ANY, mock.ANY, mock.ANY,
|
'/fake/path', mock.ANY, mock.ANY, mock.ANY,
|
||||||
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY)
|
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
|
||||||
|
mock.ANY)
|
||||||
|
|
||||||
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
'_heat_deploy', autospec=True)
|
'_heat_deploy', autospec=True)
|
||||||
|
@ -768,7 +866,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||||
try:
|
try:
|
||||||
self.cmd._try_overcloud_deploy_with_compat_yaml(
|
self.cmd._try_overcloud_deploy_with_compat_yaml(
|
||||||
'/fake/path', mock.ANY, mock.ANY, mock.ANY,
|
'/fake/path', mock.ANY, mock.ANY, mock.ANY,
|
||||||
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY)
|
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY)
|
||||||
except ValueError as value_error:
|
except ValueError as value_error:
|
||||||
self.assertIn('/fake/path', str(value_error))
|
self.assertIn('/fake/path', str(value_error))
|
||||||
|
|
||||||
|
@ -1120,7 +1218,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||||
mock_get_template_contents.return_value = [{}, {}]
|
mock_get_template_contents.return_value = [{}, {}]
|
||||||
|
|
||||||
self.cmd._heat_deploy(mock_stack, 'mock_stack', '/tmp', {},
|
self.cmd._heat_deploy(mock_stack, 'mock_stack', '/tmp', {},
|
||||||
{}, 1, '/tmp', {}, True, False)
|
{}, 1, '/tmp', {}, True, False, False)
|
||||||
|
|
||||||
self.assertFalse(mock_deploy_and_wait.called)
|
self.assertFalse(mock_deploy_and_wait.called)
|
||||||
|
|
||||||
|
|
|
@ -356,6 +356,7 @@ class TestOvercloudDeployPlan(utils.TestCommand):
|
||||||
workflow_input={
|
workflow_input={
|
||||||
'container': 'overcast',
|
'container': 'overcast',
|
||||||
'run_validations': True,
|
'run_validations': True,
|
||||||
'queue_name': 'UUID4'
|
'queue_name': 'UUID4',
|
||||||
|
'skip_deploy_identifier': False
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,7 +23,6 @@ import re
|
||||||
import shutil
|
import shutil
|
||||||
import six
|
import six
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
|
||||||
import uuid
|
import uuid
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
@ -68,8 +67,6 @@ class DeployOvercloud(command.Command):
|
||||||
|
|
||||||
stack_is_new = stack is None
|
stack_is_new = stack is None
|
||||||
|
|
||||||
timestamp = int(time.time())
|
|
||||||
parameters['DeployIdentifier'] = timestamp
|
|
||||||
parameters['UpdateIdentifier'] = ''
|
parameters['UpdateIdentifier'] = ''
|
||||||
parameters['StackAction'] = 'CREATE' if stack_is_new else 'UPDATE'
|
parameters['StackAction'] = 'CREATE' if stack_is_new else 'UPDATE'
|
||||||
|
|
||||||
|
@ -199,7 +196,7 @@ class DeployOvercloud(command.Command):
|
||||||
|
|
||||||
def _heat_deploy(self, stack, stack_name, template_path, parameters,
|
def _heat_deploy(self, stack, stack_name, template_path, parameters,
|
||||||
env_files, timeout, tht_root, env, update_plan_only,
|
env_files, timeout, tht_root, env, update_plan_only,
|
||||||
run_validations):
|
run_validations, skip_deploy_identifier):
|
||||||
"""Verify the Baremetal nodes are available and do a stack update"""
|
"""Verify the Baremetal nodes are available and do a stack update"""
|
||||||
|
|
||||||
self.log.debug("Getting template contents from plan %s" % stack_name)
|
self.log.debug("Getting template contents from plan %s" % stack_name)
|
||||||
|
@ -227,10 +224,12 @@ class DeployOvercloud(command.Command):
|
||||||
stack_name, env, moved_files, tht_root)
|
stack_name, env, moved_files, tht_root)
|
||||||
|
|
||||||
if not update_plan_only:
|
if not update_plan_only:
|
||||||
deployment.deploy_and_wait(self.log, self.clients, stack,
|
deployment.deploy_and_wait(
|
||||||
stack_name, self.app_args.verbose_level,
|
self.log, self.clients, stack,
|
||||||
timeout=timeout,
|
stack_name, self.app_args.verbose_level,
|
||||||
run_validations=run_validations)
|
timeout=timeout,
|
||||||
|
run_validations=run_validations,
|
||||||
|
skip_deploy_identifier=skip_deploy_identifier)
|
||||||
|
|
||||||
def _load_environment_directories(self, directories):
|
def _load_environment_directories(self, directories):
|
||||||
if os.environ.get('TRIPLEO_ENVIRONMENT_DIRECTORY'):
|
if os.environ.get('TRIPLEO_ENVIRONMENT_DIRECTORY'):
|
||||||
|
@ -439,19 +438,20 @@ class DeployOvercloud(command.Command):
|
||||||
self._try_overcloud_deploy_with_compat_yaml(
|
self._try_overcloud_deploy_with_compat_yaml(
|
||||||
tht_root, stack, parsed_args.stack, parameters, env_files,
|
tht_root, stack, parsed_args.stack, parameters, env_files,
|
||||||
parsed_args.timeout, env, parsed_args.update_plan_only,
|
parsed_args.timeout, env, parsed_args.update_plan_only,
|
||||||
parsed_args.run_validations)
|
parsed_args.run_validations, parsed_args.skip_deploy_identifier)
|
||||||
|
|
||||||
def _try_overcloud_deploy_with_compat_yaml(self, tht_root, stack,
|
def _try_overcloud_deploy_with_compat_yaml(self, tht_root, stack,
|
||||||
stack_name, parameters,
|
stack_name, parameters,
|
||||||
env_files, timeout,
|
env_files, timeout,
|
||||||
env, update_plan_only,
|
env, update_plan_only,
|
||||||
run_validations):
|
run_validations,
|
||||||
|
skip_deploy_identifier):
|
||||||
overcloud_yaml = os.path.join(tht_root, constants.OVERCLOUD_YAML_NAME)
|
overcloud_yaml = os.path.join(tht_root, constants.OVERCLOUD_YAML_NAME)
|
||||||
try:
|
try:
|
||||||
self._heat_deploy(stack, stack_name, overcloud_yaml,
|
self._heat_deploy(stack, stack_name, overcloud_yaml,
|
||||||
parameters, env_files, timeout,
|
parameters, env_files, timeout,
|
||||||
tht_root, env, update_plan_only,
|
tht_root, env, update_plan_only,
|
||||||
run_validations)
|
run_validations, skip_deploy_identifier)
|
||||||
except ClientException as e:
|
except ClientException as e:
|
||||||
messages = 'Failed to deploy: %s' % str(e)
|
messages = 'Failed to deploy: %s' % str(e)
|
||||||
raise ValueError(messages)
|
raise ValueError(messages)
|
||||||
|
@ -743,6 +743,18 @@ class DeployOvercloud(command.Command):
|
||||||
default=False,
|
default=False,
|
||||||
help=_('Force the overcloud post-deployment configuration.')
|
help=_('Force the overcloud post-deployment configuration.')
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--skip-deploy-identifier',
|
||||||
|
action='store_true',
|
||||||
|
default=False,
|
||||||
|
help=_('Skip generation of a unique identifier for the '
|
||||||
|
'DeployIdentifier parameter. The software configuration '
|
||||||
|
'deployment steps will only be triggered if there is an '
|
||||||
|
'actual change to the configuration. This option should '
|
||||||
|
'be used with Caution, and only if there is confidence '
|
||||||
|
'that the software configuration does not need to be '
|
||||||
|
'run, such as when scaling out certain roles.')
|
||||||
|
)
|
||||||
reg_group = parser.add_argument_group('Registration Parameters')
|
reg_group = parser.add_argument_group('Registration Parameters')
|
||||||
reg_group.add_argument(
|
reg_group.add_argument(
|
||||||
'--rhel-reg',
|
'--rhel-reg',
|
||||||
|
|
|
@ -46,12 +46,14 @@ def deploy(clients, **workflow_input):
|
||||||
|
|
||||||
|
|
||||||
def deploy_and_wait(log, clients, stack, plan_name, verbose_level,
|
def deploy_and_wait(log, clients, stack, plan_name, verbose_level,
|
||||||
timeout=None, run_validations=False):
|
timeout=None, run_validations=False,
|
||||||
|
skip_deploy_identifier=False):
|
||||||
"""Start the deploy and wait for it to finish"""
|
"""Start the deploy and wait for it to finish"""
|
||||||
|
|
||||||
workflow_input = {
|
workflow_input = {
|
||||||
"container": plan_name,
|
"container": plan_name,
|
||||||
"run_validations": run_validations,
|
"run_validations": run_validations,
|
||||||
|
"skip_deploy_identifier": skip_deploy_identifier,
|
||||||
"queue_name": str(uuid.uuid4()),
|
"queue_name": str(uuid.uuid4()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue