Move tests to tripleo deploy

After refactoring the deployment command, the tests should be migrated
to the tripleo deploy command tests. Additionally some of the utility
functions have been moved to tripleoclient.utils.

Change-Id: I48b77a4c91412a0fba9a78bc5fe5f81d8962ac18
Related-Blueprint: all-in-one
This commit is contained in:
Alex Schultz 2018-04-27 14:43:16 -06:00
parent cad736b6ea
commit f335b9e040
4 changed files with 454 additions and 508 deletions

View File

@ -14,7 +14,11 @@
#
import mock
import os
import tempfile
import yaml
from heatclient import exc as hc_exc
from tripleo_common.image import kolla_builder
from tripleoclient import exceptions
@ -55,9 +59,372 @@ class TestDeployUndercloud(TestPluginV1):
self.orc.stacks.create = mock.MagicMock(
return_value={'stack': {'id': 'foo'}})
def test_take_action_standalone(self):
"""This is currently handled by undercloud_deploy tests"""
pass
@mock.patch('os.chmod')
@mock.patch('os.path.exists')
@mock.patch('tripleo_common.utils.passwords.generate_passwords')
@mock.patch('yaml.safe_dump')
def test_update_passwords_env_init(self, mock_dump, mock_pw,
mock_exists, mock_chmod):
pw_dict = {"GeneratedPassword": 123}
pw_conf_path = os.path.join(self.temp_homedir,
'undercloud-passwords.conf')
t_pw_conf_path = os.path.join(
self.temp_homedir, 'tripleo-undercloud-passwords.yaml')
mock_pw.return_value = pw_dict
mock_exists.return_value = False
mock_open_context = mock.mock_open()
with mock.patch('six.moves.builtins.open', mock_open_context):
self.cmd._update_passwords_env(self.temp_homedir)
mock_open_handle = mock_open_context()
mock_dump.assert_called_once_with({'parameter_defaults': pw_dict},
mock_open_handle,
default_flow_style=False)
chmod_calls = [mock.call(t_pw_conf_path, 0o600),
mock.call(pw_conf_path, 0o600)]
mock_chmod.assert_has_calls(chmod_calls)
@mock.patch('os.chmod')
@mock.patch('os.path.exists')
@mock.patch('tripleo_common.utils.passwords.generate_passwords')
@mock.patch('yaml.safe_dump')
def test_update_passwords_env_update(self, mock_dump, mock_pw,
mock_exists, mock_chmod):
pw_dict = {"GeneratedPassword": 123}
pw_conf_path = os.path.join(self.temp_homedir,
'undercloud-passwords.conf')
t_pw_conf_path = os.path.join(
self.temp_homedir, 'tripleo-undercloud-passwords.yaml')
mock_pw.return_value = pw_dict
mock_exists.return_value = True
with open(t_pw_conf_path, 'w') as t_pw:
t_pw.write('parameter_defaults: {ExistingKey: xyz}\n')
with open(pw_conf_path, 'w') as t_pw:
t_pw.write('[auth]\nundercloud_db_password = abc\n')
self.cmd._update_passwords_env(self.temp_homedir,
passwords={'ADefault': 456,
'ExistingKey':
'dontupdate'})
expected_dict = {'parameter_defaults': {'GeneratedPassword': 123,
'ExistingKey': 'xyz',
'MysqlRootPassword': 'abc',
'ADefault': 456}}
mock_dump.assert_called_once_with(expected_dict,
mock.ANY,
default_flow_style=False)
chmod_calls = [mock.call(t_pw_conf_path, 0o600),
mock.call(pw_conf_path, 0o600)]
mock_chmod.assert_has_calls(chmod_calls)
@mock.patch('heatclient.common.template_utils.'
'process_environment_and_files', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.template_utils.'
'get_template_contents', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.environment_format.'
'parse', autospec=True, return_value=dict())
@mock.patch('heatclient.common.template_format.'
'parse', autospec=True, return_value=dict())
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_setup_heat_environments', autospec=True)
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_multi')
def test_deploy_tripleo_heat_templates_redir(self,
mock_cipm,
mock_setup_heat_envs,
mock_hc_templ_parse,
mock_hc_env_parse,
mock_hc_get_templ_cont,
mock_hc_process):
with tempfile.NamedTemporaryFile(delete=False) as roles_file:
self.addCleanup(os.unlink, roles_file.name)
mock_cipm.return_value = {}
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1/8',
'--templates', '/tmp/thtroot',
'--roles-file', roles_file.name], [])
mock_setup_heat_envs.return_value = [
'./inside.yaml', '/tmp/thtroot/abs.yaml',
'/tmp/thtroot/puppet/foo.yaml',
'/tmp/thtroot/environments/myenv.yaml',
'/tmp/thtroot42/notouch.yaml',
'../outside.yaml']
self.cmd._deploy_tripleo_heat_templates(self.orc, parsed_args)
mock_hc_process.assert_has_calls([
mock.call(env_path='./inside.yaml'),
mock.call(env_path='/twd/templates/abs.yaml'),
mock.call(env_path='/twd/templates/puppet/foo.yaml'),
mock.call(env_path='/twd/templates/environments/myenv.yaml'),
mock.call(env_path='/tmp/thtroot42/notouch.yaml'),
mock.call(env_path='../outside.yaml')])
@mock.patch('heatclient.common.template_utils.'
'process_environment_and_files', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.template_utils.'
'get_template_contents', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.environment_format.'
'parse', autospec=True, return_value=dict())
@mock.patch('heatclient.common.template_format.'
'parse', autospec=True, return_value=dict())
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_setup_heat_environments', autospec=True)
@mock.patch('yaml.safe_dump', autospec=True)
@mock.patch('yaml.safe_load', autospec=True)
@mock.patch('six.moves.builtins.open')
@mock.patch('tempfile.NamedTemporaryFile', autospec=True)
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_multi')
def test_deploy_tripleo_heat_templates_rewrite(self,
mock_cipm,
mock_temp, mock_open,
mock_yaml_load,
mock_yaml_dump,
mock_setup_heat_envs,
mock_hc_templ_parse,
mock_hc_env_parse,
mock_hc_get_templ_cont,
mock_hc_process):
def hc_process(*args, **kwargs):
if 'abs.yaml' in kwargs['env_path']:
raise hc_exc.CommandError
else:
return ({}, {})
mock_cipm.return_value = {}
mock_hc_process.side_effect = hc_process
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1/8',
'--templates', '/tmp/thtroot'], [])
rewritten_env = {'resource_registry': {
'OS::Foo::Bar': '/twd/outside.yaml',
'OS::Foo::Baz': '/twd/templates/inside.yaml',
'OS::Foo::Qux': '/twd/templates/abs.yaml',
'OS::Foo::Quux': '/tmp/thtroot42/notouch.yaml',
'OS::Foo::Corge': '/twd/templates/puppet/foo.yaml'
}
}
myenv = {'resource_registry': {
'OS::Foo::Bar': '../outside.yaml',
'OS::Foo::Baz': './inside.yaml',
'OS::Foo::Qux': '/tmp/thtroot/abs.yaml',
'OS::Foo::Quux': '/tmp/thtroot42/notouch.yaml',
'OS::Foo::Corge': '/tmp/thtroot/puppet/foo.yaml'
}
}
mock_yaml_load.return_value = myenv
mock_setup_heat_envs.return_value = [
'./inside.yaml', '/tmp/thtroot/abs.yaml',
'/tmp/thtroot/puppet/foo.yaml',
'/tmp/thtroot/environments/myenv.yaml',
'../outside.yaml']
self.cmd._deploy_tripleo_heat_templates(self.orc, parsed_args)
mock_yaml_dump.assert_has_calls([mock.call(rewritten_env,
default_flow_style=False)])
@mock.patch('heatclient.common.template_utils.'
'process_environment_and_files', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.template_utils.'
'get_template_contents', return_value=({}, {}),
autospec=True)
@mock.patch('tripleoclient.utils.'
'process_multiple_environments', autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_process_hieradata_overrides', return_value='foo.yaml',
autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_update_passwords_env', autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_run_and_log_output', autospec=True)
@mock.patch('tempfile.mkdtemp', autospec=True, return_value='/twd')
@mock.patch('shutil.copytree', autospec=True)
def test_setup_heat_environments(self,
mock_copy,
mock_mktemp,
mock_run,
mock_update_pass_env,
mock_process_hiera,
mock_process_multiple_environments,
mock_hc_get_templ_cont,
mock_hc_process):
mock_run.return_value = 0
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1/8',
'--templates', '/tmp/thtroot',
'--output-dir', '/my',
'--hieradata-override',
'legacy.yaml',
'-e',
'/tmp/thtroot/puppet/foo.yaml',
'-e',
'/tmp/thtroot//docker/bar.yaml',
'-e',
'/tmp/thtroot42/notouch.yaml',
'-e', '~/custom.yaml',
'-e', 'something.yaml',
'-e', '../../../outside.yaml'], [])
expected_env = [
'/twd/templates/overcloud-resource-registry-puppet.yaml',
mock.ANY,
'/twd/templates/environments/undercloud.yaml',
'/twd/templates/environments/config-download-environment.yaml',
'/twd/templates/environments/deployed-server-noop-ctlplane.yaml',
'/tmp/thtroot/puppet/foo.yaml',
'/tmp/thtroot//docker/bar.yaml',
'/tmp/thtroot42/notouch.yaml',
'~/custom.yaml',
'something.yaml',
'../../../outside.yaml',
mock.ANY, 'foo.yaml']
environment = self.cmd._setup_heat_environments(parsed_args)
self.assertEqual(environment, expected_env)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_working_dirs', autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.TripleoInventory',
autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_launch_heat', autospec=True)
@mock.patch('tripleo_common.utils.config.Config',
autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.sys.stdout.flush')
@mock.patch('os.path.join', return_value='/twd/inventory.yaml')
def test_download_ansible_playbooks(self, mock_join, mock_flush,
mock_stack_config, mock_launch_heat,
mock_importInv, createdir_mock):
fake_output_dir = '/twd'
extra_vars = {'Undercloud': {'ansible_connection': 'local'}}
mock_inventory = mock.Mock()
mock_importInv.return_value = mock_inventory
self.cmd.output_dir = fake_output_dir
self.cmd._download_ansible_playbooks(mock_launch_heat,
'undercloud')
self.assertEqual(mock_flush.call_count, 2)
mock_inventory.write_static_inventory.assert_called_once_with(
fake_output_dir + '/inventory.yaml', extra_vars)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_run_and_log_output', autospec=True)
@mock.patch('os.chdir')
@mock.patch('os.execvp')
def test_launch_ansible(self, mock_execvp, mock_chdir, mock_run):
self.cmd._launch_ansible('/tmp')
mock_chdir.assert_called_once()
mock_run.assert_called_once_with(self.cmd, [
'ansible-playbook', '-i', '/tmp/inventory.yaml',
'deploy_steps_playbook.yaml', '-e', 'role_name=Undercloud',
'-e', 'deploy_server_id=undercloud', '-e',
'bootstrap_server_id=undercloud'])
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_multi')
def test_prepare_container_images(self, mock_cipm):
env = {'parameter_defaults': {}}
mock_cipm.return_value = {'FooImage': 'foo/bar:baz'}
with tempfile.NamedTemporaryFile(mode='w') as roles_file:
yaml.dump([{'name': 'Compute'}], roles_file)
self.cmd._prepare_container_images(env, roles_file.name)
mock_cipm.assert_called_once_with(
env,
[{'name': 'Compute'}]
)
self.assertEqual(
{
'parameter_defaults': {
'FooImage': 'foo/bar:baz'
}
},
env
)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_install_artifact', return_value='/tmp/foo.tar.bzip2')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_launch_ansible')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_cleanup_working_dirs')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_working_dirs')
@mock.patch('tripleoclient.utils.wait_api_port_ready',
autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_deploy_tripleo_heat_templates', autospec=True,
return_value='undercloud, 0')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_download_ansible_playbooks', autospec=True,
return_value='/foo')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_launch_heat')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_kill_heat')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_configure_puppet')
@mock.patch('os.geteuid', return_value=0)
@mock.patch('os.environ', return_value='CREATE_COMPLETE')
@mock.patch('tripleoclient.v1.tripleo_deploy.'
'event_utils.poll_for_events',
return_value=('CREATE_COMPLETE', 0))
def test_take_action_standalone(self, mock_poll, mock_environ,
mock_geteuid, mock_puppet, mock_killheat,
mock_launchheat, mock_download, mock_tht,
mock_wait_for_port, mock_createdirs,
mock_cleanupdirs, mock_launchansible,
mock_tarball):
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1',
'--templates', '/tmp/thtroot',
'--stack', 'undercloud',
'--output-dir', '/my',
'-e', '/tmp/thtroot/puppet/foo.yaml',
'-e', '/tmp/thtroot//docker/bar.yaml',
'-e', '/tmp/thtroot42/notouch.yaml',
'-e', '~/custom.yaml',
'-e', 'something.yaml',
'-e', '../../../outside.yaml',
'--standalone'], [])
fake_orchestration = mock_launchheat(parsed_args)
self.cmd.take_action(parsed_args)
mock_createdirs.assert_called_once()
mock_puppet.assert_called_once()
mock_launchheat.assert_called_with(parsed_args)
mock_tht.assert_called_once_with(self.cmd, fake_orchestration,
parsed_args)
mock_download.assert_called_with(self.cmd, fake_orchestration,
'undercloud')
mock_launchansible.assert_called_once()
mock_tarball.assert_called_once()
mock_cleanupdirs.assert_called_once()
self.assertEqual(mock_killheat.call_count, 2)
def test_take_action(self):
parsed_args = self.check_parser(self.cmd,

View File

@ -14,31 +14,14 @@
#
import mock
import os
import tempfile
import yaml
from heatclient import exc as hc_exc
from tripleo_common.image import kolla_builder
from tripleoclient import exceptions
from tripleoclient.tests.v1.test_plugin import TestPluginV1
from osc_lib.tests import utils
# Load the plugin init module for the plugin list and show commands
from tripleoclient.v1 import undercloud_deploy
# TODO(sbaker) Remove after a tripleo-common release contains this new function
if not hasattr(kolla_builder, 'container_images_prepare_multi'):
setattr(kolla_builder, 'container_images_prepare_multi', mock.Mock())
class FakePluginV1Client(object):
def __init__(self, **kwargs):
self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint']
class TestDeployUndercloud(TestPluginV1):
class TestDeployUndercloud(utils.TestCommand):
def setUp(self):
super(TestDeployUndercloud, self).setUp()
@ -46,331 +29,9 @@ class TestDeployUndercloud(TestPluginV1):
# Get the command object to test
self.cmd = undercloud_deploy.DeployUndercloud(self.app, None)
undercloud_deploy.DeployUndercloud.heat_pid = mock.MagicMock(
return_value=False)
undercloud_deploy.DeployUndercloud.tht_render = '/twd/templates'
undercloud_deploy.DeployUndercloud.tmp_env_dir = '/twd'
undercloud_deploy.DeployUndercloud.tmp_env_file_name = 'tmp/foo'
undercloud_deploy.DeployUndercloud.heat_launch = mock.MagicMock(
side_effect=(lambda *x, **y: None))
self.tc = self.app.client_manager.tripleoclient = mock.MagicMock()
self.orc = self.tc.local_orchestration = mock.MagicMock()
self.orc.stacks.create = mock.MagicMock(
return_value={'stack': {'id': 'foo'}})
@mock.patch('os.chmod')
@mock.patch('os.path.exists')
@mock.patch('tripleo_common.utils.passwords.generate_passwords')
@mock.patch('yaml.safe_dump')
def test_update_passwords_env_init(self, mock_dump, mock_pw,
mock_exists, mock_chmod):
pw_dict = {"GeneratedPassword": 123}
pw_conf_path = os.path.join(self.temp_homedir,
'undercloud-passwords.conf')
t_pw_conf_path = os.path.join(
self.temp_homedir, 'tripleo-undercloud-passwords.yaml')
mock_pw.return_value = pw_dict
mock_exists.return_value = False
mock_open_context = mock.mock_open()
with mock.patch('six.moves.builtins.open', mock_open_context):
self.cmd._update_passwords_env(self.temp_homedir)
mock_open_handle = mock_open_context()
mock_dump.assert_called_once_with({'parameter_defaults': pw_dict},
mock_open_handle,
default_flow_style=False)
chmod_calls = [mock.call(t_pw_conf_path, 0o600),
mock.call(pw_conf_path, 0o600)]
mock_chmod.assert_has_calls(chmod_calls)
@mock.patch('os.chmod')
@mock.patch('os.path.exists')
@mock.patch('tripleo_common.utils.passwords.generate_passwords')
@mock.patch('yaml.safe_dump')
def test_update_passwords_env_update(self, mock_dump, mock_pw,
mock_exists, mock_chmod):
pw_dict = {"GeneratedPassword": 123}
pw_conf_path = os.path.join(self.temp_homedir,
'undercloud-passwords.conf')
t_pw_conf_path = os.path.join(
self.temp_homedir, 'tripleo-undercloud-passwords.yaml')
mock_pw.return_value = pw_dict
mock_exists.return_value = True
with open(t_pw_conf_path, 'w') as t_pw:
t_pw.write('parameter_defaults: {ExistingKey: xyz}\n')
with open(pw_conf_path, 'w') as t_pw:
t_pw.write('[auth]\nundercloud_db_password = abc\n')
self.cmd._update_passwords_env(self.temp_homedir,
passwords={'ADefault': 456,
'ExistingKey':
'dontupdate'})
expected_dict = {'parameter_defaults': {'GeneratedPassword': 123,
'ExistingKey': 'xyz',
'MysqlRootPassword': 'abc',
'ADefault': 456}}
mock_dump.assert_called_once_with(expected_dict,
mock.ANY,
default_flow_style=False)
chmod_calls = [mock.call(t_pw_conf_path, 0o600),
mock.call(pw_conf_path, 0o600)]
mock_chmod.assert_has_calls(chmod_calls)
@mock.patch('heatclient.common.template_utils.'
'process_environment_and_files', return_value=({}, {}),
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.take_action',
autospec=True)
@mock.patch('heatclient.common.template_utils.'
'get_template_contents', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.environment_format.'
'parse', autospec=True, return_value=dict())
@mock.patch('heatclient.common.template_format.'
'parse', autospec=True, return_value=dict())
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_setup_heat_environments', autospec=True)
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_multi')
def test_deploy_tripleo_heat_templates_redir(self,
mock_cipm,
mock_setup_heat_envs,
mock_hc_templ_parse,
mock_hc_env_parse,
mock_hc_get_templ_cont,
mock_hc_process):
with tempfile.NamedTemporaryFile(delete=False) as roles_file:
self.addCleanup(os.unlink, roles_file.name)
mock_cipm.return_value = {}
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1/8',
'--templates', '/tmp/thtroot',
'--roles-file', roles_file.name], [])
mock_setup_heat_envs.return_value = [
'./inside.yaml', '/tmp/thtroot/abs.yaml',
'/tmp/thtroot/puppet/foo.yaml',
'/tmp/thtroot/environments/myenv.yaml',
'/tmp/thtroot42/notouch.yaml',
'../outside.yaml']
self.cmd._deploy_tripleo_heat_templates(self.orc, parsed_args)
mock_hc_process.assert_has_calls([
mock.call(env_path='./inside.yaml'),
mock.call(env_path='/twd/templates/abs.yaml'),
mock.call(env_path='/twd/templates/puppet/foo.yaml'),
mock.call(env_path='/twd/templates/environments/myenv.yaml'),
mock.call(env_path='/tmp/thtroot42/notouch.yaml'),
mock.call(env_path='../outside.yaml')])
@mock.patch('heatclient.common.template_utils.'
'process_environment_and_files', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.template_utils.'
'get_template_contents', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.environment_format.'
'parse', autospec=True, return_value=dict())
@mock.patch('heatclient.common.template_format.'
'parse', autospec=True, return_value=dict())
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_setup_heat_environments', autospec=True)
@mock.patch('yaml.safe_dump', autospec=True)
@mock.patch('yaml.safe_load', autospec=True)
@mock.patch('six.moves.builtins.open')
@mock.patch('tempfile.NamedTemporaryFile', autospec=True)
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_multi')
def test_deploy_tripleo_heat_templates_rewrite(self,
mock_cipm,
mock_temp, mock_open,
mock_yaml_load,
mock_yaml_dump,
mock_setup_heat_envs,
mock_hc_templ_parse,
mock_hc_env_parse,
mock_hc_get_templ_cont,
mock_hc_process):
def hc_process(*args, **kwargs):
if 'abs.yaml' in kwargs['env_path']:
raise hc_exc.CommandError
else:
return ({}, {})
mock_cipm.return_value = {}
mock_hc_process.side_effect = hc_process
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1/8',
'--templates', '/tmp/thtroot'], [])
rewritten_env = {'resource_registry': {
'OS::Foo::Bar': '/twd/outside.yaml',
'OS::Foo::Baz': '/twd/templates/inside.yaml',
'OS::Foo::Qux': '/twd/templates/abs.yaml',
'OS::Foo::Quux': '/tmp/thtroot42/notouch.yaml',
'OS::Foo::Corge': '/twd/templates/puppet/foo.yaml'
}
}
myenv = {'resource_registry': {
'OS::Foo::Bar': '../outside.yaml',
'OS::Foo::Baz': './inside.yaml',
'OS::Foo::Qux': '/tmp/thtroot/abs.yaml',
'OS::Foo::Quux': '/tmp/thtroot42/notouch.yaml',
'OS::Foo::Corge': '/tmp/thtroot/puppet/foo.yaml'
}
}
mock_yaml_load.return_value = myenv
mock_setup_heat_envs.return_value = [
'./inside.yaml', '/tmp/thtroot/abs.yaml',
'/tmp/thtroot/puppet/foo.yaml',
'/tmp/thtroot/environments/myenv.yaml',
'../outside.yaml']
self.cmd._deploy_tripleo_heat_templates(self.orc, parsed_args)
mock_yaml_dump.assert_has_calls([mock.call(rewritten_env,
default_flow_style=False)])
@mock.patch('heatclient.common.template_utils.'
'process_environment_and_files', return_value=({}, {}),
autospec=True)
@mock.patch('heatclient.common.template_utils.'
'get_template_contents', return_value=({}, {}),
autospec=True)
@mock.patch('tripleoclient.utils.'
'process_multiple_environments', autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_process_hieradata_overrides', return_value='foo.yaml',
autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_update_passwords_env', autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_run_and_log_output', autospec=True)
@mock.patch('tempfile.mkdtemp', autospec=True, return_value='/twd')
@mock.patch('shutil.copytree', autospec=True)
def test_setup_heat_environments(self,
mock_copy,
mock_mktemp,
mock_run,
mock_update_pass_env,
mock_process_hiera,
mock_process_multiple_environments,
mock_hc_get_templ_cont,
mock_hc_process):
mock_run.return_value = 0
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1/8',
'--templates', '/tmp/thtroot',
'--output-dir', '/my',
'--hieradata-override', 'legacy.yaml',
'-e', '/tmp/thtroot/puppet/foo.yaml',
'-e', '/tmp/thtroot//docker/bar.yaml',
'-e', '/tmp/thtroot42/notouch.yaml',
'-e', '~/custom.yaml',
'-e', 'something.yaml',
'-e', '../../../outside.yaml'], [])
expected_env = [
'/twd/templates/overcloud-resource-registry-puppet.yaml',
mock.ANY,
'/twd/templates/environments/undercloud.yaml',
'/twd/templates/environments/config-download-environment.yaml',
'/twd/templates/environments/deployed-server-noop-ctlplane.yaml',
'/tmp/thtroot/puppet/foo.yaml',
'/tmp/thtroot//docker/bar.yaml',
'/tmp/thtroot42/notouch.yaml',
'~/custom.yaml',
'something.yaml',
'../../../outside.yaml',
mock.ANY, 'foo.yaml']
environment = self.cmd._setup_heat_environments(parsed_args)
self.assertEqual(environment, expected_env)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_working_dirs', autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.TripleoInventory',
autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_launch_heat', autospec=True)
@mock.patch('tripleo_common.utils.config.Config',
autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.sys.stdout.flush')
@mock.patch('os.path.join', return_value='/twd/inventory.yaml')
def test_download_ansible_playbooks(self, mock_join, mock_flush,
mock_stack_config, mock_launch_heat,
mock_importInv, createdir_mock):
fake_output_dir = '/twd'
extra_vars = {'Undercloud': {'ansible_connection': 'local'}}
mock_inventory = mock.Mock()
mock_importInv.return_value = mock_inventory
self.cmd.output_dir = fake_output_dir
self.cmd._download_ansible_playbooks(mock_launch_heat,
'undercloud')
self.assertEqual(mock_flush.call_count, 2)
mock_inventory.write_static_inventory.assert_called_once_with(
fake_output_dir + '/inventory.yaml', extra_vars)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_run_and_log_output', autospec=True)
@mock.patch('os.chdir')
@mock.patch('os.execvp')
def test_launch_ansible(self, mock_execvp, mock_chdir, mock_run):
self.cmd._launch_ansible('/tmp')
mock_chdir.assert_called_once()
mock_run.assert_called_once_with(self.cmd, [
'ansible-playbook', '-i', '/tmp/inventory.yaml',
'deploy_steps_playbook.yaml', '-e', 'role_name=Undercloud',
'-e', 'deploy_server_id=undercloud', '-e',
'bootstrap_server_id=undercloud'])
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_install_artifact', return_value='/tmp/foo.tar.bzip2')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_launch_ansible')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_cleanup_working_dirs')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_working_dirs')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_wait_local_port_ready', autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_deploy_tripleo_heat_templates', autospec=True,
return_value='undercloud, 0')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_download_ansible_playbooks', autospec=True,
return_value='/foo')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_launch_heat')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_kill_heat')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_configure_puppet')
@mock.patch('os.geteuid', return_value=0)
@mock.patch('os.environ', return_value='CREATE_COMPLETE')
@mock.patch('tripleoclient.v1.tripleo_deploy.'
'event_utils.poll_for_events',
return_value=('CREATE_COMPLETE', 0))
def test_take_action(self, mock_poll, mock_environ, mock_geteuid,
mock_puppet, mock_killheat, mock_launchheat,
mock_download, mock_tht, mock_wait_for_port,
mock_createdirs, mock_cleanupdirs,
mock_launchansible, mock_tarball):
def test_take_action(self, mock_deploy):
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1',
'--templates', '/tmp/thtroot',
@ -382,122 +43,6 @@ class TestDeployUndercloud(TestPluginV1):
'-e', '~/custom.yaml',
'-e', 'something.yaml',
'-e', '../../../outside.yaml'], [])
fake_orchestration = mock_launchheat(parsed_args)
self.cmd.take_action(parsed_args)
mock_createdirs.assert_called_once()
mock_puppet.assert_called_once()
mock_launchheat.assert_called_with(parsed_args)
mock_tht.assert_called_once_with(self.cmd, fake_orchestration,
parsed_args)
mock_download.assert_called_with(self.cmd, fake_orchestration,
'undercloud')
mock_launchansible.assert_called_once()
mock_tarball.assert_called_once()
mock_cleanupdirs.assert_called_once()
self.assertEqual(mock_killheat.call_count, 2)
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_multi')
def test_prepare_container_images(self, mock_cipm):
env = {'parameter_defaults': {}}
mock_cipm.return_value = {'FooImage': 'foo/bar:baz'}
with tempfile.NamedTemporaryFile(mode='w') as roles_file:
yaml.dump([{'name': 'Compute'}], roles_file)
self.cmd._prepare_container_images(env, roles_file.name)
mock_cipm.assert_called_once_with(
env,
[{'name': 'Compute'}]
)
self.assertEqual(
{
'parameter_defaults': {
'FooImage': 'foo/bar:baz'
}
},
env
)
@mock.patch('tempfile.NamedTemporaryFile', autospec=True)
@mock.patch('os.path.exists', return_value=True)
def test_process_hierdata_overrides(self, mock_exists, mock_tmpfile):
data = "foo: bar"
mock_open = mock.mock_open(read_data=data)
with mock.patch('tripleoclient.v1.tripleo_deploy.open', mock_open):
self.assertEqual(mock_tmpfile.return_value.__enter__().name,
self.cmd._process_hieradata_overrides('/foobar'))
@mock.patch('os.path.exists', return_value=False)
def test_process_hierdata_overrides_bad_input(self, mock_exists):
self.assertRaises(exceptions.DeploymentError,
self.cmd._process_hieradata_overrides,
['/tmp/foobar'])
@mock.patch('tempfile.NamedTemporaryFile', autospec=True)
@mock.patch('os.path.exists', return_value=True)
def test_process_hierdata_overrides_tht(self, mock_exists, mock_tmpfile):
data = "parameter_defaults:\n UndercloudExtraConfig:\n foo: bar"
mock_open = mock.mock_open(read_data=data)
with mock.patch('tripleoclient.v1.tripleo_deploy.open', mock_open):
self.assertEqual('/foobar',
self.cmd._process_hieradata_overrides('/foobar'))
@mock.patch('os.waitpid')
def test_kill_heat(self, wait_mock):
self.cmd.heat_pid = 1234
wait_mock.return_value = [0, 0]
parsed_args = self.check_parser(self.cmd, [], [])
self.cmd._kill_heat(parsed_args)
wait_mock.assert_called_once_with(1234, 0)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_get_tar_filename',
return_value='/tmp/undercloud-install-1.tar.bzip2')
@mock.patch('tarfile.open', autospec=True)
def test_create_install_artifact(self, mock_open, mock_filename):
self.cmd.output_dir = '/tmp'
self.cmd.tmp_env_dir = '/tmp/foo'
self.cmd.tmp_env_file_name = '/tmp/bar'
self.cmd.tmp_ansible_dir = '/tmp/baz'
name = self.cmd._create_install_artifact()
self.cmd.output_dir = None
self.cmd.tmp_env_dir = None
self.cmd.tmp_env_file_name = None
self.cmd.tmp_ansible_dir = None
self.assertEqual(name, '/tmp/undercloud-install-1.tar.bzip2')
@mock.patch('tempfile.mkdtemp')
def test_create_working_dirs(self, mock_tempfile):
self.output_dir = None
self.cmd.tmp_ansible_dir = None
self.cmd.tmp_env_dir = None
self.cmd._create_working_dirs()
self.assertEqual(mock_tempfile.call_count, 2)
@mock.patch('os.remove')
@mock.patch('shutil.rmtree')
@mock.patch('os.path.exists', return_value=True)
def test_cleanup_working_dirs(self, mock_exists, mock_rmtree, mock_remove):
self.cmd.tmp_env_dir = '/foo'
self.cmd.tmp_env_file_name = '/bar'
self.cmd.tmp_ansible_dir = '/baz'
self.cmd._cleanup_working_dirs()
self.assertEqual(mock_exists.call_count, 0)
mock_remove.assert_not_called()
self.assertEqual(mock_rmtree.call_count, 0)
@mock.patch('os.remove')
@mock.patch('shutil.rmtree')
@mock.patch('os.path.exists', return_value=True)
def test_cleanup_working_dirs_cleanup(self, mock_exists, mock_rmtree,
mock_remove):
self.cmd.tmp_env_dir = '/foo'
self.cmd.tmp_env_file_name = '/bar'
self.cmd.tmp_ansible_dir = '/baz'
self.cmd._cleanup_working_dirs(True)
self.assertEqual(mock_exists.call_count, 2)
mock_remove.assert_called_once_with('/bar')
self.assertEqual(mock_rmtree.call_count, 2)
parsed_args.standlone = True
mock_deploy.assert_called_with(self.cmd, parsed_args)

