def test_wait_for_stack_in_progress(self, sleep_mock, mock_el):

        mock_el.side_effect = [[
            self.mock_event('stack', 'aaa', 'Stack CREATE started',
                            'CREATE_IN_PROGRESS', '2015-10-14T02:25:21Z'),
            self.mock_event('thing', 'bbb', 'state changed',
                            'CREATE_IN_PROGRESS', '2015-10-14T02:25:21Z'),
        ], [
            self.mock_event('thing', 'ccc', 'state changed',
                            'CREATE_COMPLETE', '2015-10-14T02:25:43Z'),
            self.mock_event('stack', 'ddd',
                            'Stack CREATE completed successfully',
                            'CREATE_COMPLETE', '2015-10-14T02:25:43Z'),
        ], [], []]

        stack = mock.Mock()
        stack.stack_name = 'stack'
        stack.stack_status = 'CREATE_IN_PROGRESS'
        complete_stack = mock.Mock()
        complete_stack.stack_name = 'stack'
        complete_stack.stack_status = 'CREATE_COMPLETE'
        self.mock_orchestration.stacks.get.side_effect = [
            stack, stack, stack, complete_stack]

        utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertEqual(2, sleep_mock.call_count)
    def test_wait_for_stack_in_progress(self, sleep_mock, mock_el):

        mock_el.side_effect = [
            [
                self.mock_event('stack', 'aaa', 'Stack CREATE started',
                                'CREATE_IN_PROGRESS', '2015-10-14T02:25:21Z'),
                self.mock_event('thing', 'bbb', 'state changed',
                                'CREATE_IN_PROGRESS', '2015-10-14T02:25:21Z'),
            ],
            [
                self.mock_event('thing', 'ccc', 'state changed',
                                'CREATE_COMPLETE', '2015-10-14T02:25:43Z'),
                self.mock_event('stack', 'ddd',
                                'Stack CREATE completed successfully',
                                'CREATE_COMPLETE', '2015-10-14T02:25:43Z'),
            ], [], []
        ]

        stack = mock.Mock()
        stack.stack_name = 'stack'
        stack.stack_status = 'CREATE_IN_PROGRESS'
        complete_stack = mock.Mock()
        complete_stack.stack_name = 'stack'
        complete_stack.stack_status = 'CREATE_COMPLETE'
        self.mock_orchestration.stacks.get.side_effect = [
            stack, stack, stack, complete_stack
        ]

        utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertEqual(2, sleep_mock.call_count)
    def _heat_deploy(self, stack_name, template_path, parameters,
                     environments, timeout):
        """Verify the Baremetal nodes are available and do a stack update"""

        clients = self.app.client_manager
        orchestration_client = clients.tripleoclient.orchestration
        deploy_manager = deploy.FileDeployManager(
            orchestration_client, stack_name)

        deploy_args = {
            'template_path': template_path,
            'environment_files': environments,
            'parameters': parameters,
        }

        if timeout:
            deploy_args['timeout_mins'] = timeout

        deploy_manager.deploy(**deploy_args)

        create_result = utils.wait_for_stack_ready(
            orchestration_client, stack_name)
        if not create_result:
            if stack is None:
                raise exceptions.DeploymentError("Heat Stack create failed.")
            else:
                raise exceptions.DeploymentError("Heat Stack update failed.")
Exemple #4
0
def update(clients, **workflow_input):
    workflow_client = clients.workflow_engine
    tripleoclients = clients.tripleoclient
    plan_name = workflow_input['container']

    with tripleoclients.messaging_websocket() as ws:
        execution = base.start_workflow(
            workflow_client,
            'tripleo.package_update.v1.package_update_plan',
            workflow_input=workflow_input)

        for payload in base.wait_for_messages(workflow_client, ws, execution):
            assert payload['status'] == "SUCCESS", pprint.pformat(payload)

    orchestration_client = clients.orchestration

    events = event_utils.get_events(orchestration_client,
                                    stack_id=plan_name,
                                    event_args={
                                        'sort_dir': 'desc',
                                        'limit': 1
                                    })
    marker = events[0].id if events else None

    time.sleep(10)
    create_result = utils.wait_for_stack_ready(orchestration_client, plan_name,
                                               marker, 'UPDATE', 1)
    if not create_result:
        shell.OpenStackShell().run(["stack", "failures", "list", plan_name])
        raise exceptions.DeploymentError("Heat Stack update failed.")
