tripleo deploy accept plan environment

This enables passing a different plan environment file, and also
avoids hard-coded references to some of the environment files
such as the overcloud-resource-registry-puppet.yaml which we may
want to rename to enable plans per application e.g openstack,
openshift, ceph standalone etc in future.

This also aligns better with the overcloud deploy command.

Change-Id: I61763f62c5d44f098ad60f9426871caef16cd6de
This commit is contained in:
Steven Hardy 2018-06-08 14:37:22 +01:00
parent d3106dbd99
commit bfaefda0f1
3 changed files with 85 additions and 52 deletions

View File

@ -13,6 +13,7 @@
# under the License.
#
import fixtures
import mock
import os
import tempfile
@ -362,9 +363,6 @@ class TestDeployUndercloud(TestPluginV1):
env_files)
self.assertEqual(expected, results)
@mock.patch('os.path.exists', return_value=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)
@ -374,68 +372,80 @@ class TestDeployUndercloud(TestPluginV1):
@mock.patch('tripleoclient.utils.'
'process_multiple_environments', autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_process_hieradata_overrides', return_value='foo.yaml',
'_process_hieradata_overrides', return_value='hiera_or.yaml',
autospec=True)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_update_passwords_env', autospec=True)
@mock.patch('tripleoclient.utils.'
'run_command_and_log', autospec=True)
@mock.patch('six.moves.builtins.open')
@mock.patch('shutil.copy', autospec=True)
def test_setup_heat_environments(self, mock_cp, mock_open,
def test_setup_heat_environments(self,
mock_run,
mock_update_pass_env,
mock_process_hiera,
mock_process_multiple_environments,
mock_hc_get_templ_cont,
mock_hc_process,
mock_createdirs,
mock_exists):
mock_hc_process):
mock_update_pass_env.return_value = '/my/tripleo-heat-installer-' \
'templates/passwords.yaml'
tmpdir = self.useFixture(fixtures.TempDir()).path
tht_from = os.path.join(tmpdir, 'tht-from')
os.mkdir(tht_from)
tht_outside = os.path.join(tmpdir, 'tht-outside')
os.mkdir(tht_outside)
tht_to = os.path.join(tmpdir, 'tht-to')
os.mkdir(tht_to)
plan_env_path = os.path.join(tht_from, 'plan-environment.yaml')
with open(plan_env_path, mode='w') as plan_file:
yaml.dump({'environments': [{'path': 'env.yaml'}]}, plan_file)
self.assertTrue(os.path.exists(plan_env_path))
with open(os.path.join(tht_from, 'env.yaml'),
mode='w') as env_file:
yaml.dump({}, env_file)
with open(os.path.join(tht_from, 'foo.yaml'),
mode='w') as env_file:
yaml.dump({}, env_file)
with open(os.path.join(tht_outside, 'outside.yaml'),
mode='w') as env_file:
yaml.dump({}, env_file)
tht_render = os.path.join(tht_to, 'tripleo-heat-installer-templates')
mock_update_pass_env.return_value = os.path.join(
tht_render, 'passwords.yaml')
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'
# logic handled in _standalone_deploy
self.cmd.output_dir = tht_to
# Note we don't create tht_render as _populate_templates_dir creates it
self.cmd.tht_render = tht_render
self.cmd._populate_templates_dir(tht_from)
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1/8',
'--templates', '/tmp/thtroot',
'--output-dir', '/my',
'--templates', tht_from,
'--output-dir', tht_to,
'--hieradata-override',
'legacy.yaml',
'-e',
'/tmp/thtroot/puppet/foo.yaml',
os.path.join(tht_from, 'foo.yaml'),
'-e',
'/tmp/thtroot//docker/bar.yaml',
'-e',
'/tmp/thtroot42/notouch.yaml',
'-e', '~/custom.yaml',
'-e', 'something.yaml',
'-e', '../../../outside.yaml'], [])
os.path.join(tht_outside,
'outside.yaml'),
], [])
expected_env = [
'/my/tripleo-heat-installer-templates/'
'overcloud-resource-registry-puppet.yaml',
'/my/tripleo-heat-installer-templates/passwords.yaml',
'/my/tripleo-heat-installer-templates/'
'environments/config-download-environment.yaml',
'/my/tripleo-heat-installer-templates/'
'environments/deployed-server-noop-ctlplane.yaml',
'/my/tripleo-heat-installer-templates/'
'tripleoclient-hosts-portmaps.yaml',
'/my/tripleo-heat-installer-templates/puppet/foo.yaml',
'/my/tripleo-heat-installer-templates//docker/bar.yaml',
'/my/tripleo-heat-installer-templates/notouch.yaml',
'/my/tripleo-heat-installer-templates/custom.yaml',
'/my/tripleo-heat-installer-templates/something.yaml',
'/my/tripleo-heat-installer-templates/outside.yaml',
'foo.yaml']
os.path.join(tht_render, 'env.yaml'),
os.path.join(tht_render, 'passwords.yaml'),
os.path.join(tht_render,
'environments/config-download-environment.yaml'),
os.path.join(tht_render,
'environments/deployed-server-noop-ctlplane.yaml'),
os.path.join(tht_render,
'tripleoclient-hosts-portmaps.yaml'),
'hiera_or.yaml',
os.path.join(tht_render, 'foo.yaml'),
os.path.join(tht_render, 'outside.yaml')]
environment = self.cmd._setup_heat_environments(parsed_args)
self.assertEqual(environment, expected_env)
self.assertEqual(expected_env, environment)
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_create_working_dirs', autospec=True)