View File

@ -20,6 +20,8 @@ import getpass
import glob
import hashlib
import logging
import shutil
import os
import os.path
import simplejson
@ -39,6 +41,10 @@ from oslo_concurrency import processutils
from six.moves import configparser
from heatclient import exc as hc_exc
from six.moves.urllib import error as url_error
from six.moves.urllib import request
from tripleoclient import exceptions
@ -961,3 +967,69 @@ def load_container_registry(log, path):
"to re-run this command and provide the registry file "
"with: --container-registry-file option.")
return registry
def get_short_hostname():
"""Returns the local short hostname
:return string
"""
p = subprocess.Popen(["hostname", "-s"], stdout=subprocess.PIPE)
return p.communicate()[0].rstrip()
def wait_api_port_ready(api_port, host='127.0.0.1'):
"""Wait until an http services becomes available
:param api_port: api service port
:type api_port: integer
:param host: host running the service (default: 127.0.0.1)
:type host: string
:return boolean
"""
count = 0
while count < 30:
time.sleep(1)
count += 1
try:
request.urlopen("http://%s:%s/" % (host, api_port), timeout=1)
except url_error.HTTPError as he:
if he.code == 300:
return True
pass
except url_error.URLError:
pass
return False
def bulk_symlink(log, src, dst, tmpd='/tmp'):
"""Create bulk symlinks from a directory
:param log: logger instance for logging
:type log: Logger
:param src: dir of directories to symlink
:type src: string
:param dst: dir to create the symlinks
:type dst: string
:param tmpd: temporary working directory to use
:type tmp: string
"""
log.debug("Symlinking %s to %s, via temp dir %s" %
(src, dst, tmpd))
try:
tmp = tempfile.mkdtemp(dir=tmpd)
subprocess.check_call(['mkdir', '-p', dst])
os.chmod(tmp, 0o755)
for obj in os.listdir(src):
tmpf = os.path.join(tmp, obj)
os.symlink(os.path.join(src, obj), tmpf)
os.rename(tmpf, os.path.join(dst, obj))
except Exception:
raise
finally:
shutil.rmtree(tmp, ignore_errors=True)