Exemple #5
0
def deploy_and_wait(log,
                    clients,
                    stack,
                    plan_name,
                    verbose_level,
                    timeout=None,
                    run_validations=False,
                    skip_deploy_identifier=False,
                    deployment_options={}):
    """Start the deploy and wait for it to finish"""

    orchestration_client = clients.orchestration

    if stack is None:
        log.info("Performing Heat stack create")
        action = 'CREATE'
        marker = None
    else:
        log.info("Performing Heat stack update")
        # Make sure existing parameters for stack are reused
        # Find the last top-level event to use for the first marker
        events = event_utils.get_events(orchestration_client,
                                        stack_id=plan_name,
                                        event_args={
                                            'sort_dir': 'desc',
                                            'limit': 1
                                        })
        marker = events[0].id if events else None
        action = 'UPDATE'

    set_deployment_status(clients=clients, plan=plan_name, status='DEPLOYING')

    try:
        deploy(container=plan_name,
               run_validations=run_validations,
               skip_deploy_identifier=skip_deploy_identifier,
               timeout=timeout,
               verbosity=verbose_level)
    except Exception:
        set_deployment_status(clients=clients,
                              plan=plan_name,
                              status='DEPLOY_FAILED')
        raise

    # we always want the heat stack output while it's going.
    verbose_events = True

    # TODO(rabi) Simplify call to get events as we don't need to wait
    # for stack to be ready anymore i.e just get the events.
    create_result = utils.wait_for_stack_ready(orchestration_client, plan_name,
                                               marker, action, verbose_events)
    if not create_result:
        shell.OpenStackShell().run(["stack", "failures", "list", plan_name])
        set_deployment_status(clients=clients,
                              plan=plan_name,
                              status='DEPLOY_FAILED')
        if stack is None:
            raise exceptions.DeploymentError("Heat Stack create failed.")
        else:
            raise exceptions.DeploymentError("Heat Stack update failed.")
