tripleo-common/tripleo_common/tests/actions/test_parameters.py

1708 lines
70 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 mock
import yaml
from swiftclient import exceptions as swiftexceptions
from tripleo_common.actions import parameters
from tripleo_common import constants
from tripleo_common import exception
from tripleo_common.tests import base
from tripleo_common.utils import passwords as password_utils
_EXISTING_PASSWORDS = {
'PlacementPassword': 'VFJeqBKbatYhQm9jja67hufft',
'MistralPassword': 'VFJeqBKbatYhQm9jja67hufft',
'BarbicanPassword': 'MGGQBtgKT7FnywvkcdMwE9nhx',
'BarbicanSimpleCryptoKek': 'dGhpcnR5X3R3b19ieXRlX2tleWJsYWhibGFoYmxhaGg=',
'AdminPassword': 'jFmY8FTpvtF2e4d4ReXvmUP8k',
'CeilometerMeteringSecret': 'CbHTGK4md4Cc8P8ZyzTns6wry',
'ZaqarPassword': 'bbFgCTFbAH8vf9n3xvZCP8aMR',
'NovaPassword': '7dZATgVPwD7Ergs9kTTDMCr7F',
'MysqlRootPassword': 'VqJYpEdKks',
'RabbitCookie': 'BqJYpEdKksAqJYpEdKks',
'HeatAuthEncryptionKey': '9xZXehsKc2HbmFFMKjuqxTJHn',
'PcsdPassword': 'KjEzeitus8eu751a',
'HorizonSecret': 'mjEzeitus8eu751B',
'NovajoinPassword': '7dZATgVPwD7Ergs9kTTDMCr7F',
'IronicPassword': '4hFDgn9ANeVfuqk84pHpD4ksa',
'RedisPassword': 'xjj3QZDcUQmU6Q7NzWBHRUhGd',
'SaharaPassword': 'spFvYGezdFwnTk7NPxgYTbUPh',
'AdminToken': 'jq6G6HyZtj7dcZEvuyhAfjutM',
'CinderPassword': 'dcxC3xyUcrmvzfrrxpAd3REcm',
'CongressPassword': 'DwcKvMqXMuNYYFU4zTCuG4234',
'GlancePassword': 'VqJYNEdKKsGZtgnHct77XBtrV',
'RabbitPassword': 'ahuHRXdPMx9rzCdjD9CJJNCgA',
'RpcPassword': 'ahuHRXdPMx9rzCdjD9CJJNCgA',
'NotifyPassword': 'ahuHRXdPMx9rzCdjD9CJJNCgA',
'CephAdminKey': b'AQCQXtlXAAAAABAAT4Gk+U8EqqStL+JFa9bp1Q==',
'HAProxyStatsPassword': 'P8tbdK6n4YUkTaUyy8XgEVTe6',
'TackerPassword': 'DwcKvMqXMuNYYFU4zTCuG4234',
'TrovePassword': 'V7A7zegkMdRFnYuN23gdc4KQC',
'CeilometerPassword': 'RRdpwK6qf2pbKz2UtzxqauAdk',
'GnocchiPassword': 'cRYHcUkMuJeK3vyU9pCaznUZc',
'HeatStackDomainAdminPassword': 'GgTRyWzKYsxK4mReTJ4CM6sMc',
'CephRgwKey': b'AQCQXtlXAAAAABAAUKcqUMu6oMjAXMjoUV4/3A==',
'AodhPassword': '8VZXehsKc2HbmFFMKYuqxTJHn',
'PankoPassword': 'cVZXehsSc2KdmFFMKDudxTLKn',
'OctaviaHeartbeatKey': 'oct-heartbeat-key',
'OctaviaPassword': 'NMl7j3nKk1VVwMxUZC8Cgw==',
'OctaviaServerCertsKeyPassphrase': 'aW5zZWN1cmUta2V5LWRvLW5vdC11c2U=',
'OctaviaCaKeyPassphrase': 'SLj4c3uCk4DDxPwQOG1Heb==',
'ManilaPassword': 'NYJN86Fua3X8AVFWmMhQa2zTH',
'NeutronMetadataProxySharedSecret': 'Q2YgUCwmBkYdqsdhhCF4hbghu',
'CephMdsKey': b'AQCQXtlXAAAAABAAT4Gk+U8EqqStL+JFa9bp1Q==',
'CephManilaClientKey': b'AQANOFFY1NW6AxAAu6jWI3YSOsp2QWusb5Y3DQ==',
'CephMonKey': b'AQCQXtlXAAAAABAA9l+59N3yH+C49Y0JiKeGFg==',
'SwiftHashSuffix': 'td8mV6k7TYEGKCDvjVBwckpn9',
'SnmpdReadonlyUserPassword': 'TestPassword',
'SwiftPassword': 'z6EWAVfW7CuxvKdzjWTdrXCeg',
'HeatPassword': 'bREnsXtMHKTHxt8XW6NXAYr48',
'MysqlClustercheckPassword': 'jN4RMMWWJ4sycaRwh7UvrAtfX',
'CephClientKey': b'AQCQXtlXAAAAABAAKyc+8St8i9onHyu2mPk+vg==',
'NeutronPassword': 'ZxAjdU2UXCV4GM3WyPKrzAZXD',
'DesignatePassword': 'wHYj7rftFzHMpJKnGxbjjR9CW',
'DesignateRndcKey': 'hB8XaZRd2Tf00jKsyoXpyw==',
'KeystoneCredential0': 'ftJNQ_XlDUK7Lgvv1kdWf3SyqVsrvNDgoNV4kJg3yzw=',
'KeystoneCredential1': 'c4MFq82TQLFLKpiiUjrKkp15dafE2ALcD3jbaIu3rfE=',
'KeystoneFernetKey0': 'O8NSPxr4zXBBAoGIj-5aUmtE7-Jk5a4ptVsEhzJ8Vd8=',
'KeystoneFernetKey1': 'AueoL37kd6eLjV29AG-Ruxu5szW47osgXx6aPOqtI6I=',
'KeystoneFernetKeys': {
'/etc/keystone/fernet-keys/0': {'content': 'IAMAVERYSAFEKEY'},
'/etc/keystone/fernet-keys/1': {'content': 'IALSOAMAVERYSAFEKEY'}
},
'CephClusterFSID': u'97c16f44-b62c-11e6-aed3-185e0f73fdc5',
'Ec2ApiPassword': 'FPvz2WiWxrHVWrmSSvv44bqmr',
'EtcdInitialClusterToken': 'fcVZXehsSc2KdmFFMKDudxTLKa',
'PacemakerRemoteAuthkey':
'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'
'sGhUtCQVed7dtj12',
'MigrationSshKey': {
'private_key': 'private_key',
'public_key': 'public_key'
},
'LibvirtTLSPassword': 'xCdt9yeamKz8Fb6EGba9u82XU',
'OpenDaylightPassword': 'abc487gfh017rmviuq75jdiw7',
}
class GetParametersActionTest(base.TestCase):
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_get')
@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_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run(self, mock_get_object_client,
mock_get_orchestration_client,
mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
mock_process_multiple_environments_and_files.return_value = ({}, {})
mock_heat = mock.MagicMock()
mock_heat.stacks.validate.return_value = {}
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
# Test
action = parameters.GetParametersAction()
action.run(mock_ctx)
mock_heat.stacks.validate.assert_called_once_with(
environment={},
files={},
show_nested=True,
template={'heat_template_version': '2016-04-30'},
)
mock_cache_get.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get"
)
mock_cache_set.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get",
{'heat_resource_tree': {}, 'environment_parameters': None}
)
class ResetParametersActionTest(base.TestCase):
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_delete')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run(self, mock_get_object_client, mock_cache):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}],
'parameter_defaults': {'SomeTestParameter': 42}
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
# Test
action = parameters.ResetParametersAction()
action.run(mock_ctx)
mock_env_reset = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'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_reset
)
mock_cache.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get"
)
class UpdateParametersActionTest(base.TestCase):
@mock.patch('tripleo_common.actions.parameters.uuid')
@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.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_object_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
def test_run(self, mock_get_orchestration_client_client,
mock_get_object_client, mock_cache,
mock_get_template_contents, mock_env_files,
mock_uuid):
mock_env_files.return_value = ({}, {})
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}],
}, default_flow_style=False)
mock_roles = yaml.safe_dump([{"name": "foo"}])
mock_network = yaml.safe_dump([{'enabled': False}])
mock_exclude = yaml.safe_dump({"name": "foo"})
swift.get_object.side_effect = (
({}, mock_env),
({}, mock_env),
({}, mock_roles),
({}, mock_network),
({}, mock_exclude),
({}, mock_env),
({}, mock_env),
({}, mock_env),
({}, mock_roles),
({}, mock_network),
({}, mock_exclude),
({}, mock_env),
({}, mock_env),
swiftexceptions.ClientException('atest2')
)
def return_container_files(*args):
return ('headers', [{'name': 'foo.role.j2.yaml'}])
swift.get_container = mock.MagicMock(
side_effect=return_container_files)
mock_get_object_client.return_value = swift
mock_heat = mock.MagicMock()
mock_get_orchestration_client_client.return_value = mock_heat
mock_heat.stacks.validate.return_value = {
"Type": "Foo",
"Description": "Le foo bar",
"Parameters": {"bar": {"foo": "bar barz"}},
"NestedParameters": {"Type": "foobar"}
}
mock_uuid.uuid4.return_value = "cheese"
expected_value = {
'environment_parameters': None,
'heat_resource_tree': {
'parameters': {'bar': {'foo': 'bar barz',
'name': 'bar'}},
'resources': {'cheese': {
'id': 'cheese',
'name': 'Root',
'description': 'Le foo bar',
'parameters': ['bar'],
'resources': ['cheese'],
'type': 'Foo'}
}
}
}
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
# Test
test_parameters = {'SomeTestParameter': 42}
action = parameters.UpdateParametersAction(test_parameters)
return_value = action.run(mock_ctx)
mock_env_updated = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'temp_environment': 'temp_environment',
'parameter_defaults': {'SomeTestParameter': 42},
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.put_object.assert_any_call(
constants.DEFAULT_CONTAINER_NAME,
constants.PLAN_ENVIRONMENT,
mock_env_updated
)
mock_heat.stacks.validate.assert_called_once_with(
environment={},
files={},
show_nested=True,
template={'heat_template_version': '2016-04-30'},
)
mock_cache.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get",
expected_value
)
self.assertEqual(return_value, expected_value)
@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.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_object_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
def test_run_new_key(self, mock_get_orchestration_client_client,
mock_get_object_client, mock_cache,
mock_get_template_contents, mock_env_files):
mock_env_files.return_value = ({}, {})
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}],
}, default_flow_style=False)
mock_roles = yaml.safe_dump([{"name": "foo"}])
mock_network = yaml.safe_dump([{'enabled': False}])
mock_exclude = yaml.safe_dump({"name": "foo"})
swift.get_object.side_effect = (
({}, mock_env),
({}, mock_env),
({}, mock_roles),
({}, mock_network),
({}, mock_exclude),
({}, mock_env),
({}, mock_env),
({}, mock_env),
({}, mock_roles),
({}, mock_network),
({}, mock_exclude),
({}, mock_env),
({}, mock_env),
swiftexceptions.ClientException('atest2')
)
def return_container_files(*args):
return ('headers', [{'name': 'foo.role.j2.yaml'}])
swift.get_container = mock.MagicMock(
side_effect=return_container_files)
mock_get_object_client.return_value = swift
heat = mock.MagicMock()
heat.stacks.validate.return_value = {}
mock_get_orchestration_client_client.return_value = heat
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
# Test
test_parameters = {'SomeTestParameter': 42}
action = parameters.UpdateParametersAction(test_parameters,
key='test_key')
action.run(mock_ctx)
mock_env_updated = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'temp_environment': 'temp_environment',
'test_key': {'SomeTestParameter': 42},
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.put_object.assert_any_call(
constants.DEFAULT_CONTAINER_NAME,
constants.PLAN_ENVIRONMENT,
mock_env_updated
)
heat.stacks.validate.assert_called_once_with(
environment={},
files={},
show_nested=True,
template={'heat_template_version': '2016-04-30'},
)
mock_cache.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get",
{'environment_parameters': None, 'heat_resource_tree': {}}
)
class UpdateRoleParametersActionTest(base.TestCase):
@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.'
'cache_set')
@mock.patch('tripleo_common.utils.parameters.set_count_and_flavor_params')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_baremetal_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_compute_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_object_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
def test_run(self, mock_get_orchestration_client_client,
mock_get_object_client, mock_get_compute_client,
mock_get_baremetal_client, mock_set_count_and_flavor,
mock_cache, mock_get_template_contents, mock_env_files):
mock_env_files.return_value = ({}, {})
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': 'overcast'
}, default_flow_style=False)
mock_roles = yaml.safe_dump([{"name": "foo"}])
mock_network = yaml.safe_dump([{'enabled': False}])
mock_exclude = yaml.safe_dump({"name": "foo"})
swift.get_object.side_effect = (
({}, mock_env),
({}, mock_env),
({}, mock_roles),
({}, mock_network),
({}, mock_exclude),
({}, mock_env),
({}, mock_env),
({}, mock_env),
({}, mock_roles),
({}, mock_network),
({}, mock_exclude),
({}, mock_env),
({}, mock_env),
swiftexceptions.ClientException('atest2')
)
def return_container_files(*args):
return ('headers', [{'name': 'foo.yaml'}])
swift.get_container = mock.MagicMock(
side_effect=return_container_files)
mock_get_object_client.return_value = swift
heat = mock.MagicMock()
heat.stacks.validate.return_value = {}
mock_get_orchestration_client_client.return_value = heat
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
params = {'CephStorageCount': 1,
'OvercloudCephStorageFlavor': 'ceph-storage'}
mock_set_count_and_flavor.return_value = params
action = parameters.UpdateRoleParametersAction('ceph-storage',
'overcast')
action.run(mock_ctx)
mock_env_updated = yaml.safe_dump({
'name': 'overcast',
'parameter_defaults': params
}, default_flow_style=False)
swift.put_object.assert_any_call(
'overcast',
constants.PLAN_ENVIRONMENT,
mock_env_updated
)
heat.stacks.validate.assert_called_once_with(
environment={},
files={},
show_nested=True,
template={'heat_template_version': '2016-04-30'},
)
mock_cache.assert_called_once_with(
mock_ctx,
"overcast",
"tripleo.parameters.get",
{'environment_parameters': None, 'heat_resource_tree': {}}
)
class GeneratePasswordsActionTest(base.TestCase):
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_delete')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.utils.passwords.'
'get_snmpd_readonly_user_password')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client', return_value="TestPassword")
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run(self, mock_get_object_client,
mock_get_workflow_client,
mock_get_snmpd_readonly_user_password,
mock_get_orchestration_client, mock_cache):
mock_get_snmpd_readonly_user_password.return_value = "TestPassword"
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': 'overcast',
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}],
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
mock_orchestration = mock.MagicMock()
mock_orchestration.stacks.environment.return_value = {
'parameter_defaults': {}
}
mock_resource = mock.MagicMock()
mock_resource.attributes = {
'value': 'existing_value'
}
mock_orchestration.resources.get.return_value = mock_resource
mock_get_orchestration_client.return_value = mock_orchestration
action = parameters.GeneratePasswordsAction()
result = action.run(mock_ctx)
for password_param_name in constants.PASSWORD_PARAMETER_NAMES:
self.assertTrue(password_param_name in result,
"%s is not in %s" % (password_param_name, result))
if password_param_name in \
constants.LEGACY_HEAT_PASSWORD_RESOURCE_NAMES:
self.assertEqual(result[password_param_name], 'existing_value')
else:
self.assertNotEqual(result[password_param_name],
'existing_value')
mock_cache.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get"
)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_delete')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.utils.passwords.'
'create_ssh_keypair')
@mock.patch('tripleo_common.utils.passwords.'
'create_fernet_keys_repo_structure_and_keys')
@mock.patch('tripleo_common.utils.passwords.'
'get_snmpd_readonly_user_password')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_passwords_exist(self, mock_get_object_client,
mock_get_workflow_client,
mock_get_snmpd_readonly_user_password,
mock_fernet_keys_setup,
mock_create_ssh_keypair,
mock_get_orchestration_client,
mock_cache):
mock_get_snmpd_readonly_user_password.return_value = "TestPassword"
mock_create_ssh_keypair.return_value = {'public_key': 'Foo',
'private_key': 'Bar'}
mock_fernet_keys_setup.return_value = {'/tmp/foo': {'content': 'Foo'},
'/tmp/bar': {'content': 'Bar'}}
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}],
'passwords': _EXISTING_PASSWORDS.copy()
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
mock_orchestration = mock.MagicMock()
mock_orchestration.stacks.environment.return_value = {
'parameter_defaults': {}
}
mock_get_orchestration_client.return_value = mock_orchestration
action = parameters.GeneratePasswordsAction()
result = action.run(mock_ctx)
# ensure old passwords used and no new generation
self.assertEqual(_EXISTING_PASSWORDS, result)
mock_cache.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get"
)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_delete')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.utils.passwords.'
'create_ssh_keypair')
@mock.patch('tripleo_common.utils.passwords.'
'create_fernet_keys_repo_structure_and_keys')
@mock.patch('tripleo_common.utils.passwords.'
'get_snmpd_readonly_user_password')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_rotate_no_rotate_list(self, mock_get_object_client,
mock_get_workflow_client,
mock_get_snmpd_readonly_user_password,
mock_fernet_keys_setup,
mock_create_ssh_keypair,
mock_get_orchestration_client,
mock_cache):
mock_get_snmpd_readonly_user_password.return_value = "TestPassword"
mock_create_ssh_keypair.return_value = {'public_key': 'Foo',
'private_key': 'Bar'}
mock_fernet_keys_setup.return_value = {'/tmp/foo': {'content': 'Foo'},
'/tmp/bar': {'content': 'Bar'}}
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}],
'passwords': _EXISTING_PASSWORDS.copy()
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
mock_orchestration = mock.MagicMock()
mock_orchestration.stacks.environment.return_value = {
'parameter_defaults': {}
}
mock_resource = mock.MagicMock()
mock_resource.attributes = {
'value': 'existing_value'
}
mock_orchestration.resources.get.return_value = mock_resource
mock_get_orchestration_client.return_value = mock_orchestration
action = parameters.GeneratePasswordsAction(rotate_passwords=True)
result = action.run(mock_ctx)
# ensure passwords in the DO_NOT_ROTATE_LIST are not modified
for name in constants.DO_NOT_ROTATE_LIST:
self.assertEqual(_EXISTING_PASSWORDS[name], result[name])
# ensure all passwords are generated
for name in constants.PASSWORD_PARAMETER_NAMES:
self.assertTrue(name in result, "%s is not in %s" % (name, result))
# ensure new passwords have been generated
self.assertNotEqual(_EXISTING_PASSWORDS, result)
mock_cache.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get"
)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_delete')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.utils.passwords.'
'create_ssh_keypair')
@mock.patch('tripleo_common.utils.passwords.'
'create_fernet_keys_repo_structure_and_keys')
@mock.patch('tripleo_common.utils.passwords.'
'get_snmpd_readonly_user_password')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_rotate_with_rotate_list(self, mock_get_object_client,
mock_get_workflow_client,
mock_get_snmpd_readonly_user_password,
mock_fernet_keys_setup,
mock_create_ssh_keypair,
mock_get_orchestration_client,
mock_cache):
mock_get_snmpd_readonly_user_password.return_value = "TestPassword"
mock_create_ssh_keypair.return_value = {'public_key': 'Foo',
'private_key': 'Bar'}
mock_fernet_keys_setup.return_value = {'/tmp/foo': {'content': 'Foo'},
'/tmp/bar': {'content': 'Bar'}}
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}],
'passwords': _EXISTING_PASSWORDS.copy()
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
mock_orchestration = mock.MagicMock()
mock_orchestration.stacks.environment.return_value = {
'parameter_defaults': {}
}
mock_resource = mock.MagicMock()
mock_resource.attributes = {
'value': 'existing_value'
}
mock_orchestration.resources.get.return_value = mock_resource
mock_get_orchestration_client.return_value = mock_orchestration
rotate_list = [
'MistralPassword',
'BarbicanPassword',
'AdminPassword',
'CeilometerMeteringSecret',
'ZaqarPassword',
'NovaPassword',
'MysqlRootPassword'
]
action = parameters.GeneratePasswordsAction(
rotate_passwords=True,
rotate_pw_list=rotate_list
)
result = action.run(mock_ctx)
# ensure only specified passwords are regenerated
for name in constants.PASSWORD_PARAMETER_NAMES:
self.assertTrue(name in result, "%s is not in %s" % (name, result))
if name in rotate_list:
self.assertNotEqual(_EXISTING_PASSWORDS[name], result[name])
else:
self.assertEqual(_EXISTING_PASSWORDS[name], result[name])
mock_cache.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get"
)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_delete')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.utils.passwords.'
'create_ssh_keypair')
@mock.patch('tripleo_common.utils.passwords.'
'create_fernet_keys_repo_structure_and_keys')
@mock.patch('tripleo_common.utils.passwords.'
'get_snmpd_readonly_user_password')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_passwords_exist_in_heat(self, mock_get_object_client,
mock_get_workflow_client,
mock_get_snmpd_readonly_user_password,
mock_fernet_keys_setup,
mock_create_ssh_keypair,
mock_get_orchestration_client,
mock_cache):
mock_get_snmpd_readonly_user_password.return_value = "TestPassword"
mock_create_ssh_keypair.return_value = {'public_key': 'Foo',
'private_key': 'Bar'}
mock_fernet_keys_setup.return_value = {'/tmp/foo': {'content': 'Foo'},
'/tmp/bar': {'content': 'Bar'}}
existing_passwords = _EXISTING_PASSWORDS.copy()
existing_passwords.pop("AdminPassword")
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'name': constants.DEFAULT_CONTAINER_NAME,
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}],
'passwords': existing_passwords.copy()
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
mock_orchestration = mock.MagicMock()
mock_orchestration.stacks.environment.return_value = {
'parameter_defaults': {
'AdminPassword': 'ExistingPasswordInHeat',
}
}
mock_get_orchestration_client.return_value = mock_orchestration
action = parameters.GeneratePasswordsAction()
result = action.run(mock_ctx)
existing_passwords["AdminPassword"] = "ExistingPasswordInHeat"
# ensure old passwords used and no new generation
self.assertEqual(existing_passwords, result)
mock_cache.assert_called_once_with(
mock_ctx,
"overcloud",
"tripleo.parameters.get"
)
class GetPasswordsActionTest(base.TestCase):
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_password_from_parameter_defaults(self,
mock_get_object_client,
mock_get_orchestration_client):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
"name": constants.DEFAULT_CONTAINER_NAME,
"parameter_defaults": _EXISTING_PASSWORDS,
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
mock_orchestration = mock.MagicMock()
mock_get_orchestration_client.return_value = mock_orchestration
action = parameters.GetPasswordsAction()
result = action.run(mock_ctx)
# ensure old passwords used and no new generation
self.assertEqual(_EXISTING_PASSWORDS, result)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_password_from_generated_passwords(self,
mock_get_object_client,
mock_get_orchestration_client):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
"name": constants.DEFAULT_CONTAINER_NAME,
"parameter_defaults": {},
"passwords": _EXISTING_PASSWORDS,
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
mock_orchestration = mock.MagicMock()
mock_get_orchestration_client.return_value = mock_orchestration
action = parameters.GetPasswordsAction()
result = action.run(mock_ctx)
# ensure old passwords used and no new generation
self.assertEqual(_EXISTING_PASSWORDS, result)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_password_merging_passwords(self,
mock_get_object_client,
mock_get_orchestration_client):
parameter_defaults = _EXISTING_PASSWORDS.copy()
passwords = {"AdminPassword": parameter_defaults.pop("AdminPassword")}
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
"name": constants.DEFAULT_CONTAINER_NAME,
"parameter_defaults": parameter_defaults,
"passwords": passwords
}, default_flow_style=False)
swift.get_object.return_value = ({}, mock_env)
mock_get_object_client.return_value = swift
mock_orchestration = mock.MagicMock()
mock_get_orchestration_client.return_value = mock_orchestration
action = parameters.GetPasswordsAction()
result = action.run(mock_ctx)
# ensure old passwords used and no new generation
self.assertEqual(_EXISTING_PASSWORDS, result)
class GenerateFencingParametersActionTestCase(base.TestCase):
@mock.patch('tripleo_common.utils.nodes.generate_hostmap')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_compute_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_baremetal_client')
def test_no_success(self, mock_get_baremetal, mock_get_compute,
mock_generate_hostmap):
mock_ctx = mock.MagicMock()
test_hostmap = {
"00:11:22:33:44:55": {
"compute_name": "compute_name_0",
"baremetal_name": "baremetal_name_0"
},
"11:22:33:44:55:66": {
"compute_name": "compute_name_1",
"baremetal_name": "baremetal_name_1"
},
"aa:bb:cc:dd:ee:ff": {
"compute_name": "compute_name_4",
"baremetal_name": "baremetal_name_4"
},
"bb:cc:dd:ee:ff:gg": {
"compute_name": "compute_name_5",
"baremetal_name": "baremetal_name_5"
}
}
mock_generate_hostmap.return_value = test_hostmap
test_envjson = [{
"name": "control-0",
"pm_password": "control-0-password",
"pm_type": "ipmi",
"pm_user": "control-0-admin",
"pm_addr": "0.1.2.3",
"pm_port": "0123",
"mac": [
"00:11:22:33:44:55"
]
}, {
"name": "control-1",
"pm_password": "control-1-password",
# Still support deprecated drivers
"pm_type": "pxe_ipmitool",
"pm_user": "control-1-admin",
"pm_addr": "1.2.3.4",
"mac": [
"11:22:33:44:55:66"
]
}, {
# test node using redfish pm
"name": "compute-4",
"pm_password": "calvin",
"pm_type": "redfish",
"pm_user": "root",
"pm_addr": "172.16.0.1:8000",
"pm_port": "8000",
"redfish_verify_ca": "false",
"pm_system_id": "/redfish/v1/Systems/5678",
"mac": [
"aa:bb:cc:dd:ee:ff"
]
}, {
# This is an extra node on oVirt/RHV
"name": "control-3",
"pm_password": "ovirt-password",
"pm_type": "staging-ovirt",
"pm_user": "admin@internal",
"pm_addr": "3.4.5.6",
"pm_vm_name": "control-3",
"mac": [
"bb:cc:dd:ee:ff:gg"
]
}, {
# This is an extra node that is not in the hostmap, to ensure we
# cope with unprovisioned nodes
"name": "control-2",
"pm_password": "control-2-password",
"pm_type": "ipmi",
"pm_user": "control-2-admin",
"pm_addr": "2.3.4.5",
"mac": [
"22:33:44:55:66:77"
]
}
]
action = parameters.GenerateFencingParametersAction(test_envjson,
28,
5,
0,
True)
result = action.run(mock_ctx)["parameter_defaults"]
self.assertTrue(result["EnableFencing"])
self.assertEqual(len(result["FencingConfig"]["devices"]), 4)
self.assertEqual(result["FencingConfig"]["devices"][0], {
"agent": "fence_ipmilan",
"host_mac": "00:11:22:33:44:55",
"params": {
"delay": 28,
"ipaddr": "0.1.2.3",
"ipport": "0123",
"lanplus": True,
"privlvl": 5,
"login": "control-0-admin",
"passwd": "control-0-password",
"pcmk_host_list": "compute_name_0"
}
})
self.assertEqual(result["FencingConfig"]["devices"][1], {
"agent": "fence_ipmilan",
"host_mac": "11:22:33:44:55:66",
"params": {
"delay": 28,
"ipaddr": "1.2.3.4",
"lanplus": True,
"privlvl": 5,
"login": "control-1-admin",
"passwd": "control-1-password",
"pcmk_host_list": "compute_name_1"
}
})
self.assertEqual(result["FencingConfig"]["devices"][2], {
"agent": "fence_redfish",
"host_mac": "aa:bb:cc:dd:ee:ff",
"params": {
"delay": 28,
"ipaddr": "172.16.0.1:8000",
"ipport": "8000",
"lanplus": True,
"privlvl": 5,
"login": "root",
"passwd": "calvin",
"systems_uri": "/redfish/v1/Systems/5678",
"ssl_insecure": "true",
"pcmk_host_list": "compute_name_4"
}
})
self.assertEqual(result["FencingConfig"]["devices"][3], {
"agent": "fence_rhevm",
"host_mac": "bb:cc:dd:ee:ff:gg",
"params": {
"delay": 28,
"ipaddr": "3.4.5.6",
"login": "admin@internal",
"passwd": "ovirt-password",
"port": "control-3",
"ssl": 1,
"ssl_insecure": 1,
"pcmk_host_list": "compute_name_5"
}
})
class GetFlattenedParametersActionTest(base.TestCase):
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_get')
@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_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_empty_resource_tree(self, mock_get_object_client,
mock_get_orchestration_client,
mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
mock_cache_get.return_value = None
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
mock_process_multiple_environments_and_files.return_value = ({}, {})
mock_heat = mock.MagicMock()
mock_get_orchestration_client.return_value = mock_heat
mock_heat.stacks.validate.return_value = {}
expected_value = {
'heat_resource_tree': {},
'environment_parameters': None,
}
# Test
action = parameters.GetFlattenedParametersAction()
result = action.run(mock_ctx)
mock_heat.stacks.validate.assert_called_once_with(
environment={},
files={},
show_nested=True,
template={'heat_template_version': '2016-04-30'},
)
self.assertEqual(result, expected_value)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_get')
@mock.patch('uuid.uuid4', side_effect=['1', '2'])
@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_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_valid_resource_tree(self, mock_get_object_client,
mock_get_orchestration_client,
mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_uuid,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
mock_cache_get.return_value = None
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
mock_process_multiple_environments_and_files.return_value = ({}, {})
mock_heat = mock.MagicMock()
mock_get_orchestration_client.return_value = mock_heat
mock_heat.stacks.validate.return_value = {
'NestedParameters': {
'CephStorageHostsDeployment': {
'Type': 'OS::Heat::StructuredDeployments',
},
},
'description': 'sample',
'Parameters': {
'ControllerCount': {
'Default': 1,
'Type': 'Number',
},
}
}
expected_value = {
'heat_resource_tree': {
'resources': {
'1': {
'id': '1',
'name': 'Root',
'resources': [
'2'
],
'parameters': [
'ControllerCount'
]
},
'2': {
'id': '2',
'name': 'CephStorageHostsDeployment',
'type': 'OS::Heat::StructuredDeployments'
}
},
'parameters': {
'ControllerCount': {
'default': 1,
'type': 'Number',
'name': 'ControllerCount'
}
},
},
'environment_parameters': None,
}
# Test
action = parameters.GetFlattenedParametersAction()
result = action.run(mock_ctx)
self.assertEqual(result, expected_value)
class GetProfileOfFlavorActionTest(base.TestCase):
@mock.patch('tripleo_common.utils.parameters.get_profile_of_flavor')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_compute_client')
def test_profile_found(self, mock_get_compute_client,
mock_get_profile_of_flavor):
mock_ctx = mock.MagicMock()
mock_get_profile_of_flavor.return_value = 'compute'
action = parameters.GetProfileOfFlavorAction('oooq_compute')
result = action.run(mock_ctx)
expected_result = "compute"
self.assertEqual(result, expected_result)
@mock.patch('tripleo_common.utils.parameters.get_profile_of_flavor')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_compute_client')
def test_profile_not_found(self, mock_get_compute_client,
mock_get_profile_of_flavor):
mock_ctx = mock.MagicMock()
profile = (exception.DeriveParamsError, )
mock_get_profile_of_flavor.side_effect = profile
action = parameters.GetProfileOfFlavorAction('no_profile')
result = action.run(mock_ctx)
self.assertTrue(result.is_error())
mock_get_profile_of_flavor.assert_called_once()
class RotateFernetKeysActionTest(base.TestCase):
def test_get_next_index(self):
action = parameters.RotateFernetKeysAction()
keys_map = {
password_utils.KEYSTONE_FERNET_REPO + '0': {
'content': 'Some key'},
password_utils.KEYSTONE_FERNET_REPO + '1': {
'content': 'Some other key'},
}
next_index = action.get_next_index(keys_map)
self.assertEqual(next_index, 2)
@mock.patch('tripleo_common.utils.passwords.'
'create_keystone_credential')
def test_rotate_keys(self, mock_keystone_creds):
action = parameters.RotateFernetKeysAction()
mock_keystone_creds.return_value = 'Some new key'
staged_key_index = password_utils.KEYSTONE_FERNET_REPO + '0'
new_primary_key_index = password_utils.KEYSTONE_FERNET_REPO + '2'
keys_map = {
password_utils.KEYSTONE_FERNET_REPO + '0': {
'content': 'Some key'},
password_utils.KEYSTONE_FERNET_REPO + '1': {
'content': 'Some other key'},
}
new_keys_map = action.rotate_keys(keys_map, 2)
# Staged key should be the new key
self.assertEqual('Some new key',
new_keys_map[staged_key_index]['content'])
# primary key should be the previous staged key
self.assertEqual('Some key',
new_keys_map[new_primary_key_index]['content'])
def test_purge_excess_keys_should_purge(self):
action = parameters.RotateFernetKeysAction()
keys_map = {
password_utils.KEYSTONE_FERNET_REPO + '0': {
'content': 'key0'},
password_utils.KEYSTONE_FERNET_REPO + '1': {
'content': 'key1'},
password_utils.KEYSTONE_FERNET_REPO + '2': {
'content': 'key2'},
password_utils.KEYSTONE_FERNET_REPO + '3': {
'content': 'key3'},
password_utils.KEYSTONE_FERNET_REPO + '4': {
'content': 'key4'},
}
max_keys = 3
keys_map = action.purge_excess_keys(max_keys, keys_map)
self.assertEqual(max_keys, len(keys_map))
# It should keep index 0, 3 and 4
self.assertIn(password_utils.KEYSTONE_FERNET_REPO + '0', keys_map)
self.assertIn(password_utils.KEYSTONE_FERNET_REPO + '3', keys_map)
self.assertIn(password_utils.KEYSTONE_FERNET_REPO + '4', keys_map)
# It sould have removed index 1 and 2
self.assertNotIn(password_utils.KEYSTONE_FERNET_REPO + '1', keys_map)
self.assertNotIn(password_utils.KEYSTONE_FERNET_REPO + '2', keys_map)
def test_purge_excess_keys_should_not_purge_if_equal_to_max(self):
action = parameters.RotateFernetKeysAction()
keys_map = {
password_utils.KEYSTONE_FERNET_REPO + '0': {
'content': 'key0'},
password_utils.KEYSTONE_FERNET_REPO + '1': {
'content': 'key1'},
password_utils.KEYSTONE_FERNET_REPO + '2': {
'content': 'key2'},
}
max_keys = 3
keys_map = action.purge_excess_keys(max_keys, keys_map)
self.assertEqual(max_keys, len(keys_map))
def test_purge_excess_keys_should_not_purge_if_less_than_max(self):
action = parameters.RotateFernetKeysAction()
keys_map = {
password_utils.KEYSTONE_FERNET_REPO + '0': {
'content': 'key0'},
password_utils.KEYSTONE_FERNET_REPO + '1': {
'content': 'key1'},
}
max_keys = 3
keys_map = action.purge_excess_keys(max_keys, keys_map)
self.assertEqual(2, len(keys_map))
class GetNetworkConfigActionTest(base.TestCase):
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_get')
@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_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_valid_network_config(
self, mock_get_object_client, mock_get_workflow_client,
mock_get_orchestration_client, mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
mock_process_multiple_environments_and_files.return_value = ({}, {})
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"}
}])
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
expected = {"network_config": {}}
# Test
action = parameters.GetNetworkConfigAction(container='overcloud',
role_name='Compute')
result = action.run(mock_ctx)
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment={},
files={},
template={'heat_template_version': '2016-04-30'},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_get')
@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_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_valid_network_config_with_no_interface_routes_inputs(
self, mock_get_object_client, mock_get_workflow_client,
mock_get_orchestration_client, mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30',
'resources': {'ComputeGroupVars': {'properties': {
'value': {'role_networks': ['InternalApi', 'Storage']}
}
}}
})
mock_process_multiple_environments_and_files.return_value = (
{}, {'parameter_defaults': {}})
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"
" > /etc/os-net-config/config.json"}
}])
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
expected = {"network_config": {}}
# Test
action = parameters.GetNetworkConfigAction(container='overcloud',
role_name='Compute')
result = action.run(mock_ctx)
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment={'parameter_defaults': {
'InternalApiInterfaceRoutes': [[]],
'StorageInterfaceRoutes': [[]]}},
files={},
template={'heat_template_version': '2016-04-30',
'resources': {'ComputeGroupVars': {
'properties': {'value': {
'role_networks': ['InternalApi',
'Storage']}}}}},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_get')
@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_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_valid_network_config_with_interface_routes_inputs(
self, mock_get_object_client, mock_get_workflow_client,
mock_get_orchestration_client, mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30',
'resources': {'ComputeGroupVars': {'properties': {
'value': {'role_networks': ['InternalApi', 'Storage']}}}}
})
mock_process_multiple_environments_and_files.return_value = (
{}, {'parameter_defaults': {
'InternalApiInterfaceRoutes': ['test1'],
'StorageInterfaceRoutes': ['test2']}})
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"
" > /etc/os-net-config/config.json"}
}])
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
expected = {"network_config": {}}
# Test
action = parameters.GetNetworkConfigAction(container='overcloud',
role_name='Compute')
result = action.run(mock_ctx)
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment={'parameter_defaults': {
'InternalApiInterfaceRoutes': ['test1'],
'StorageInterfaceRoutes': ['test2']}},
files={},
template={'heat_template_version': '2016-04-30',
'resources': {'ComputeGroupVars': {'properties': {
'value': {'role_networks': ['InternalApi',
'Storage']}}}}},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_set')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'cache_get')
@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_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_invalid_network_config(
self, mock_get_object_client,
mock_get_workflow_client, mock_get_orchestration_client,
mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get, mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
mock_process_multiple_environments_and_files.return_value = ({}, {})
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": ""}
}])
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
# Test
action = parameters.GetNetworkConfigAction(container='overcloud',
role_name='Compute')
result = action.run(mock_ctx)
self.assertTrue(result.is_error())
mock_heat.stacks.preview.assert_called_once_with(
environment={},
files={},
template={'heat_template_version': '2016-04-30'},
stack_name='overcloud-TEMP',
)