Merge "Adding ansible python interpreter as driver_info"

This commit is contained in:
Zuul 2019-03-14 16:00:19 +00:00 committed by Gerrit Code Review
commit b2a48fab36
5 changed files with 62 additions and 5 deletions

View File

@ -231,6 +231,13 @@ ansible_clean_steps_config
Default is taken from ``[ansible]/default_clean_steps_config`` option of the Default is taken from ``[ansible]/default_clean_steps_config`` option of the
ironic configuration file (defaults to ``clean_steps.yaml``). ironic configuration file (defaults to ``clean_steps.yaml``).
ansible_python_interpreter
Absolute path to the python interpreter on the managed machine.
Default is taken from ``[ansible]/default_python_interpreter`` option of
the ironic configuration file.
Ansible uses ``/usr/bin/python`` by default.
Customizing the deployment logic Customizing the deployment logic
================================ ================================

View File

@ -136,8 +136,10 @@ opts = [
"'driver_info' field.")), "'driver_info' field.")),
cfg.StrOpt('default_python_interpreter', cfg.StrOpt('default_python_interpreter',
help=_("Absolute path to the python interpreter on the " help=_("Absolute path to the python interpreter on the "
"managed machines. By default, ansible uses " "managed machines. It may be overridden by per-node "
"/usr/bin/python")), "'ansible_python_interpreter' option in node's "
"'driver_info' field. "
"By default, ansible uses /usr/bin/python")),
] ]

View File

@ -73,6 +73,8 @@ OPTIONAL_PROPERTIES = {
'ansible_clean_steps_config': _('Name of the file inside the ' 'ansible_clean_steps_config': _('Name of the file inside the '
'"ansible_playbooks_path" folder with ' '"ansible_playbooks_path" folder with '
'cleaning steps configuration. Optional.'), 'cleaning steps configuration. Optional.'),
'ansible_python_interpreter': _('Absolute path to the python interpreter '
'on the managed machines. Optional.'),
} }
COMMON_PROPERTIES = OPTIONAL_PROPERTIES COMMON_PROPERTIES = OPTIONAL_PROPERTIES
@ -101,6 +103,11 @@ def _parse_ansible_driver_info(node, action='deploy'):
return os.path.basename(playbook), user, key return os.path.basename(playbook), user, key
def _get_python_interpreter(node):
return node.driver_info.get('ansible_python_interpreter',
CONF.ansible.default_python_interpreter)
def _get_configdrive_path(basename): def _get_configdrive_path(basename):
return os.path.join(CONF.tempdir, basename + '.cndrive') return os.path.join(CONF.tempdir, basename + '.cndrive')
@ -126,9 +133,9 @@ def _run_playbook(node, name, extra_vars, key, tags=None, notags=None):
playbook = os.path.join(root, name) playbook = os.path.join(root, name)
inventory = os.path.join(root, 'inventory') inventory = os.path.join(root, 'inventory')
ironic_vars = {'ironic': extra_vars} ironic_vars = {'ironic': extra_vars}
if CONF.ansible.default_python_interpreter: python_interpreter = _get_python_interpreter(node)
ironic_vars['ansible_python_interpreter'] = ( if python_interpreter:
CONF.ansible.default_python_interpreter) ironic_vars['ansible_python_interpreter'] = python_interpreter
args = [CONF.ansible.ansible_playbook_script, playbook, args = [CONF.ansible.ansible_playbook_script, playbook,
'-i', inventory, '-i', inventory,
'-e', json.dumps(ironic_vars), '-e', json.dumps(ironic_vars),

View File

@ -191,6 +191,35 @@ class TestAnsibleMethods(AnsibleDeployTestCaseBase):
"ironic": {"foo": "bar"}}, "ironic": {"foo": "bar"}},
json.loads(all_vars)) json.loads(all_vars))
@mock.patch.object(com_utils, 'execute', return_value=('out', 'err'),
autospec=True)
def test__run_playbook_ansible_interpreter_override(self, execute_mock):
self.config(group='ansible', playbooks_path='/path/to/playbooks')
self.config(group='ansible', config_file_path='/path/to/config')
self.config(group='ansible', verbosity=3)
self.config(group='ansible',
default_python_interpreter='/usr/bin/python3')
self.config(group='ansible', ansible_extra_args='--timeout=100')
self.node.driver_info['ansible_python_interpreter'] = (
'/usr/bin/python4')
extra_vars = {'foo': 'bar'}
ansible_deploy._run_playbook(self.node, 'deploy',
extra_vars, '/path/to/key',
tags=['spam'], notags=['ham'])
execute_mock.assert_called_once_with(
'env', 'ANSIBLE_CONFIG=/path/to/config',
'ansible-playbook', '/path/to/playbooks/deploy', '-i',
'/path/to/playbooks/inventory', '-e',
mock.ANY, '--tags=spam', '--skip-tags=ham',
'--private-key=/path/to/key', '-vvv', '--timeout=100')
all_vars = execute_mock.call_args[0][7]
self.assertEqual({"ansible_python_interpreter": "/usr/bin/python4",
"ironic": {"foo": "bar"}},
json.loads(all_vars))
@mock.patch.object(com_utils, 'execute', @mock.patch.object(com_utils, 'execute',
side_effect=processutils.ProcessExecutionError( side_effect=processutils.ProcessExecutionError(
description='VIKINGS!'), description='VIKINGS!'),
@ -286,6 +315,16 @@ class TestAnsibleMethods(AnsibleDeployTestCaseBase):
self.assertEqual(2, ansible_deploy._calculate_memory_req(task)) self.assertEqual(2, ansible_deploy._calculate_memory_req(task))
image_mock.assert_called_once_with(task.context, 'fake-image') image_mock.assert_called_once_with(task.context, 'fake-image')
def test__get_python_interpreter(self):
self.config(group='ansible',
default_python_interpreter='/usr/bin/python3')
self.node.driver_info['ansible_python_interpreter'] = (
'/usr/bin/python4')
python_interpreter = ansible_deploy._get_python_interpreter(self.node)
self.assertEqual('/usr/bin/python4', python_interpreter)
def test__get_configdrive_path(self): def test__get_configdrive_path(self):
self.config(tempdir='/path/to/tmpdir') self.config(tempdir='/path/to/tmpdir')
self.assertEqual('/path/to/tmpdir/spam.cndrive', self.assertEqual('/path/to/tmpdir/spam.cndrive',

View File

@ -11,3 +11,5 @@ features:
``/usr/bin/python3``. ``/usr/bin/python3``.
The same interpreter will be used in all operations that use the The same interpreter will be used in all operations that use the
ansible deploy interface. ansible deploy interface.
It is also possible to override the value set in the configuration for a
node by passing ``ansible_python_interpreter`` in its ``driver_info``.