Allow ansible python interpreter be configurable
In order to be able to properly configure the python interpreter we want to use for the ansible deployment process, we need to expose it to the deployment process. If a user is deploying from a CentOS7 host to a fedora28 host, we need to be able to specify that we want to use python3. The opposite might be true for Fedora28 host to CentOS7. For the undercloud or standalone deployment methods we use the version of python that the openstack client is running under as our default. For the overcloud deployment, we currently do not specify anything by default which will fall back to the ansible default. This may need to change as we begine to run deployments against python3 hosts in CI. But for now this change lays the framework to be able to specify it in the deployment commands as an option. Depends-On: https://review.openstack.org/#/c/617793/ Depends-On: https://review.openstack.org/#/c/616203/ Change-Id: I425905110d701bb7e3079f1017a07678eca42456 Related-Blueprint: python3-support Co-Authored-By: Alex Schultz <aschultz@redhat.com>
This commit is contained in:
parent
37ec7906d7
commit
6eef81ab76
@ -1147,3 +1147,17 @@ class TestDeployNameScenarios(TestWithScenarios):
|
||||
observed = self.func()
|
||||
|
||||
self.assertEqual(self.expected, observed)
|
||||
|
||||
|
||||
class TestDeploymentPythonInterpreter(TestCase):
|
||||
def test_system_default(self):
|
||||
args = mock.MagicMock()
|
||||
args.deployment_python_interpreter = None
|
||||
py = utils.get_deployment_python_interpreter(args)
|
||||
self.assertEqual(py, sys.executable)
|
||||
|
||||
def test_provided_interpreter(self):
|
||||
args = mock.MagicMock()
|
||||
args.deployment_python_interpreter = 'foo'
|
||||
py = utils.get_deployment_python_interpreter(args)
|
||||
self.assertEqual(py, 'foo')
|
||||
|
@ -658,7 +658,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
def _fake_heat_deploy(self, stack, stack_name, template_path,
|
||||
parameters, environments, timeout, tht_root,
|
||||
env, update_plan_only, run_validations,
|
||||
skip_deploy_identifier, plan_env_file):
|
||||
skip_deploy_identifier, plan_env_file,
|
||||
deployment_options=None):
|
||||
assertEqual(
|
||||
{'parameter_defaults': {'NovaComputeLibvirtType': 'qemu'},
|
||||
'resource_registry': {
|
||||
@ -719,7 +720,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
def _fake_heat_deploy(self, stack, stack_name, template_path,
|
||||
parameters, environments, timeout, tht_root,
|
||||
env, update_plan_only, run_validations,
|
||||
skip_deploy_identifier, plan_env_file):
|
||||
skip_deploy_identifier, plan_env_file,
|
||||
deployment_options=None):
|
||||
# Should be no breakpoint cleanup because utils.get_stack = None
|
||||
assertEqual(
|
||||
{'parameter_defaults': {},
|
||||
@ -1030,7 +1032,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
self.cmd, {}, 'overcloud',
|
||||
'/fake/path/' + constants.OVERCLOUD_YAML_NAME, {},
|
||||
['~/overcloud-env.json'], 1, '/fake/path', {}, False, True, False,
|
||||
None)
|
||||
None, deployment_options=None)
|
||||
|
||||
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||
'_heat_deploy', autospec=True)
|
||||
|
@ -419,7 +419,8 @@ class TestOvercloudDeployPlan(utils.TestCommand):
|
||||
workflow_input={
|
||||
'container': 'overcast',
|
||||
'run_validations': True,
|
||||
'skip_deploy_identifier': False
|
||||
'skip_deploy_identifier': False,
|
||||
'deployment_options': {},
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -669,7 +669,9 @@ class TestDeployUndercloud(TestPluginV1):
|
||||
mock_importInv, createdir_mock):
|
||||
|
||||
fake_output_dir = '/twd'
|
||||
extra_vars = {'Undercloud': {'ansible_connection': 'local'}}
|
||||
extra_vars = {'Undercloud': {
|
||||
'ansible_connection': 'local',
|
||||
'ansible_python_interpreter': sys.executable}}
|
||||
mock_inventory = mock.Mock()
|
||||
mock_importInv.return_value = mock_inventory
|
||||
self.cmd.output_dir = fake_output_dir
|
||||
@ -793,7 +795,8 @@ class TestDeployUndercloud(TestPluginV1):
|
||||
mock_tht.assert_called_once_with(self.cmd, fake_orchestration,
|
||||
parsed_args)
|
||||
mock_download.assert_called_with(self.cmd, fake_orchestration,
|
||||
'undercloud', 'Undercloud')
|
||||
'undercloud', 'Undercloud',
|
||||
sys.executable)
|
||||
mock_launchansible.assert_called_once()
|
||||
mock_tarball.assert_called_once()
|
||||
mock_cleanupdirs.assert_called_once()
|
||||
|
@ -1341,3 +1341,10 @@ def update_nodes_deploy_data(imageclient, nodes):
|
||||
if 'ramdisk_id' not in node and ramdisk in img_map:
|
||||
node['ramdisk_id'] = img_map[ramdisk]
|
||||
break
|
||||
|
||||
|
||||
def get_deployment_python_interpreter(parsed_args):
|
||||
"""Return correct deployment python interpreter """
|
||||
if parsed_args.deployment_python_interpreter:
|
||||
return parsed_args.deployment_python_interpreter
|
||||
return sys.executable
|
||||
|
@ -188,7 +188,8 @@ class DeployOvercloud(command.Command):
|
||||
|
||||
def _heat_deploy(self, stack, stack_name, template_path, parameters,
|
||||
env_files, timeout, tht_root, env, update_plan_only,
|
||||
run_validations, skip_deploy_identifier, plan_env_file):
|
||||
run_validations, skip_deploy_identifier, plan_env_file,
|
||||
deployment_options=None):
|
||||
"""Verify the Baremetal nodes are available and do a stack update"""
|
||||
|
||||
self.log.debug("Getting template contents from plan %s" % stack_name)
|
||||
@ -231,7 +232,8 @@ class DeployOvercloud(command.Command):
|
||||
stack_name, self.app_args.verbose_level,
|
||||
timeout=timeout,
|
||||
run_validations=run_validations,
|
||||
skip_deploy_identifier=skip_deploy_identifier)
|
||||
skip_deploy_identifier=skip_deploy_identifier,
|
||||
deployment_options=deployment_options)
|
||||
|
||||
def _process_and_upload_environment(self, container_name,
|
||||
env, moved_files, tht_root):
|
||||
@ -426,6 +428,11 @@ class DeployOvercloud(command.Command):
|
||||
if parsed_args.environment_files:
|
||||
created_env_files.extend(parsed_args.environment_files)
|
||||
|
||||
deployment_options = {}
|
||||
if parsed_args.deployment_python_interpreter:
|
||||
deployment_options['ansible_python_interpreter'] = \
|
||||
parsed_args.deployment_python_interpreter
|
||||
|
||||
self.log.debug("Processing environment files %s" % created_env_files)
|
||||
env_files, localenv = utils.process_multiple_environments(
|
||||
created_env_files, tht_root, user_tht_root,
|
||||
@ -451,7 +458,8 @@ class DeployOvercloud(command.Command):
|
||||
tht_root, stack, parsed_args.stack, parameters, env_files,
|
||||
parsed_args.timeout, env, parsed_args.update_plan_only,
|
||||
parsed_args.run_validations, parsed_args.skip_deploy_identifier,
|
||||
parsed_args.plan_environment_file)
|
||||
parsed_args.plan_environment_file,
|
||||
deployment_options=deployment_options)
|
||||
|
||||
def _try_overcloud_deploy_with_compat_yaml(self, tht_root, stack,
|
||||
stack_name, parameters,
|
||||
@ -459,14 +467,16 @@ class DeployOvercloud(command.Command):
|
||||
env, update_plan_only,
|
||||
run_validations,
|
||||
skip_deploy_identifier,
|
||||
plan_env_file):
|
||||
plan_env_file,
|
||||
deployment_options=None):
|
||||
overcloud_yaml = os.path.join(tht_root, constants.OVERCLOUD_YAML_NAME)
|
||||
try:
|
||||
self._heat_deploy(stack, stack_name, overcloud_yaml,
|
||||
parameters, env_files, timeout,
|
||||
tht_root, env, update_plan_only,
|
||||
run_validations, skip_deploy_identifier,
|
||||
plan_env_file)
|
||||
plan_env_file,
|
||||
deployment_options=deployment_options)
|
||||
except ClientException as e:
|
||||
messages = 'Failed to deploy: %s' % str(e)
|
||||
raise ValueError(messages)
|
||||
@ -830,6 +840,11 @@ class DeployOvercloud(command.Command):
|
||||
'unset, will default to however much time is leftover '
|
||||
'from the --timeout parameter after the stack operation.')
|
||||
)
|
||||
parser.add_argument('--deployment-python-interpreter', default=None,
|
||||
help=_('The path to python interpreter to use for '
|
||||
'the deployment actions. This may need to '
|
||||
'be used if deploying on a python2 host '
|
||||
'from a python3 system or vice versa.'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
|
@ -760,7 +760,8 @@ class Deploy(command.Command):
|
||||
return "%s/%s" % (stack_name, stack_id)
|
||||
|
||||
def _download_ansible_playbooks(self, client, stack_name,
|
||||
tripleo_role_name='Standalone'):
|
||||
tripleo_role_name='Standalone',
|
||||
python_interpreter=sys.executable):
|
||||
stack_config = config.Config(client)
|
||||
self._create_working_dirs()
|
||||
|
||||
@ -778,7 +779,13 @@ class Deploy(command.Command):
|
||||
ansible_ssh_user='root')
|
||||
|
||||
inv_path = os.path.join(self.tmp_ansible_dir, 'inventory.yaml')
|
||||
extra_vars = {tripleo_role_name: {'ansible_connection': 'local'}}
|
||||
extra_vars = {
|
||||
tripleo_role_name: {
|
||||
'ansible_connection': 'local',
|
||||
'ansible_python_interpreter': python_interpreter,
|
||||
}
|
||||
}
|
||||
|
||||
inventory.write_static_inventory(inv_path, extra_vars)
|
||||
|
||||
self.log.info(_('** Downloaded {0} ansible to {1} **').format(
|
||||
@ -899,6 +906,13 @@ class Deploy(command.Command):
|
||||
'Defaults to $SUDO_USER. If $SUDO_USER is unset '
|
||||
'it defaults to stack.')
|
||||
)
|
||||
parser.add_argument('--deployment-python-interpreter', default=None,
|
||||
help=_('The path to python interpreter to use for '
|
||||
'the deployment actions. If not specified '
|
||||
'the python version of the openstackclient '
|
||||
'will be used. This may need to be used '
|
||||
'if deploying on a python2 host from a '
|
||||
'python3 system or vice versa.'))
|
||||
parser.add_argument(
|
||||
'--heat-container-image', metavar='<HEAT_CONTAINER_IMAGE>',
|
||||
dest='heat_container_image',
|
||||
@ -1130,10 +1144,12 @@ class Deploy(command.Command):
|
||||
raise exceptions.DeploymentError(message)
|
||||
|
||||
# download the ansible playbooks and execute them.
|
||||
depl_python = utils.get_deployment_python_interpreter(parsed_args)
|
||||
self.ansible_dir = \
|
||||
self._download_ansible_playbooks(orchestration_client,
|
||||
parsed_args.stack,
|
||||
parsed_args.standalone_role)
|
||||
parsed_args.standalone_role,
|
||||
depl_python)
|
||||
|
||||
# Do not override user's custom ansible configuraition file,
|
||||
# it may have been pre-created with the tripleo CLI, or the like
|
||||
|
@ -64,13 +64,14 @@ def deploy(log, clients, **workflow_input):
|
||||
|
||||
def deploy_and_wait(log, clients, stack, plan_name, verbose_level,
|
||||
timeout=None, run_validations=False,
|
||||
skip_deploy_identifier=False):
|
||||
skip_deploy_identifier=False, deployment_options={}):
|
||||
"""Start the deploy and wait for it to finish"""
|
||||
|
||||
workflow_input = {
|
||||
"container": plan_name,
|
||||
"run_validations": run_validations,
|
||||
"skip_deploy_identifier": skip_deploy_identifier
|
||||
"skip_deploy_identifier": skip_deploy_identifier,
|
||||
"deployment_options": deployment_options,
|
||||
}
|
||||
|
||||
if timeout is not None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user