Merge "Move tests to tripleo deploy"

This commit is contained in:
Zuul 2018-05-02 03:32:42 +00:00 committed by Gerrit Code Review
commit 8b1803de14
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
@ -973,3 +979,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,