Exemple #6
0
    def test_wait_for_stack_ready(self, sleep_mock, mock_el):
        stack = mock.Mock()
        stack.stack_name = 'stack'
        self.mock_orchestration.stacks.get.return_value = stack

        mock_el.side_effect = [
            [
                self.mock_event('stack', 'aaa', 'Stack CREATE started',
                                'CREATE_IN_PROGRESS', '2015-10-14T02:25:21Z'),
                self.mock_event('thing', 'bbb', 'state changed',
                                'CREATE_IN_PROGRESS', '2015-10-14T02:25:21Z'),
            ],
            [
                self.mock_event('thing', 'ccc', 'state changed',
                                'CREATE_COMPLETE', '2015-10-14T02:25:43Z'),
                self.mock_event('stack', 'ddd',
                                'Stack CREATE completed successfully',
                                'CREATE_COMPLETE', '2015-10-14T02:25:43Z'),
            ]
        ]

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertTrue(complete)

        sleep_mock.assert_called_once_with(mock.ANY)
    def test_wait_for_stack_ready(self, mock_el):
        stack = mock.Mock()
        stack.stack_name = 'stack'
        stack.stack_status = "CREATE_COMPLETE"
        self.mock_orchestration.stacks.get.return_value = stack

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')
        self.assertTrue(complete)
    def test_wait_for_stack_ready(self, mock_el):
        stack = mock.Mock()
        stack.stack_name = 'stack'
        stack.stack_status = "CREATE_COMPLETE"
        self.mock_orchestration.stacks.get.return_value = stack

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')
        self.assertTrue(complete)
    def test_wait_for_stack_ready_failed(self, mock_el):
        stack = mock.Mock()
        stack.stack_name = 'stack'
        stack.stack_status = "CREATE_FAILED"
        self.mock_orchestration.stacks.get.return_value = stack

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertFalse(complete)
 def _stack_delete(self, orchestration_client, stack_name):
     print("Deleting stack {s}...".format(s=stack_name))
     stack = utils.get_stack(orchestration_client, stack_name)
     if stack is None:
         self.log.warning("No stack found ('{s}'), skipping delete".
                          format(s=stack_name))
     else:
         try:
             utils.wait_for_stack_ready(
                 orchestration_client=orchestration_client,
                 stack_name=stack_name,
                 action='DELETE')
         except Exception as e:
             self.log.error("Exception while waiting for stack to delete "
                            "{}".format(e))
             raise oscexc.CommandError(
                 "Error occurred while waiting for stack to delete {}".
                 format(e))
    def test_wait_for_stack_ready_failed(self, mock_el):
        stack = mock.Mock()
        stack.stack_name = 'stack'
        stack.stack_status = "CREATE_FAILED"
        self.mock_orchestration.stacks.get.return_value = stack

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertFalse(complete)
    def test_wait_for_stack_ready_no_stack(self):
        self.mock_orchestration.reset_mock()

        self.mock_orchestration.stacks.get.return_value = None

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.mock_orchestration.stacks.get.return_value = self.mock_stacks

        self.assertFalse(complete)
    def test_wait_for_stack_in_progress(self, mock_poll_for_events):

        mock_poll_for_events.return_value = ("CREATE_IN_PROGRESS", "MESSAGE")

        stack = mock.Mock()
        stack.stack_name = 'stack'
        stack.stack_status = 'CREATE_IN_PROGRESS'
        self.mock_orchestration.stacks.get.return_value = stack

        result = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')
        self.assertEqual(False, result)
    def test_wait_for_stack_in_progress(self, mock_poll_for_events):

        mock_poll_for_events.return_value = ("CREATE_IN_PROGRESS", "MESSAGE")

        stack = mock.Mock()
        stack.stack_name = 'stack'
        stack.stack_status = 'CREATE_IN_PROGRESS'
        self.mock_orchestration.stacks.get.return_value = stack

        result = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')
        self.assertEqual(False, result)
    def test_wait_for_stack_ready_failed(self):
        self.mock_orchestration.reset_mock()
        self.mock_stacks.reset_mock()

        return_values = ['CREATE_FAILED']

        self.stack_status.side_effect = return_values

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertFalse(complete)
def deploy_and_wait(log,
                    clients,
                    stack,
                    plan_name,
                    verbose_level,
                    timeout=None,
                    run_validations=False,
                    skip_deploy_identifier=False,
                    deployment_options={}):
    """Start the deploy and wait for it to finish"""

    workflow_input = {
        "container": plan_name,
        "run_validations": run_validations,
        "skip_deploy_identifier": skip_deploy_identifier,
        "deployment_options": deployment_options,
    }

    if timeout is not None:
        workflow_input['timeout'] = timeout

    deploy(log, clients, **workflow_input)

    orchestration_client = clients.orchestration

    if stack is None:
        log.info("Performing Heat stack create")
        action = 'CREATE'
        marker = None
    else:
        log.info("Performing Heat stack update")
        # Make sure existing parameters for stack are reused
        # Find the last top-level event to use for the first marker
        events = event_utils.get_events(orchestration_client,
                                        stack_id=plan_name,
                                        event_args={
                                            'sort_dir': 'desc',
                                            'limit': 1
                                        })
        marker = events[0].id if events else None
        action = 'UPDATE'

    time.sleep(10)
    verbose_events = verbose_level >= 1
    create_result = utils.wait_for_stack_ready(orchestration_client, plan_name,
                                               marker, action, verbose_events)
    if not create_result:
        shell.OpenStackShell().run(["stack", "failures", "list", plan_name])
        set_deployment_status(clients, 'failed', plan=plan_name)
        if stack is None:
            raise exceptions.DeploymentError("Heat Stack create failed.")
        else:
            raise exceptions.DeploymentError("Heat Stack update failed.")
    def _heat_deploy(self, stack, stack_name, template_path, parameters,
                     environments, timeout):
        """Verify the Baremetal nodes are available and do a stack update"""

        self.log.debug("Processing environment files")
        env_files, env = (
            template_utils.process_multiple_environments_and_files(
                environments))
        if stack:
            update.add_breakpoints_cleanup_into_env(env)

        self.log.debug("Getting template contents")
        template_files, template = template_utils.get_template_contents(
            template_path)

        files = dict(list(template_files.items()) + list(env_files.items()))

        clients = self.app.client_manager
        orchestration_client = clients.tripleoclient.orchestration()

        self.log.debug("Deploying stack: %s", stack_name)
        self.log.debug("Deploying template: %s", template)
        self.log.debug("Deploying parameters: %s", parameters)
        self.log.debug("Deploying environment: %s", env)
        self.log.debug("Deploying files: %s", files)

        stack_args = {
            'stack_name': stack_name,
            'template': template,
            'environment': env,
            'files': files
        }

        if timeout:
            stack_args['timeout_mins'] = timeout

        if stack is None:
            self.log.info("Performing Heat stack create")
            orchestration_client.stacks.create(**stack_args)
        else:
            self.log.info("Performing Heat stack update")
            # Make sure existing parameters for stack are reused
            stack_args['existing'] = 'true'
            orchestration_client.stacks.update(stack.id, **stack_args)

        create_result = utils.wait_for_stack_ready(
            orchestration_client, stack_name)
        if not create_result:
            if stack is None:
                raise Exception("Heat Stack create failed.")
            else:
                raise Exception("Heat Stack update failed.")
    def test_wait_for_stack_ready(self, sleep_mock):
        self.mock_orchestration.reset_mock()
        self.mock_stacks.reset_mock()

        return_values = ['CREATE_IN_PROGRESS', 'CREATE_COMPLETE']

        self.stack_status.side_effect = return_values

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertTrue(complete)

        sleep_mock.assert_called_once_with(mock.ANY)
