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,
:xa
git

as that is now handled by the tripleo-common action.

Depends-On: Idb901a841846fec33d189b3c95f669b0380498ce
Change-Id: I294eabe84e070367981534030b5927062f00c628
Closes-Bug: #1688387
(cherry picked from commit f3acb69ffc)
(cherry picked from commit 1b877698ce)
This commit is contained in:
James Slagle 2017-03-31 10:24:32 -04:00
parent a93e6d1a15
commit d98fff454b
5 changed files with 154 additions and 18 deletions

View File

@ -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.

View File

@ -404,6 +404,112 @@ 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.'
'process_environment_and_files', autospec=True)
@mock.patch('heatclient.common.template_utils.get_template_contents',
autospec=True)
@mock.patch('tripleoclient.utils.check_hypervisor_stats',
autospec=True)
@mock.patch('os_cloud_config.keystone_pki.generate_certs_into_json',
autospec=True)
@mock.patch('tripleoclient.utils.create_environment_file',
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_environment_file,
mock_generate_certs,
mock_check_hypervisor_stats,
mock_get_template_contents,
mock_process_env,
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
mock_env = fakes.create_env()
mock_process_env.return_value = [{}, mock_env]
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)
@ -566,7 +672,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
def _fake_heat_deploy(self, stack, stack_name, template_path,
parameters, environments, timeout, tht_root,
env, update_plan_only):
env, update_plan_only,
skip_deploy_identifier):
assertEqual(
{'parameter_defaults': {},
'resource_registry': {'Test': u'OS::Heat::None'}}, env)
@ -620,7 +727,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
def _fake_heat_deploy(self, stack, stack_name, template_path,
parameters, environments, timeout, tht_root,
env, update_plan_only):
env, update_plan_only,
skip_deploy_identifier):
assertEqual(
{'parameter_defaults': {},
'resource_registry': {'Test': u'OS::Heat::None'}}, env)
@ -966,13 +1074,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)
{}, False, 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)
['~/overcloud-env.json'], 1, '/fake/path', {}, False, False)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_heat_deploy', autospec=True)
@ -982,7 +1090,7 @@ 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.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_heat_deploy', autospec=True)
@ -993,7 +1101,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)
except ValueError as value_error:
self.assertIn('/fake/path', str(value_error))
@ -1504,7 +1612,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_get_template_contents.return_value = [{}, {}]
self.cmd._heat_deploy(mock_stack, 'mock_stack', '/tmp', {},
{}, 1, '/tmp', {}, True)
{}, 1, '/tmp', {}, True, False)
self.assertFalse(mock_deploy_and_wait.called)

View File

@ -278,6 +278,7 @@ class TestOvercloudDeployPlan(utils.TestCommand):
'tripleo.deployment.v1.deploy_plan',
workflow_input={
'container': 'overcast',
'queue_name': 'UUID4'
'queue_name': 'UUID4',
'skip_deploy_identifier': False
}
)

View File

@ -23,7 +23,6 @@ import re
import shutil
import six
import tempfile
import time
import yaml
from heatclient.common import template_utils
@ -59,8 +58,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'
@ -202,7 +199,8 @@ class DeployOvercloud(command.Command):
return env_files, localenv
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,
skip_deploy_identifier):
"""Verify the Baremetal nodes are available and do a stack update"""
clients = self.app.client_manager
@ -249,8 +247,11 @@ class DeployOvercloud(command.Command):
workflow_client)
if not update_plan_only:
deployment.deploy_and_wait(self.log, clients, stack, stack_name,
self.app_args.verbose_level, timeout)
deployment.deploy_and_wait(
self.log, clients, stack, stack_name,
self.app_args.verbose_level,
timeout=timeout,
skip_deploy_identifier=skip_deploy_identifier)
def _load_environment_directories(self, directories):
if os.environ.get('TRIPLEO_ENVIRONMENT_DIRECTORY'):
@ -462,17 +463,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.timeout, env, parsed_args.update_plan_only,
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):
env, update_plan_only,
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)
tht_root, env, update_plan_only,
skip_deploy_identifier)
except ClientException as e:
messages = 'Failed to deploy: %s' % str(e)
raise ValueError(messages)
@ -1072,6 +1076,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',

View File

@ -41,11 +41,12 @@ def deploy(clients, **workflow_input):
def deploy_and_wait(log, clients, stack, plan_name, verbose_level,
timeout=None):
timeout=None, skip_deploy_identifier=False):
"""Start the deploy and wait for it to finish"""
workflow_input = {
"container": plan_name,
"skip_deploy_identifier": skip_deploy_identifier,
"queue_name": str(uuid.uuid4()),
}