View File

@ -1139,3 +1139,14 @@ def build_prepare_env(environment_files, environment_directories):
object_request=get_env_file))
return env
def rel_or_abs_path(tht_root, file_path):
'''Find a file, either absolute path or relative to the t-h-t dir'''
path = os.path.abspath(file_path)
if not os.path.exists(path):
path = os.path.abspath(os.path.join(tht_root, file_path))
if not os.path.exists(path):
raise exceptions.DeploymentError(
"Can't find path %s %s" % (file_path, path))
return path

View File

@ -464,13 +464,14 @@ class Deploy(command.Command):
# TODO(aschultz): in overcloud deploy we have a --environments-dir
# we might want to handle something similar for this
# (shardy) alternatively perhaps we should rely on the plan-environment
# environments list instead?
if parsed_args.environment_files:
env_files.extend(parsed_args.environment_files)
# ensure any user provided templates get copied into tht_render
environments = self._normalize_user_templates(parsed_args.templates,
self.tht_render,
env_files)
user_environments = self._normalize_user_templates(
parsed_args.templates, self.tht_render, env_files)
# generate jinja templates by its work dir location
self.log.debug(_("Using roles file %s") % self.roles_file)
@ -487,25 +488,30 @@ class Deploy(command.Command):
# NOTE(aschultz): the next set of environment files are system included
# so we have to include them at the front of our environment list so a
# user can override anything in them.
resource_registry_path = os.path.join(
self.tht_render, 'overcloud-resource-registry-puppet.yaml')
environments.insert(0, resource_registry_path)
# Include any environments from the plan-environment.yaml
plan_env_path = utils.rel_or_abs_path(
self.tht_render, parsed_args.plan_environment_file)
with open(plan_env_path, 'r') as f:
plan_env_data = yaml.safe_load(f)
environments = [utils.rel_or_abs_path(self.tht_render, e.get('path'))
for e in plan_env_data.get('environments', {})]
# this will allow the user to overwrite passwords with custom envs
pw_file = self._update_passwords_env(self.output_dir)
environments.insert(1, pw_file)
environments.append(pw_file)
# use deployed-server because we run os-collect-config locally
deployed_server_env = os.path.join(
self.tht_render, 'environments',
'config-download-environment.yaml')
environments.insert(2, deployed_server_env)
environments.append(deployed_server_env)
# use deployed-server because we run os-collect-config locally
deployed_server_env = os.path.join(
self.tht_render, 'environments',
'deployed-server-noop-ctlplane.yaml')
environments.insert(3, deployed_server_env)
environments.append(deployed_server_env)
self.log.info(_("Deploying templates in the directory {0}").format(
os.path.abspath(self.tht_render)))
@ -534,7 +540,7 @@ class Deploy(command.Command):
with open(maps_file, 'w') as env_file:
yaml.safe_dump({'parameter_defaults': tmp_env}, env_file,
default_flow_style=False)
environments.insert(4, maps_file)
environments.append(maps_file)
# NOTE(aschultz): this doesn't get copied into tht_root but
# we always include the hieradata override stuff last.
@ -543,7 +549,7 @@ class Deploy(command.Command):
parsed_args.hieradata_override,
parsed_args.standalone_role))
return environments
return environments + user_environments
def _prepare_container_images(self, env):
roles_data = self._get_roles_data()
@ -700,6 +706,12 @@ class Deploy(command.Command):
'directory') % constants.UNDERCLOUD_ROLES_FILE,
default=constants.UNDERCLOUD_ROLES_FILE
)
parser.add_argument(
'--plan-environment-file', '-p',
help=_('Plan Environment file, overrides the default %s in the '
'--templates directory') % constants.PLAN_ENVIRONMENT,
default=constants.PLAN_ENVIRONMENT
)
parser.add_argument(
'--heat-api-port', metavar='<HEAT_API_PORT>',
dest='heat_api_port',