def deploy_and_wait(log,
                    clients,
                    stack,
                    plan_name,
                    verbose_level,
                    timeout=None):
    """Start the deploy and wait for it to finish"""

    workflow_input = {
        "container": plan_name,
        "queue_name": str(uuid.uuid4()),
    }

    if timeout is not None:
        workflow_input['timeout'] = timeout

    deploy(clients, **workflow_input)

    orchestration_client = clients.orchestration

    if stack is None:
        log.info("Performing Heat stack create")
        action = 'CREATE'
        marker = None
    else:
        log.info("Performing Heat stack update")
        # Make sure existing parameters for stack are reused
        # Find the last top-level event to use for the first marker
        events = event_utils.get_events(orchestration_client,
                                        stack_id=plan_name,
                                        event_args={
                                            'sort_dir': 'desc',
                                            'limit': 1
                                        })
        marker = events[0].id if events else None
        action = 'UPDATE'

    time.sleep(10)
    verbose_events = verbose_level > 0
    create_result = utils.wait_for_stack_ready(orchestration_client, plan_name,
                                               marker, action, verbose_events)
    if not create_result:
        if stack is None:
            raise exceptions.DeploymentError("Heat Stack create failed.")
        else:
            raise exceptions.DeploymentError("Heat Stack update failed.")
def update(clients, container):
    """Update the heat stack outputs for purposes of update/upgrade.

    This workflow assumes that previously the
    plan_management.update_deployment_plan workflow has already been
    run to process the templates and environments (the same way as
    'deploy' command processes them).

    :param clients: Application client object.
    :type clients: Object

    :param container: Container name to pull from.
    :type container: String.
    """

    tripleoclients = clients.tripleoclient

    orchestration_client = clients.orchestration
    object_client = tripleoclients.object_store
    plan.update_plan_environment_with_image_parameters(
       object_client, container)
    stack.stack_update(object_client, orchestration_client,
                       _STACK_TIMEOUT, container)

    events = event_utils.get_events(orchestration_client,
                                    stack_id=container,
                                    event_args={'sort_dir': 'desc',
                                                'limit': 1})
    marker = events[0].id if events else None
    time.sleep(10)
    create_result = utils.wait_for_stack_ready(
        clients.orchestration,
        container,
        marker,
        'UPDATE',
        verbose=True
    )
    if not create_result:
        raise exceptions.DeploymentError(
            'Heat Stack update failed, run the following command'
            ' `openstack --os-cloud undercloud stack failures list {}`'
            ' to investigate these failures further.'.format(container)
        )
    def test_wait_for_stack_ready_failed(self, sleep_mock, mock_el):
        stack = mock.Mock()
        stack.stack_name = "stack"
        self.mock_orchestration.stacks.get.return_value = stack
        mock_el.side_effect = [
            [
                self.mock_event("stack", "aaa", "Stack CREATE started", "CREATE_IN_PROGRESS", "2015-10-14T02:25:21Z"),
                self.mock_event("thing", "bbb", "state changed", "CREATE_IN_PROGRESS", "2015-10-14T02:25:21Z"),
            ],
            [
                self.mock_event("thing", "ccc", "ouch", "CREATE_FAILED", "2015-10-14T02:25:43Z"),
                self.mock_event("stack", "ddd", "ouch", "CREATE_FAILED", "2015-10-14T02:25:43Z"),
            ],
        ]

        complete = utils.wait_for_stack_ready(self.mock_orchestration, "stack", verbose=True)

        self.assertFalse(complete)

        sleep_mock.assert_called_once_with(mock.ANY)
    def test_wait_for_stack_ready_failed(self, sleep_mock, mock_el):
        stack = mock.Mock()
        stack.stack_name = 'stack'
        self.mock_orchestration.stacks.get.return_value = stack
        mock_el.side_effect = [[
            self.mock_event('stack', 'aaa', 'Stack CREATE started',
                            'CREATE_IN_PROGRESS', '2015-10-14T02:25:21Z'),
            self.mock_event('thing', 'bbb', 'state changed',
                            'CREATE_IN_PROGRESS', '2015-10-14T02:25:21Z'),
        ], [
            self.mock_event('thing', 'ccc', 'ouch',
                            'CREATE_FAILED', '2015-10-14T02:25:43Z'),
            self.mock_event('stack', 'ddd', 'ouch',
                            'CREATE_FAILED', '2015-10-14T02:25:43Z'),
        ]]

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertFalse(complete)

        sleep_mock.assert_called_once_with(mock.ANY)
