384 lines
15 KiB
Python
384 lines
15 KiB
Python
# Copyright 2016 Red Hat, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
import tempfile
|
|
from unittest import mock
|
|
|
|
import yaml
|
|
|
|
from heatclient import exc as heat_exc
|
|
from swiftclient import exceptions as swiftexceptions
|
|
|
|
from tripleo_common import constants
|
|
from tripleo_common.tests import base
|
|
from tripleo_common.utils import stack
|
|
|
|
|
|
class UpdateStackTest(base.TestCase):
|
|
|
|
@mock.patch('tripleo_common.utils.template.process_templates')
|
|
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
|
@mock.patch('tripleo_common.utils.plan.put_env')
|
|
@mock.patch('tripleo_common.utils.plan.get_env')
|
|
@mock.patch('tripleo_common.utils.plan.update_in_env')
|
|
def test_stack_update(self, mock_updateinenv,
|
|
mock_getenv,
|
|
mock_putenv,
|
|
mock_template_contents,
|
|
mock_process_templates):
|
|
heat = mock.MagicMock()
|
|
heat.stacks.get.return_value = mock.MagicMock(
|
|
stack_name='mycloud', id='stack_id')
|
|
|
|
mock_template_contents.return_value = ({}, {
|
|
'heat_template_version': '2016-04-30'
|
|
})
|
|
mock_swift = mock.MagicMock()
|
|
env = {
|
|
'name': 'mycloud',
|
|
'parameter_defaults': {
|
|
'ControllerCount': 1,
|
|
'ComputeCount': 1,
|
|
'ObjectStorageCount': 0,
|
|
'BlockStorageCount': 0,
|
|
'CephStorageCount': 0,
|
|
},
|
|
'stack_name': 'mycloud',
|
|
'stack_status': "CREATE_COMPLETE",
|
|
'outputs': [
|
|
{'output_key': 'RoleConfig',
|
|
'output_value': {
|
|
'foo_config': 'foo'}},
|
|
{'output_key': 'RoleData',
|
|
'output_value': {
|
|
'FakeCompute': {
|
|
'config_settings': {'nova::compute::fake'
|
|
'libvirt_virt_type': 'qemu'},
|
|
'global_config_settings': {},
|
|
'logging_groups': ['root', 'neutron', 'nova'],
|
|
'logging_sources': [{'path': '/var/log/fake.log',
|
|
'type': 'tail'}],
|
|
'monitoring_subscriptions': ['nova-compute'],
|
|
'service_config_settings': None,
|
|
'service_metadata_settings': None,
|
|
'service_names': ['nova_compute', 'fake_service'],
|
|
'step_config': ['include ::tripleo::profile::fake',
|
|
'include ::timezone'],
|
|
'upgrade_batch_tasks': [],
|
|
'upgrade_tasks': [{'name': 'Stop fake service',
|
|
'service': 'name=fo state=stopped',
|
|
'tags': 'step1',
|
|
'when': 'existingcondition'},
|
|
{'name': 'Stop nova-compute',
|
|
'service': 'name=nova-compute '
|
|
'state=stopped',
|
|
'tags': 'step1',
|
|
'when': ['existing', 'list']}]
|
|
}}}]}
|
|
|
|
mock_getenv.return_value = env
|
|
mock_swift.get_object.return_value = ({}, env)
|
|
|
|
stack.stack_update(mock_swift, heat, 120)
|
|
mock_putenv.assert_called_once_with(mock_swift, {
|
|
'name': env['name'],
|
|
'resource_registry': {
|
|
'OS::TripleO::DeploymentSteps': 'OS::Heat::None',
|
|
},
|
|
'parameter_defaults': {
|
|
'DeployIdentifier': mock.ANY,
|
|
'ControllerCount': 1,
|
|
'ComputeCount': 1,
|
|
'ObjectStorageCount': 0,
|
|
'BlockStorageCount': 0,
|
|
'CephStorageCount': 0,
|
|
},
|
|
'stack_name': env['stack_name'],
|
|
'stack_status': env['stack_status'],
|
|
'outputs': env['outputs'],
|
|
})
|
|
|
|
heat.stacks.update.assert_called_once_with('stack_id')
|
|
|
|
|
|
class DeployStackTest(base.TestCase):
|
|
|
|
@mock.patch('tripleo_common.utils.stack.time')
|
|
@mock.patch('heatclient.common.template_utils.'
|
|
'process_multiple_environments_and_files')
|
|
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
|
def test_stack_deploy(
|
|
self, mock_get_template_contents,
|
|
mock_process_multiple_environments_and_files,
|
|
mock_time):
|
|
|
|
# setup swift
|
|
swift = mock.MagicMock(url="http://test.com")
|
|
mock_env = yaml.safe_dump({
|
|
'name': 'overcloud',
|
|
'temp_environment': 'temp_environment',
|
|
'template': 'template',
|
|
'environments': [{u'path': u'environments/test.yaml'}],
|
|
'parameter_defaults': {'random_existing_data': 'a_value'},
|
|
}, default_flow_style=False)
|
|
swift.get_object.side_effect = (
|
|
({}, mock_env),
|
|
({}, mock_env),
|
|
swiftexceptions.ClientException('atest2')
|
|
)
|
|
heat = mock.MagicMock()
|
|
heat.stacks.get.return_value = None
|
|
|
|
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
|
|
|
|
stack.deploy_stack(swift, heat, 'overcloud')
|
|
|
|
# verify parameters are as expected
|
|
expected_defaults = {'DeployIdentifier': 1473366264,
|
|
'StackAction': 'CREATE',
|
|
'random_existing_data': 'a_value'}
|
|
|
|
mock_env_updated = yaml.safe_dump({
|
|
'name': 'overcloud',
|
|
'temp_environment': 'temp_environment',
|
|
'parameter_defaults': expected_defaults,
|
|
'template': 'template',
|
|
'environments': [{u'path': u'environments/test.yaml'}]
|
|
}, default_flow_style=False)
|
|
|
|
swift.put_object.assert_called_once_with(
|
|
'overcloud',
|
|
constants.PLAN_ENVIRONMENT,
|
|
mock_env_updated
|
|
)
|
|
|
|
heat.stacks.create.assert_called_once_with(
|
|
environment={},
|
|
files={},
|
|
stack_name='overcloud',
|
|
template={'heat_template_version': '2016-04-30'},
|
|
timeout_mins=240,
|
|
)
|
|
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)
|
|
|
|
@mock.patch('tripleo_common.utils.stack.time')
|
|
@mock.patch('heatclient.common.template_utils.'
|
|
'process_multiple_environments_and_files')
|
|
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
|
def test_run_skip_deploy_identifier(
|
|
self, mock_get_template_contents,
|
|
mock_process_multiple_environments_and_files,
|
|
mock_time):
|
|
|
|
# setup swift
|
|
swift = mock.MagicMock(url="http://test.com")
|
|
|
|
heat = mock.MagicMock()
|
|
heat.stacks.get.return_value = None
|
|
|
|
mock_env = yaml.safe_dump({
|
|
'name': constants.DEFAULT_CONTAINER_NAME,
|
|
'temp_environment': 'temp_environment',
|
|
'template': 'template',
|
|
'environments': [{u'path': u'environments/test.yaml'}],
|
|
'parameter_defaults': {'random_existing_data': 'a_value'},
|
|
}, default_flow_style=False)
|
|
swift.get_object.side_effect = (
|
|
({}, mock_env),
|
|
({}, mock_env),
|
|
swiftexceptions.ClientException('atest2')
|
|
)
|
|
|
|
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
|
|
|
|
stack.deploy_stack(swift, heat,
|
|
'overcloud', skip_deploy_identifier=True)
|
|
|
|
# verify parameters are as expected
|
|
mock_env_updated = yaml.safe_dump({
|
|
'name': constants.DEFAULT_CONTAINER_NAME,
|
|
'temp_environment': 'temp_environment',
|
|
'parameter_defaults': {'StackAction': 'CREATE',
|
|
'DeployIdentifier': '',
|
|
'random_existing_data': 'a_value'},
|
|
'template': 'template',
|
|
'environments': [{u'path': u'environments/test.yaml'}]
|
|
}, default_flow_style=False)
|
|
|
|
swift.put_object.assert_called_once_with(
|
|
constants.DEFAULT_CONTAINER_NAME,
|
|
constants.PLAN_ENVIRONMENT,
|
|
mock_env_updated
|
|
)
|
|
|
|
heat.stacks.create.assert_called_once_with(
|
|
environment={},
|
|
files={},
|
|
stack_name='overcloud',
|
|
template={'heat_template_version': '2016-04-30'},
|
|
timeout_mins=240,
|
|
)
|
|
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)
|
|
|
|
@mock.patch('tripleo_common.utils.stack.time')
|
|
@mock.patch('heatclient.common.template_utils.'
|
|
'process_multiple_environments_and_files')
|
|
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
|
def test_run_create_failed(
|
|
self, mock_get_template_contents,
|
|
mock_process_multiple_environments_and_files,
|
|
mock_time):
|
|
|
|
# setup swift
|
|
swift = mock.MagicMock(url="http://test.com")
|
|
mock_env = yaml.safe_dump({
|
|
'name': 'overcloud',
|
|
'temp_environment': 'temp_environment',
|
|
'template': 'template',
|
|
'environments': [{u'path': u'environments/test.yaml'}],
|
|
'parameter_defaults': {'random_existing_data': 'a_value'},
|
|
}, default_flow_style=False)
|
|
swift.get_object.side_effect = (
|
|
({}, mock_env),
|
|
({}, mock_env),
|
|
swiftexceptions.ClientException('atest2')
|
|
)
|
|
|
|
heat = mock.MagicMock()
|
|
heat.stacks.get.return_value = None
|
|
heat.stacks.create.side_effect = heat_exc.HTTPException("Oops")
|
|
|
|
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
|
|
|
|
self.assertRaises(RuntimeError, stack.deploy_stack,
|
|
swift, heat, 'overcloud')
|
|
|
|
@mock.patch('tripleo_common.update.check_neutron_mechanism_drivers')
|
|
@mock.patch('tripleo_common.utils.stack.time')
|
|
@mock.patch('heatclient.common.template_utils.'
|
|
'process_multiple_environments_and_files')
|
|
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
|
def test_run_update_failed(
|
|
self, mock_get_template_contents,
|
|
mock_process_multiple_environments_and_files, mock_time,
|
|
mock_check_neutron_drivers):
|
|
|
|
# setup swift
|
|
swift = mock.MagicMock(url="http://test.com")
|
|
mock_env = yaml.safe_dump({
|
|
'name': 'overcloud',
|
|
'temp_environment': 'temp_environment',
|
|
'template': 'template',
|
|
'environments': [{u'path': u'environments/test.yaml'}],
|
|
'parameter_defaults': {'random_existing_data': 'a_value'},
|
|
}, default_flow_style=False)
|
|
swift.get_object.side_effect = (
|
|
({}, mock_env),
|
|
({}, mock_env),
|
|
swiftexceptions.ClientException('atest2')
|
|
)
|
|
|
|
heat = mock.MagicMock()
|
|
heat.stacks.get.return_value = mock.Mock()
|
|
heat.stacks.update.side_effect = heat_exc.HTTPException("Oops")
|
|
|
|
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
|
|
mock_check_neutron_drivers.return_value = None
|
|
|
|
self.assertRaises(RuntimeError, stack.deploy_stack,
|
|
swift, heat, 'overcloud')
|
|
|
|
def test_set_tls_parameters_no_ca_found(self):
|
|
my_params = {}
|
|
my_env = {'parameter_defaults': {}}
|
|
stack.set_tls_parameters(
|
|
parameters=my_params, env=my_env,
|
|
local_ca_path='/tmp/my-unexistent-file.txt')
|
|
self.assertEqual(my_params, {})
|
|
|
|
def test_set_tls_parameters_ca_found_no_camap_provided(self):
|
|
my_params = {}
|
|
my_env = {'parameter_defaults': {}}
|
|
with tempfile.NamedTemporaryFile() as ca_file:
|
|
# Write test data
|
|
ca_file.write(b'FAKE CA CERT')
|
|
ca_file.flush()
|
|
|
|
# Test
|
|
stack.set_tls_parameters(
|
|
parameters=my_params, env=my_env,
|
|
local_ca_path=ca_file.name)
|
|
self.assertIn('CAMap', my_params)
|
|
self.assertIn('undercloud-ca', my_params['CAMap'])
|
|
self.assertIn('content', my_params['CAMap']['undercloud-ca'])
|
|
self.assertEqual(
|
|
'FAKE CA CERT',
|
|
my_params['CAMap']['undercloud-ca']['content'])
|
|
|
|
def test_set_tls_parameters_ca_found_camap_provided(self):
|
|
my_params = {}
|
|
my_env = {
|
|
'parameter_defaults': {
|
|
'CAMap': {'overcloud-ca': {'content': 'ANOTER FAKE CERT'}}}}
|
|
with tempfile.NamedTemporaryFile() as ca_file:
|
|
# Write test data
|
|
ca_file.write(b'FAKE CA CERT')
|
|
ca_file.flush()
|
|
|
|
# Test
|
|
stack.set_tls_parameters(
|
|
parameters=my_params, env=my_env,
|
|
local_ca_path=ca_file.name)
|
|
self.assertIn('CAMap', my_params)
|
|
self.assertIn('undercloud-ca', my_params['CAMap'])
|
|
self.assertIn('content', my_params['CAMap']['undercloud-ca'])
|
|
self.assertEqual('FAKE CA CERT',
|
|
my_params['CAMap']['undercloud-ca']['content'])
|
|
self.assertIn('overcloud-ca', my_params['CAMap'])
|
|
self.assertIn('content', my_params['CAMap']['overcloud-ca'])
|
|
self.assertEqual('ANOTER FAKE CERT',
|
|
my_params['CAMap']['overcloud-ca']['content'])
|