View File

@ -26,7 +26,6 @@ import subprocess
import sys
import tarfile
import tempfile
import time
import traceback
import yaml
@ -36,8 +35,6 @@ from heatclient.common import event_utils
from heatclient.common import template_utils
from openstackclient.i18n import _
from six.moves import configparser
from six.moves.urllib import error as url_error
from six.moves.urllib import request
from tripleoclient import constants
from tripleoclient import exceptions
@ -90,22 +87,6 @@ class Deploy(command.Command):
tmp_env_file_name = None
tmp_ansible_dir = None
def _symlink(self, src, dst, tmpd='/tmp'):
self.log.debug("Symlinking %s to %s, via temp dir %s" %
(src, dst, tmpd))
try:
tmp = tempfile.mkdtemp(dir=tmpd)
subprocess.check_call(['mkdir', '-p', dst])
os.chmod(tmp, 0o755)
for obj in os.listdir(src):
tmpf = os.path.join(tmp, obj)
os.symlink(os.path.join(src, obj), tmpf)
os.rename(tmpf, os.path.join(dst, obj))
except Exception:
raise
finally:
shutil.rmtree(tmp, ignore_errors=True)
def _get_tar_filename(self):
"""Return tarball name for the install artifacts"""
return '%s/undercloud-install-%s.tar.bzip2' % \
@ -179,30 +160,11 @@ class Deploy(command.Command):
self.log.warning("Not cleaning ansible directory %s"
% self.tmp_ansible_dir)
def _get_hostname(self):
p = subprocess.Popen(["hostname", "-s"], stdout=subprocess.PIPE)
return p.communicate()[0].rstrip()
def _configure_puppet(self):
self.log.info('Configuring puppet modules symlinks ...')
self._symlink(constants.TRIPLEO_PUPPET_MODULES,
constants.PUPPET_MODULES,
constants.PUPPET_BASE)
def _wait_local_port_ready(self, api_port):
count = 0
while count < 30:
time.sleep(1)
count += 1
try:
request.urlopen("http://127.0.0.1:%s/" % api_port, timeout=1)
except url_error.HTTPError as he:
if he.code == 300:
return True
pass
except url_error.URLError:
pass
return False
utils.bulk_symlink(self.log, constants.TRIPLEO_PUPPET_MODULES,
constants.PUPPET_MODULES,
constants.PUPPET_BASE)
def _run_and_log_output(self, cmd, cwd=None):
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
@ -280,7 +242,7 @@ class Deploy(command.Command):
return pw_file
def _generate_hosts_parameters(self, parsed_args, p_ip):
hostname = self._get_hostname()
hostname = utils.get_short_hostname()
domain = parsed_args.local_domain
data = {
@ -296,7 +258,7 @@ class Deploy(command.Command):
def _generate_portmap_parameters(self, ip_addr, cidr_prefixlen,
ctlplane_vip_addr, public_vip_addr):
hostname = self._get_hostname()
hostname = utils.get_short_hostname()
data = {
'ControlPlaneSubnetCidr': '%s' % cidr_prefixlen,
@ -767,7 +729,7 @@ class Deploy(command.Command):
# Launch heat.
orchestration_client = self._launch_heat(parsed_args)
# Wait for heat to be ready.
self._wait_local_port_ready(parsed_args.heat_api_port)
utils.wait_api_port_ready(parsed_args.heat_api_port)
# Deploy TripleO Heat templates.
stack_id = \
self._deploy_tripleo_heat_templates(orchestration_client,