diff --git a/devstack/lib/ironic b/devstack/lib/ironic index 06dfd75d25..707f3b5845 100644 --- a/devstack/lib/ironic +++ b/devstack/lib/ironic @@ -1279,6 +1279,9 @@ function configure_ironic_conductor { # we definitely know the default username to use for TinyIPA image IRONIC_ANSIBLE_SSH_USER='tc' fi + # (rpittau) most recent tinyipa uses python3 natively so we need to change + # the default ansible python interpreter. + iniset $IRONIC_CONF_FILE ansible default_python_interpreter /usr/bin/python3 fi iniset $IRONIC_CONF_FILE ansible default_key_file $IRONIC_ANSIBLE_SSH_KEY if [[ -n $IRONIC_ANSIBLE_SSH_USER ]]; then diff --git a/ironic/conf/ansible.py b/ironic/conf/ansible.py index 97869460c4..bcabb1b963 100644 --- a/ironic/conf/ansible.py +++ b/ironic/conf/ansible.py @@ -134,6 +134,10 @@ opts = [ "It may be overridden by per-node " "'ansible_clean_steps_config' option in node's " "'driver_info' field.")), + cfg.StrOpt('default_python_interpreter', + help=_("Absolute path to the python interpreter on the " + "managed machines. By default, ansible uses " + "/usr/bin/python")), ] diff --git a/ironic/drivers/modules/ansible/deploy.py b/ironic/drivers/modules/ansible/deploy.py index a5b28cd776..17d7174520 100644 --- a/ironic/drivers/modules/ansible/deploy.py +++ b/ironic/drivers/modules/ansible/deploy.py @@ -126,6 +126,9 @@ def _run_playbook(node, name, extra_vars, key, tags=None, notags=None): playbook = os.path.join(root, name) inventory = os.path.join(root, 'inventory') ironic_vars = {'ironic': extra_vars} + if CONF.ansible.default_python_interpreter: + ironic_vars['ansible_python_interpreter'] = ( + CONF.ansible.default_python_interpreter) args = [CONF.ansible.ansible_playbook_script, playbook, '-i', inventory, '-e', json.dumps(ironic_vars), diff --git a/ironic/tests/unit/drivers/modules/ansible/test_deploy.py b/ironic/tests/unit/drivers/modules/ansible/test_deploy.py index 69237b312a..1391bcc5ec 100644 --- a/ironic/tests/unit/drivers/modules/ansible/test_deploy.py +++ b/ironic/tests/unit/drivers/modules/ansible/test_deploy.py @@ -10,6 +10,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json + from ironic_lib import utils as irlib_utils import mock from oslo_concurrency import processutils @@ -162,6 +164,33 @@ class TestAnsibleMethods(AnsibleDeployTestCaseBase): '/path/to/playbooks/inventory', '-e', '{"ironic": {"foo": "bar"}}', '--private-key=/path/to/key', '-vvvv') + @mock.patch.object(com_utils, 'execute', return_value=('out', 'err'), + autospec=True) + def test__run_playbook_ansible_interpreter_python3(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') + 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/python3", + "ironic": {"foo": "bar"}}, + json.loads(all_vars)) + @mock.patch.object(com_utils, 'execute', side_effect=processutils.ProcessExecutionError( description='VIKINGS!'), diff --git a/releasenotes/notes/add-ansible-python-interpreter-2035e0f23d407aaf.yaml b/releasenotes/notes/add-ansible-python-interpreter-2035e0f23d407aaf.yaml new file mode 100644 index 0000000000..9981967598 --- /dev/null +++ b/releasenotes/notes/add-ansible-python-interpreter-2035e0f23d407aaf.yaml @@ -0,0 +1,13 @@ +--- +features: + - Adds option ``[ansible]default_python_interpreter`` to choose + the python interpreter that ansible uses on managed machines. + By default, ansible uses ``/usr/bin/python`` as interpreter, making the + assumption that that path is always present on remote managed systems. + This might not be always the case, for example in custom build + images or Python 3 native distributions. + With this option the operator has the ability to set the absolute + path of the python interpreter on the remote machines, for example + ``/usr/bin/python3``. + The same interpreter will be used in all operations that use the + ansible deploy interface. diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index 2932855fee..0c89d48d17 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -11,10 +11,7 @@ check: jobs: - ironic-tox-unit-with-driver-libs - # making ironic-standalone non voting until we can run ansible - # with python3 interpreter on remote machines - - ironic-standalone: - voting: false + - ironic-standalone - ironic-tempest-functional-python2 - ironic-tempest-functional-python3 - ironic-grenade-dsvm @@ -40,9 +37,7 @@ queue: ironic jobs: - ironic-tox-unit-with-driver-libs - # removing ironic-standalone from gate until we can run ansible - # with python3 interpreter on remote machines - # - ironic-standalone + - ironic-standalone - ironic-tempest-functional-python2 - ironic-tempest-functional-python3 - ironic-grenade-dsvm