Use a Zaqar queue to get stack events

This adds the ability to use Zaqar to retrieve Heat events instead of
polling the API.

Change-Id: I3b836637d4e72aaf7183dbabf0b0e32c2caa8270
Closes-Bug: #1639283
This commit is contained in:
Thomas Herve 2016-11-03 10:51:04 +01:00
parent 9e670a18d4
commit f4f0e92d75
5 changed files with 57 additions and 21 deletions

View File

@ -22,6 +22,7 @@ from unittest import TestCase
import yaml
from tripleoclient import exceptions
from tripleoclient.tests import fakes
from tripleoclient import utils
@ -109,6 +110,20 @@ class TestWaitForStackUtil(TestCase):
result = utils.wait_for_stack_ready(self.mock_orchestration, 'stack')
self.assertEqual(False, result)
@mock.patch("heatclient.common.event_utils.wait_for_events")
def test_wait_for_stack_websocket(self, mock_wait_for_events):
mock_wait_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',
ws_client=fakes.FakeWebSocket())
self.assertEqual(False, result)
@mock.patch('tripleoclient.utils.wait_for_provision_state')
def test_set_nodes_state(self, wait_for_state_mock):

View File

@ -463,10 +463,13 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.assertEqual(*args)
def _fake_heat_deploy(self, stack, stack_name, template_path,
parameters, environments, timeout, tht_root,
env, update_plan_only, run_validations):
parameters, environments, timeout, tht_root, env,
update_plan_only, run_validations, ws_client):
queue = env['event_sinks'][0]['target']
assertEqual(
{'parameter_defaults': {},
'event_sinks': [
{'target': queue, 'ttl': 14400, 'type': 'zaqar-queue'}],
'resource_registry': {'Test': u'OS::Heat::None'}}, env)
mock_deploy_heat.side_effect = _fake_heat_deploy
@ -519,10 +522,13 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.assertEqual(*args)
def _fake_heat_deploy(self, stack, stack_name, template_path,
parameters, environments, timeout, tht_root,
env, update_plan_only, run_validations):
parameters, environments, timeout, tht_root, env,
update_plan_only, run_validations, ws_client):
queue = env['event_sinks'][0]['target']
assertEqual(
{'parameter_defaults': {},
'event_sinks': [
{'target': queue, 'ttl': 14400, 'type': 'zaqar-queue'}],
'resource_registry': {'Test': u'OS::Heat::None'}}, env)
mock_deploy_heat.side_effect = _fake_heat_deploy
@ -760,13 +766,14 @@ 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, mock.ANY)
# 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,
mock.ANY)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_heat_deploy', autospec=True)
@ -775,7 +782,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_heat_deploy_func.side_effect = ObjectClientException('error')
self.assertRaises(ValueError,
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.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
@ -786,8 +793,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
ObjectClientException('/fake/path not found')
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)
'/fake/path', 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))
@ -1256,7 +1263,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, mock.ANY)
self.assertFalse(mock_deploy_and_wait.called)

View File

@ -153,7 +153,7 @@ def check_hypervisor_stats(compute_client, nodes=1, memory=0, vcpu=0):
def wait_for_stack_ready(orchestration_client, stack_name, marker=None,
action='CREATE', verbose=False):
action='CREATE', verbose=False, ws_client=None):
"""Check the status of an orchestration stack
Get the status of an orchestration stack and check whether it is complete
@ -183,9 +183,14 @@ def wait_for_stack_ready(orchestration_client, stack_name, marker=None,
out = sys.stdout
else:
out = open(os.devnull, "w")
stack_status, msg = event_utils.poll_for_events(
orchestration_client, stack_name, action=action,
poll_period=5, marker=marker, out=out, nested_depth=2)
if ws_client is not None:
with ws_client:
stack_status, msg = event_utils.wait_for_events(
ws_client, stack_name, out=out)
else:
stack_status, msg = event_utils.poll_for_events(
orchestration_client, stack_name, action=action,
poll_period=5, marker=marker, out=out, nested_depth=2)
print(msg)
return stack_status == '%s_COMPLETE' % action

View File

@ -192,7 +192,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, ws_client):
"""Verify the Baremetal nodes are available and do a stack update"""
clients = self.app.client_manager
@ -242,7 +242,8 @@ class DeployOvercloud(command.Command):
deployment.deploy_and_wait(self.log, clients, stack, stack_name,
self.app_args.verbose_level,
timeout=timeout,
run_validations=run_validations)
run_validations=run_validations,
ws_client=ws_client)
def _load_environment_directories(self, directories):
if os.environ.get('TRIPLEO_ENVIRONMENT_DIRECTORY'):
@ -433,6 +434,13 @@ class DeployOvercloud(command.Command):
parsed_args.environment_directories))
env.update(self._create_parameters_env(parameters))
event_queue = str(uuid.uuid4())
env['event_sinks'] = [
{'type': 'zaqar-queue', 'target': event_queue,
'ttl': parsed_args.timeout * 60}]
clients = self.app.client_manager
ws_client = clients.tripleoclient.messaging_websocket(event_queue)
if parsed_args.rhel_reg:
reg_env_files, reg_env = self._create_registration_env(parsed_args)
created_env_files.extend(reg_env_files)
@ -449,19 +457,19 @@ 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, ws_client)
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, ws_client):
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, ws_client)
except ClientException as e:
messages = 'Failed to deploy: %s' % str(e)
raise ValueError(messages)

View File

@ -45,7 +45,7 @@ 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, ws_client=None):
"""Start the deploy and wait for it to finish"""
workflow_input = {
@ -79,7 +79,8 @@ def deploy_and_wait(log, clients, stack, plan_name, verbose_level,
time.sleep(10)
verbose_events = verbose_level > 0
create_result = utils.wait_for_stack_ready(
orchestration_client, plan_name, marker, action, verbose_events)
orchestration_client, plan_name, marker, action, verbose_events,
ws_client)
if not create_result:
shell.OpenStackShell().run(["stack", "failures", "list", plan_name])
if stack is None: