Merge "Update HostnameMap generation"

This commit is contained in:
Zuul 2018-05-23 19:46:19 +00:00 committed by Gerrit Code Review
commit 31997572ff
2 changed files with 182 additions and 35 deletions

View File

@ -21,6 +21,7 @@ import yaml
from heatclient import exc as hc_exc
from tripleo_common.image import kolla_builder
from tripleoclient import constants
from tripleoclient import exceptions
from tripleoclient.tests.v1.test_plugin import TestPluginV1
@ -58,6 +59,74 @@ class TestDeployUndercloud(TestPluginV1):
self.orc.stacks.create = mock.MagicMock(
return_value={'stack': {'id': 'foo'}})
@mock.patch('os.path.exists', return_value=True)
def test_set_roles_file(self, mock_exists):
self.cmd._set_roles_file('/foobar.yaml')
self.assertEqual(self.cmd.roles_file, '/foobar.yaml')
@mock.patch('os.path.exists', return_value=False)
def test_set_roles_file_relative(self, mock_exists):
self.cmd._set_roles_file('foobar.yaml',
constants.TRIPLEO_HEAT_TEMPLATES)
self.assertEqual(self.cmd.roles_file,
'/usr/share/openstack-tripleo-heat-templates/'
'foobar.yaml')
def test_get_roles_data(self):
self.cmd.roles_data = [{'name': 'Foobar'}]
self.assertEqual(self.cmd._get_roles_data(),
[{'name': 'Foobar'}])
def test_get_roles_data_from_file(self):
with tempfile.NamedTemporaryFile(mode='w') as roles_file:
yaml.dump([{'name': 'Foobar'}], roles_file)
self.cmd.roles_file = roles_file.name
self.assertEqual(self.cmd._get_roles_data(),
[{'name': 'Foobar'}])
@mock.patch('os.path.exists', return_value=False)
def test_get_roles_data_missing(self, mock_exists):
self.cmd.roles_file = '/tmp/foo.yaml'
self.cmd.roles_data = None
self.assertEqual(self.cmd._get_roles_data(), None)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_get_roles_data')
def test_get_primary_role_name(self, mock_data):
mock_data.return_value = [
{'name': 'Bar'}, {'name': 'Foo', 'tags': ['primary']}
]
self.assertEqual(self.cmd._get_primary_role_name(), 'Foo')
def test_get_primary_role_name_none_defined(self):
self.assertEqual(self.cmd._get_primary_role_name(), 'Controller')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_get_roles_data')
def test_get_primary_role_name_no_primary(self, mock_data):
mock_data.return_value = [{'name': 'Bar'}, {'name': 'Foo'}]
self.assertEqual(self.cmd._get_primary_role_name(), 'Bar')
@mock.patch('os.path.exists', side_effect=[True, False])
@mock.patch('shutil.copytree')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_working_dirs')
def test_populate_templates_dir(self, mock_workingdirs, mock_copy,
mock_exists):
self.cmd.tht_render = '/foo'
self.cmd._populate_templates_dir('/bar')
mock_workingdirs.assert_called_once()
mock_copy.assert_called_once_with('/bar', '/foo', symlinks=True)
@mock.patch('os.path.exists', return_value=False)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_working_dirs')
def test_populate_templates_dir_bad_source(self, mock_workingdirs,
mock_exists):
self.cmd.tht_render = '/foo'
self.assertRaises(exceptions.NotFound,
self.cmd._populate_templates_dir, '/foo')
@mock.patch('os.chmod')
@mock.patch('os.path.exists')
@mock.patch('tripleo_common.utils.passwords.generate_passwords')
@ -240,6 +309,8 @@ class TestDeployUndercloud(TestPluginV1):
mock_yaml_dump.assert_has_calls([mock.call(rewritten_env,
default_flow_style=False)])
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_working_dirs')
@mock.patch('heatclient.common.template_utils.'
'process_environment_and_files', return_value=({}, {}),
autospec=True)
@ -255,21 +326,22 @@ class TestDeployUndercloud(TestPluginV1):
'_update_passwords_env', autospec=True)
@mock.patch('tripleoclient.utils.'
'run_command_and_log', autospec=True)
@mock.patch('tempfile.mkdtemp', autospec=True, return_value='/twd')
@mock.patch('shutil.copytree', autospec=True)
@mock.patch('shutil.copy', autospec=True)
def test_setup_heat_environments(self, mock_cp,
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_hc_process,
mock_createdirs):
mock_run.return_value = 0
# logic handled in _standalone_deploy and _create_working_dirs
self.cmd.output_dir = '/my'
self.cmd.tht_render = '/my/tripleo-heat-installer-templates'
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1/8',
'--templates', '/tmp/thtroot',
@ -344,15 +416,16 @@ class TestDeployUndercloud(TestPluginV1):
'ansible-playbook', '-i', '/tmp/inventory.yaml',
'deploy_steps_playbook.yaml'])
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_get_roles_data')
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_multi')
def test_prepare_container_images(self, mock_cipm):
def test_prepare_container_images(self, mock_cipm, rolesdata_mock):
env = {'parameter_defaults': {}}
mock_cipm.return_value = {'FooImage': 'foo/bar:baz'}
rolesdata_mock.return_value = [{'name': 'Compute'}]
with tempfile.NamedTemporaryFile(mode='w') as roles_file:
yaml.dump([{'name': 'Compute'}], roles_file)
self.cmd._prepare_container_images(env, roles_file.name)
self.cmd._prepare_container_images(env)
mock_cipm.assert_called_once_with(
env,
@ -367,6 +440,8 @@ class TestDeployUndercloud(TestPluginV1):
env
)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_populate_templates_dir')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_install_artifact', return_value='/tmp/foo.tar.bzip2')
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
@ -399,7 +474,7 @@ class TestDeployUndercloud(TestPluginV1):
mock_launchheat, mock_download, mock_tht,
mock_wait_for_port, mock_createdirs,
mock_cleanupdirs, mock_launchansible,
mock_tarball):
mock_tarball, mock_templates_dir):
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1',

