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(
|
||||
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',
|
||||
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,
|
||||
parameters, environments, timeout, tht_root,
|
||||
env, update_plan_only, run_validations):
|
||||
env, update_plan_only, run_validations,
|
||||
skip_deploy_identifier):
|
||||
assertEqual(
|
||||
{'parameter_defaults': {},
|
||||
'resource_registry': {
|
||||
@ -506,7 +602,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
|
||||
def _fake_heat_deploy(self, stack, stack_name, template_path,
|
||||
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
|
||||
assertEqual(
|
||||
{'parameter_defaults': {},
|
||||
@ -741,13 +838,13 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
self, mock_heat_deploy_func):
|
||||
result = self.cmd._try_overcloud_deploy_with_compat_yaml(
|
||||
'/fake/path', {}, 'overcloud', {}, ['~/overcloud-env.json'], 1,
|
||||
{}, False, True)
|
||||
{}, False, True, False)
|
||||
# If it returns None it succeeded
|
||||
self.assertIsNone(result)
|
||||
mock_heat_deploy_func.assert_called_once_with(
|
||||
self.cmd, {}, 'overcloud',
|
||||
'/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.'
|
||||
'_heat_deploy', autospec=True)
|
||||
@ -757,7 +854,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
self.assertRaises(ValueError,
|
||||
self.cmd._try_overcloud_deploy_with_compat_yaml,
|
||||
'/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.'
|
||||
'_heat_deploy', autospec=True)
|
||||
@ -768,7 +866,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
try:
|
||||
self.cmd._try_overcloud_deploy_with_compat_yaml(
|
||||
'/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:
|
||||
self.assertIn('/fake/path', str(value_error))
|
||||
|
||||
@ -1120,7 +1218,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
mock_get_template_contents.return_value = [{}, {}]
|
||||
|
||||
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)
|
||||
|
||||
|
@ -356,6 +356,7 @@ class TestOvercloudDeployPlan(utils.TestCommand):
|
||||
workflow_input={
|
||||
'container': 'overcast',
|
||||
'run_validations': True,
|
||||
'queue_name': 'UUID4'
|
||||
'queue_name': 'UUID4',
|
||||
'skip_deploy_identifier': False
|
||||
}
|
||||
)
|
||||
|
@ -23,7 +23,6 @@ import re
|
||||
import shutil
|
||||
import six
|
||||
import tempfile
|
||||
import time
|
||||
import uuid
|
||||
import yaml
|
||||
|
||||
@ -68,8 +67,6 @@ class DeployOvercloud(command.Command):
|
||||
|
||||
stack_is_new = stack is None
|
||||
|
||||
timestamp = int(time.time())
|
||||
parameters['DeployIdentifier'] = timestamp
|
||||
parameters['UpdateIdentifier'] = ''
|
||||
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,
|
||||
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"""
|
||||
|
||||
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)
|
||||
|
||||
if not update_plan_only:
|
||||
deployment.deploy_and_wait(self.log, self.clients, stack,
|
||||
stack_name, self.app_args.verbose_level,
|
||||
timeout=timeout,
|
||||
run_validations=run_validations)
|
||||
deployment.deploy_and_wait(
|
||||
self.log, self.clients, stack,
|
||||
stack_name, self.app_args.verbose_level,
|
||||
timeout=timeout,
|
||||
run_validations=run_validations,
|
||||
skip_deploy_identifier=skip_deploy_identifier)
|
||||
|
||||
def _load_environment_directories(self, directories):
|
||||
if os.environ.get('TRIPLEO_ENVIRONMENT_DIRECTORY'):
|
||||
@ -439,19 +438,20 @@ class DeployOvercloud(command.Command):
|
||||
self._try_overcloud_deploy_with_compat_yaml(
|
||||
tht_root, stack, parsed_args.stack, parameters, env_files,
|
||||
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,
|
||||
stack_name, parameters,
|
||||
env_files, timeout,
|
||||
env, update_plan_only,
|
||||
run_validations):
|
||||
run_validations,
|
||||
skip_deploy_identifier):
|
||||
overcloud_yaml = os.path.join(tht_root, constants.OVERCLOUD_YAML_NAME)
|
||||
try:
|
||||
self._heat_deploy(stack, stack_name, overcloud_yaml,
|
||||
parameters, env_files, timeout,
|
||||
tht_root, env, update_plan_only,
|
||||
run_validations)
|
||||
run_validations, skip_deploy_identifier)
|
||||
except ClientException as e:
|
||||
messages = 'Failed to deploy: %s' % str(e)
|
||||
raise ValueError(messages)
|
||||
@ -743,6 +743,18 @@ class DeployOvercloud(command.Command):
|
||||
default=False,
|
||||
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.add_argument(
|
||||
'--rhel-reg',
|
||||
|
@ -46,12 +46,14 @@ def deploy(clients, **workflow_input):
|
||||
|
||||
|
||||
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"""
|
||||
|
||||
workflow_input = {
|
||||
"container": plan_name,
|
||||
"run_validations": run_validations,
|
||||
"skip_deploy_identifier": skip_deploy_identifier,
|
||||
"queue_name": str(uuid.uuid4()),
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user