def deploy_and_wait(log, clients, stack, plan_name, verbose_level,
                    timeout=None):
    """Start the deploy and wait for it to finish"""

    workflow_input = {
        "container": plan_name,
        "queue_name": str(uuid.uuid4()),
    }

    if timeout is not None:
        workflow_input['timeout'] = timeout

    deploy(clients, **workflow_input)

    orchestration_client = clients.orchestration

    if stack is None:
        log.info("Performing Heat stack create")
        action = 'CREATE'
        marker = None
    else:
        log.info("Performing Heat stack update")
        # Make sure existing parameters for stack are reused
        # Find the last top-level event to use for the first marker
        events = event_utils.get_events(orchestration_client,
                                        stack_id=plan_name,
                                        event_args={'sort_dir': 'desc',
                                                    'limit': 1})
        marker = events[0].id if events else None
        action = 'UPDATE'

    time.sleep(10)
    verbose_events = verbose_level > 0
    create_result = utils.wait_for_stack_ready(
        orchestration_client, plan_name, marker, action, verbose_events)
    if not create_result:
        if stack is None:
            raise exceptions.DeploymentError("Heat Stack create failed.")
        else:
            raise exceptions.DeploymentError("Heat Stack update failed.")
    def test_wait_for_stack_ready_no_stack(self):
        self.mock_orchestration.stacks.get.return_value = None

        complete = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')

        self.assertFalse(complete)
    def _heat_deploy(self, stack, stack_name, template_path, parameters,
                     environments, timeout):
        """Verify the Baremetal nodes are available and do a stack update"""

        self.log.debug("Processing environment files")
        env_files, env = (
            template_utils.process_multiple_environments_and_files(
                environments))
        if stack:
            update.add_breakpoints_cleanup_into_env(env)

        self.log.debug("Getting template contents")
        template_files, template = template_utils.get_template_contents(
            template_path)

        files = dict(list(template_files.items()) + list(env_files.items()))

        clients = self.app.client_manager
        orchestration_client = clients.tripleoclient.orchestration

        self.log.debug("Deploying stack: %s", stack_name)
        self.log.debug("Deploying template: %s", template)
        self.log.debug("Deploying parameters: %s", parameters)
        self.log.debug("Deploying environment: %s", env)
        self.log.debug("Deploying files: %s", files)

        stack_args = {
            'stack_name': stack_name,
            'template': template,
            'environment': env,
            'files': files,
            'clear_parameters': env['parameter_defaults'].keys(),
        }

        if timeout:
            stack_args['timeout_mins'] = timeout

        if stack is None:
            self.log.info("Performing Heat stack create")
            action = 'CREATE'
            marker = None
            orchestration_client.stacks.create(**stack_args)
        else:
            self.log.info("Performing Heat stack update")
            # Make sure existing parameters for stack are reused
            stack_args['existing'] = 'true'
            # Find the last top-level event to use for the first marker
            events = event_utils.get_events(orchestration_client,
                                            stack_id=stack_name,
                                            event_args={'sort_dir': 'desc',
                                                        'limit': 1})
            marker = events[0].id if events else None
            action = 'UPDATE'

            orchestration_client.stacks.update(stack.id, **stack_args)

        verbose_events = self.app_args.verbose_level > 0
        create_result = utils.wait_for_stack_ready(
            orchestration_client, stack_name, marker, action, verbose_events)
        if not create_result:
            if stack is None:
                raise Exception("Heat Stack create failed.")
            else:
                raise Exception("Heat Stack update failed.")
    def _heat_deploy(self, stack, stack_name, template_path, parameters,
                     environments, timeout):
        """Verify the Baremetal nodes are available and do a stack update"""

        self.log.debug("Processing environment files")
        env_files, env = (
            template_utils.process_multiple_environments_and_files(
                environments))
        if stack:
            update.add_breakpoints_cleanup_into_env(env)

        self.log.debug("Getting template contents")
        template_files, template = template_utils.get_template_contents(
            template_path)

        files = dict(list(template_files.items()) + list(env_files.items()))

        clients = self.app.client_manager
        orchestration_client = clients.tripleoclient.orchestration

        self.log.debug("Deploying stack: %s", stack_name)
        self.log.debug("Deploying template: %s", template)
        self.log.debug("Deploying parameters: %s", parameters)
        self.log.debug("Deploying environment: %s", env)
        self.log.debug("Deploying files: %s", files)

        stack_args = {
            'stack_name': stack_name,
            'template': template,
            'environment': env,
            'files': files,
            'clear_parameters': env['parameter_defaults'].keys(),
        }

        if timeout:
            stack_args['timeout_mins'] = timeout

        if stack is None:
            self.log.info("Performing Heat stack create")
            action = 'CREATE'
            marker = None
            orchestration_client.stacks.create(**stack_args)
        else:
            self.log.info("Performing Heat stack update")
            # Make sure existing parameters for stack are reused
            stack_args['existing'] = 'true'
            # Find the last top-level event to use for the first marker
            events = event_utils.get_events(orchestration_client,
                                            stack_id=stack_name,
                                            event_args={
                                                'sort_dir': 'desc',
                                                'limit': 1
                                            })
            marker = events[0].id if events else None
            action = 'UPDATE'

            orchestration_client.stacks.update(stack.id, **stack_args)

        verbose_events = self.app_args.verbose_level > 0
        create_result = utils.wait_for_stack_ready(orchestration_client,
                                                   stack_name, marker, action,
                                                   verbose_events)
        if not create_result:
            if stack is None:
                raise exceptions.DeploymentError("Heat Stack create failed.")
            else:
                raise exceptions.DeploymentError("Heat Stack update failed.")