View File

@ -83,6 +83,52 @@ class Deploy(command.Command):
output_dir = None
tmp_env_file_name = None
tmp_ansible_dir = None
roles_file = None
roles_data = None
def _set_roles_file(self, file_name=None, templates_dir=None):
"""Set the roles file for the deployment
If the file_name is a full path, it will be used. If the file name
passed in is not a full path, we will join it with the templates
dir and use that instead.
:param file_name: (String) role file name to use, can be relative to
templates directory
:param templates_dir:
"""
if os.path.exists(file_name):
self.roles_file = file_name
else:
self.roles_file = os.path.join(templates_dir, file_name)
def _get_roles_data(self):
"""Load the roles data for deployment"""
# only load once
if self.roles_data:
return self.roles_data
if self.roles_file and os.path.exists(self.roles_file):
with open(self.roles_file) as f:
self.roles_data = yaml.safe_load(f)
elif self.roles_file:
self.log.warning("roles_data '%s' is not found" % self.roles_file)
return self.roles_data
def _get_primary_role_name(self):
"""Return the primary role name"""
roles_data = self._get_roles_data()
if not roles_data:
# TODO(aschultz): should this be Undercloud instead?
return 'Controller'
for r in roles_data:
if 'tags' in r and 'primary' in r['tags']:
return r['name']
self.log.warning('No primary role found in roles_data, using '
'first defined role')
return roles_data[0]['name']
def _get_tar_filename(self):
"""Return tarball name for the install artifacts"""
@ -122,12 +168,35 @@ class Deploy(command.Command):
"""Creates temporary working directories"""
if self.output_dir and not os.path.exists(self.output_dir):
os.mkdir(self.output_dir)
if self.tht_render and not os.path.exists(self.tht_render):
os.mkdir(self.tht_render)
if not self.tht_render:
self.tht_render = os.path.join(self.output_dir,
'tripleo-heat-installer-templates')
# Clear dir since we're using a static name and shutils.copytree
# needs the fodler to not exist. We'll generate the
# contents each time. This should clear the folder on the first
# run of this function.
shutil.rmtree(self.tht_render, ignore_errors=True)
if not self.tmp_ansible_dir:
self.tmp_ansible_dir = tempfile.mkdtemp(
prefix='undercloud-ansible-', dir=self.output_dir)
def _populate_templates_dir(self, source_templates_dir):
"""Creates template dir with templates
* Copy --templates content into a working dir
created as 'output_dir/tripleo-heat-installer-templates'.
:param source_templates_dir: string to a directory containing our
source templates
"""
self._create_working_dirs()
if not os.path.exists(source_templates_dir):
raise exceptions.NotFound("%s template director does not exists" %
source_templates_dir)
if not os.path.exists(self.tht_render):
shutil.copytree(source_templates_dir, self.tht_render,
symlinks=True)
def _cleanup_working_dirs(self, cleanup=False):
"""Cleanup temporary working directories
@ -242,13 +311,18 @@ class Deploy(command.Command):
return data
def _generate_portmap_parameters(self, ip_addr, cidr_prefixlen,
ctlplane_vip_addr, public_vip_addr):
ctlplane_vip_addr, public_vip_addr,
stack_name='Undercloud',
role_name='Undercloud'):
hostname = utils.get_short_hostname()
# in order for deployed server network information to match correctly,
# we need to ensure the HostnameMap matches our hostname
hostname_map_name = "%s-%s-0" % (stack_name.lower(), role_name.lower())
data = {
'ControlPlaneSubnetCidr': '%s' % cidr_prefixlen,
'HostnameMap': {
'undercloud-undercloud-0': '%s' % hostname
hostname_map_name: '%s' % hostname
},
# The settings below allow us to inject a custom public
# VIP. This requires use of the generated
@ -340,8 +414,6 @@ class Deploy(command.Command):
def _setup_heat_environments(self, parsed_args):
"""Process tripleo heat templates with jinja and deploy into work dir
* Copy --templates content into a working dir
created as 'output_dir/tripleo-heat-installer-templates'.
* Process j2/install additional templates there
* Return the environments list for futher processing as a new base.
@ -349,24 +421,22 @@ class Deploy(command.Command):
overcloud-resource-registry-puppet.yaml and passwords files.
"""
self.tht_render = os.path.join(os.path.abspath(parsed_args.output_dir),
'tripleo-heat-installer-templates')
# The target should not exist, bear in mind consequent deploys.
# But we need to copy in the env files generated by undercloud_config
# in the current deployment executed, like undercloud_parameters.yaml.
shutil.rmtree(self.tht_render, ignore_errors=True)
shutil.copytree(parsed_args.templates, self.tht_render, symlinks=True)
# TODO(aschultz): This probably needs to get thought about because
# we likely need to do this for any environment file that gets passed
# in the deploy. This file breaks the seperation between standalone
# and undercloud deployment so we need to not hardcode
# undercloud_parameters.yaml
shutil.copy(os.path.join(os.path.abspath(parsed_args.output_dir),
'tripleo-config-generated-env-files',
'undercloud_parameters.yaml'),
self.tht_render)
# generate jinja templates by its work dir location
self.log.debug(_("Using roles file %s") % parsed_args.roles_file)
self.log.debug(_("Using roles file %s") % self.roles_file)
process_templates = os.path.join(parsed_args.templates,
'tools/process-templates.py')
args = ['python', process_templates, '--roles-data',
parsed_args.roles_file, '--output-dir', self.tht_render]
self.roles_file, '--output-dir', self.tht_render]
if utils.run_command_and_log(self.log, args, cwd=self.tht_render) != 0:
# TODO(aschultz): improve error messaging
msg = _("Problems generating templates.")
@ -425,7 +495,8 @@ class Deploy(command.Command):
tmp_env = self._generate_hosts_parameters(parsed_args, p_ip)
tmp_env.update(self._generate_portmap_parameters(
ip, cidr_prefixlen, c_ip, p_ip))
ip, cidr_prefixlen, c_ip, p_ip, stack_name=parsed_args.stack,
role_name=self._get_primary_role_name()))
with open(self.tmp_env_file_name, 'w') as env_file:
yaml.safe_dump({'parameter_defaults': tmp_env}, env_file,
@ -438,12 +509,8 @@ class Deploy(command.Command):
return environments
def _prepare_container_images(self, env, roles_file):
if roles_file:
with open(roles_file) as f:
roles_data = yaml.safe_load(f)
else:
roles_data = None
def _prepare_container_images(self, env):
roles_data = self._get_roles_data()
image_params = kolla_builder.container_images_prepare_multi(
env, roles_data)
@ -467,9 +534,7 @@ class Deploy(command.Command):
environments, self.tht_render, parsed_args.templates,
cleanup=parsed_args.cleanup)
roles_file = os.path.join(
self.tht_render, parsed_args.roles_file)
self._prepare_container_images(env, roles_file)
self._prepare_container_images(env)
self.log.debug(_("Getting template contents"))
template_path = os.path.join(self.tht_render, 'overcloud.yaml')
@ -735,6 +800,13 @@ class Deploy(command.Command):
# configure puppet
self._configure_puppet()
# copy the templates dir in place
self._populate_templates_dir(parsed_args.templates)
# configure our roles data
self._set_roles_file(parsed_args.roles_file, self.tht_render)
self._get_roles_data()
rc = 1
try:
# Launch heat.