diff --git a/releasenotes/notes/skip-deploy-identifier-d5abb0d4e6af0ecd.yaml b/releasenotes/notes/skip-deploy-identifier-d5abb0d4e6af0ecd.yaml new file mode 100644 index 000000000..f80315d7f --- /dev/null +++ b/releasenotes/notes/skip-deploy-identifier-d5abb0d4e6af0ecd.yaml @@ -0,0 +1,10 @@ +--- +features: + - Add a new action argument, skip_deploy_identifier to DeployStackAction. 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. diff --git a/tripleo_common/actions/deployment.py b/tripleo_common/actions/deployment.py index ba81938ff..ef00be7c6 100644 --- a/tripleo_common/actions/deployment.py +++ b/tripleo_common/actions/deployment.py @@ -128,9 +128,11 @@ class OrchestrationDeployAction(base.TripleOAction): class DeployStackAction(templates.ProcessTemplatesAction): """Deploys a heat stack.""" - def __init__(self, timeout, container=constants.DEFAULT_CONTAINER_NAME): + def __init__(self, timeout, container=constants.DEFAULT_CONTAINER_NAME, + skip_deploy_identifier=False): super(DeployStackAction, self).__init__(container) self.timeout_mins = timeout + self.skip_deploy_identifier = skip_deploy_identifier def run(self): # check to see if the stack exists @@ -147,7 +149,8 @@ class DeployStackAction(templates.ProcessTemplatesAction): wf_env = wc.environments.get(self.container) parameters = dict() - parameters['DeployIdentifier'] = int(time.time()) + if not self.skip_deploy_identifier: + parameters['DeployIdentifier'] = int(time.time()) parameters['UpdateIdentifier'] = '' parameters['StackAction'] = 'CREATE' if stack_is_new else 'UPDATE' diff --git a/tripleo_common/tests/actions/test_deployment.py b/tripleo_common/tests/actions/test_deployment.py index 5a3279316..81cb53158 100644 --- a/tripleo_common/tests/actions/test_deployment.py +++ b/tripleo_common/tests/actions/test_deployment.py @@ -266,6 +266,77 @@ class DeployStackActionTest(base.TestCase): "overcloud-swift-rings", "swift-rings.tar.gz", "overcloud-swift-rings/swift-rings.tar.gz-%d" % 1473366264) + @mock.patch('tripleo_common.actions.deployment.time') + @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_workflow_client') + @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client') + @mock.patch( + 'tripleo_common.actions.base.TripleOAction.get_orchestration_client') + @mock.patch('mistral.context.ctx') + def test_run_skip_deploy_identifier( + self, mock_ctx, get_orchestration_client_mock, + mock_get_object_client, mock_get_workflow_client, + mock_get_template_contents, + mock_process_multiple_environments_and_files, + mock_time): + + mock_ctx.return_value = mock.MagicMock() + # setup swift + swift = mock.MagicMock(url="http://test.com") + swift.get_object.side_effect = swiftexceptions.ClientException( + 'atest2') + mock_get_object_client.return_value = swift + + heat = mock.MagicMock() + heat.stacks.get.return_value = None + get_orchestration_client_mock.return_value = heat + + mock_mistral = mock.MagicMock() + mock_env = mock.MagicMock() + mock_env.variables = { + 'temp_environment': 'temp_environment', + 'template': 'template', + 'environments': [{u'path': u'environments/test.yaml'}], + 'parameter_defaults': {'random_existing_data': 'a_value'}, + } + mock_mistral.environments.get.return_value = mock_env + mock_get_workflow_client.return_value = mock_mistral + + mock_get_template_contents.return_value = ({}, { + 'heat_template_version': '2016-04-30' + }) + mock_process_multiple_environments_and_files.return_value = ({}, {}) + + # freeze time at datetime.datetime(2016, 9, 8, 16, 24, 24) + mock_time.time.return_value = 1473366264 + + action = deployment.DeployStackAction(1, 'overcloud', + skip_deploy_identifier=True) + action.run() + + # verify parameters are as expected + expected_defaults = {'StackAction': 'CREATE', + 'UpdateIdentifier': '', + 'random_existing_data': 'a_value'} + self.assertEqual(expected_defaults, + mock_env.variables['parameter_defaults']) + + heat.stacks.create.assert_called_once_with( + environment={}, + files={}, + stack_name='overcloud', + template={'heat_template_version': '2016-04-30'}, + timeout_mins=1, + ) + swift.delete_object.assert_called_once_with( + "overcloud-swift-rings", "swift-rings.tar.gz") + swift.copy_object.assert_called_once_with( + "overcloud-swift-rings", "swift-rings.tar.gz", + "overcloud-swift-rings/swift-rings.tar.gz-%d" % 1473366264) + class OvercloudRcActionTestCase(base.TestCase): diff --git a/workbooks/deployment.yaml b/workbooks/deployment.yaml index 5ca89cf28..2c34cf093 100644 --- a/workbooks/deployment.yaml +++ b/workbooks/deployment.yaml @@ -110,6 +110,7 @@ workflows: - container - run_validations: False - timeout: 240 + - skip_deploy_identifier: False - queue_name: tripleo tasks: @@ -197,6 +198,7 @@ workflows: input: timeout: <% $.timeout %> container: <% $.container %> + skip_deploy_identifier: <% $.skip_deploy_identifier %> on-success: send_message on-error: set_deployment_failed