def scale_down(log,
               clients,
               stack,
               nodes,
               timeout=None,
               verbosity=0,
               connection_timeout=None):
    """Unprovision and deletes overcloud nodes from a heat stack.

    :param log: Logging object
    :type log: Object

    :param clients: Application client object.
    :type clients: Object

    :param stack: Heat Stack object
    :type stack: Object

    :param nodes: List of nodes to delete. If the node UUID is used the
                  UUID will be used to lookup the node name before being
                  passed through to the cleanup playbook.
    :type nodes: List

    :param timeout: Timeout to use when deleting nodes. If timeout is None
                    it will be set to 240 minutes.
    :type timeout: Integer

    :param verbosity: Verbosity level
    :type verbosity: Integer

    :param connection_timeout: Ansible connection timeout in seconds.
    :type connection_timeout: Integer
    """

    if not timeout:
        timeout = 240

    limit_list = list()
    for node in nodes:
        try:
            _node = clients.compute.servers.get(node)
            limit_list.append(_node.name)
        except Exception:
            limit_list.append(node)

    deployment.config_download(log=log,
                               clients=clients,
                               stack=stack,
                               timeout=connection_timeout,
                               ansible_playbook_name='scale_playbook.yaml',
                               limit_list=limit_list,
                               verbosity=verbosity,
                               deployment_timeout=timeout)

    print('Running scale down')
    context = clients.tripleoclient.create_mistral_context()
    scale_down_action = scale.ScaleDownAction(nodes=nodes,
                                              timeout=timeout,
                                              container=stack.stack_name)
    scale_down_action.run(context=context)
    utils.wait_for_stack_ready(orchestration_client=clients.orchestration,
                               stack_name=stack.stack_name,
                               action='UPDATE')