Skip to content

Commit

Permalink
work on mafalb.ansible.virtualenv
Browse files Browse the repository at this point in the history
  • Loading branch information
mafalb committed Jan 16, 2024
1 parent ae38977 commit 5651de5
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 96 deletions.
91 changes: 43 additions & 48 deletions plugins/action/virtualenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os
from ansible.plugins.action import ActionBase
from ansible.plugins.filter.core import to_json
from ansible_collections.mafalb.ansible.plugins.filter.ansible import best_version
Expand Down Expand Up @@ -32,68 +33,62 @@ def run(self, tmp=None, task_vars=None):
self._supports_check_mode = True
super(ActionModule, self).run(tmp, task_vars)
module_args = self._task.args.copy()
module_return = {
'results': [
{'item': 'python_info1'},
{'item': 'create_virtualenv'},
{'item': 'python_info2'},
{'item': 'install_packages'}
]
}

display.debug("Variables %s" % to_json(task_vars))
# display.debug("Variables %s" % to_json(task_vars))

ansible_python_executable = task_vars.get('ansible_python')['executable']
python_executable = self._task.args.get('executable', ansible_python_executable)

# Get info about the targeted python interpreter
# Note that the virtualenv may exist already and could have been created with
# another interpreter. However, We do not recreate virtualenvs.
# another interpreter. If the virtualenv already exists override
# python_executable
#
module_return['results'][0] = self.python_info(executable=python_executable,
task_vars=task_vars)
virtualenv = self._task.args.get('virtualenv')
if (os.path.exists(os.path.join(virtualenv, 'bin', 'activate')) and
os.path.exists(os.path.join(virtualenv, 'bin', 'python'))):
python_executable = os.path.join(virtualenv, 'bin', 'python')
else:
python_executable = self._task.args.get('virtualenv_python', ansible_python_executable)

python_version = self._task.args.get('python_version')
packages = self._task.args.get('name')
fixed_packages = fix_package_list(packages, python_version)
best_ansible_version = best_version(packages, python_version)
# Get info about the targeted python interpreter
ret0 = self.python_info(executable=python_executable, task_vars=task_vars)
ret0['item'] = 'python_info1'

display.debug("Python interpreter %s" % to_json(python_version))
display.debug("Python interpreter %s" % to_json(packages))
display.debug("Python interpreter %s" % to_json(fixed_packages))
display.debug("Python interpreter %s" % to_json(best_ansible_version))
display.v("Virtualenv %s" % to_json(self._task.args.get('virtualenv')))
display.v("python_info1 %s" % to_json(ret0))

# create the virtualenv
display.v("Virtualenv %s" % to_json(self._task.args.get('virtualenv')))
module_args['virtualenv_command'] = python_executable + " -m venv"
module_args_copy = dict(module_args)
module_args_copy['name'] = ['wheel']
module_return['results'][1] = self._execute_module(module_name='pip',
module_args=module_args_copy,
task_vars=task_vars)
ret1 = self._execute_module(module_name='pip', module_args=module_args_copy, task_vars=task_vars)
ret1['item'] = 'create_virtualenv'
del module_args_copy
if 'failed' not in module_return['results'][1]:
module_return['results'][1]['failed'] = False
if 'failed' not in ret1:
ret1['failed'] = False
display.v("Create virtualenv %s" % to_json(ret1))

# if the virtualenv already existed, the virtualenv interpreter could
# be different from python_version
#
if module_return['results'][1]['changed']:
if self._play_context.check_mode:
virtualenv = self._task.args.get('virtualenv')
else:
# get absolute path (get rid of shellism like ~)
virtualenv = module_return['results'][1]['virtualenv']
module_return['results'][2] = self.python_info(executable=virtualenv + '/bin/python',
task_vars=task_vars)
module_return['results'][2] = {}
packages = self._task.args.get('name')
display.v("Packages %s" % to_json(packages))

python_version = ret0['version']['majmin']
display.v("Python version %s" % to_json(python_version))

fixed_packages = fix_package_list(packages, python_version)
display.v("Fixed packages %s" % to_json(fixed_packages))
module_args['name'] = fixed_packages

best_ansible_version = best_version(packages, python_version)
display.v("Best ansible version %s" % to_json(best_ansible_version))

# install the packages
module_return['results'][3] = self._execute_module(module_name='pip',
module_args=module_args,
task_vars=task_vars)
if 'failed' not in module_return['results'][3]:
module_return['results'][3]['failed'] = False

module_return['failed'] = False
module_return['changed'] = module_return['results'][3]['changed']
ret2 = self._execute_module(module_name='pip', module_args=module_args, task_vars=task_vars)
ret2['item'] = 'install_packages'
if 'failed' not in ret2:
ret2['failed'] = False

module_return = {}
module_return['failed'] = ret2['failed']
if 'changed' in ret2:
module_return['changed'] = ret2['changed']
module_return['results'] = [ret0, ret1, ret2]
return dict(module_return)
2 changes: 1 addition & 1 deletion plugins/filter/ansible.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def best_version(arg_packages, python_version=None):
break
name, spec, specstr, req_contains = parse_requirement(s)
if name != 'ansible':
raise AnsibleFilterError("not '_ansible': {str}".format(str=name))
raise AnsibleFilterError("There is no '_ansible' in package list: {str}".format(str=name))

# exact version is requested, expand to full version if necessary
# it could be that that's not compatible with requested python version
Expand Down
2 changes: 1 addition & 1 deletion roles/virtualenv/meta/argument_specs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ argument_specs:
type: path
default: ~/.virtualenvs/ansible

virtualenv_interpreter:
virtualenv_python:
description: The path to the python interpreter
type: path
129 changes: 83 additions & 46 deletions tests/integration/targets/action_virtualenv/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,87 @@
# see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt
---

- name: Virtualenv virtualenv-test1 is present | check mode
check_mode: true
register: _output
mafalb.ansible.virtualenv:
virtualenv: ~/.virtualenvs/virtualenv-test1
virtualenv_command: python3 -m venv
name:
- ansible

- name: Assertions | check mode
ansible.builtin.assert:
that:
- not _output.failed
- _output.changed
- not _output.results[0].changed
- _output.results[1].changed
- _output.results[2] == {}
- _output.results[3].changed
- not _output.results[0].failed
- not _output.results[1].failed
- not _output.results[3].failed

- name: Virtualenv virtualenv-test1 is present
mafalb.ansible.virtualenv:
virtualenv: ~/.virtualenvs/virtualenv-test1
virtualenv_command: python3 -m venv
name:
- ansible
register: _output

- name: Debug _output
ansible.builtin.debug:
var: _output

- name: Assertions
ansible.builtin.assert:
that:
- _output.changed
- not _output.failed
- not _output.results[0].changed
- _output.results[1].changed
- _output.results[2] == {}
- _output.results[3].changed
- not _output.results[0].failed
- not _output.results[1].failed
- not _output.results[3].failed
- name: Test creation of mafalb.ansible.virtualenv
# unset PYTHONPATH, it contains ansible-core
# The contents would be visible in virtualenv otherwise
#
environment:
PYTHONPATH: ''
block:

- name: Virtualenv virtualenv-test1 is present | check mode
check_mode: true
register: _result
mafalb.ansible.virtualenv:
virtualenv: ~/.virtualenvs/virtualenv-test1
name:
- _ansible
- selinux

- name: Assertions | check mode
ansible.builtin.assert:
that:
- not _result.failed
- _result.changed
- not _result.results[0].changed
- _result.results[1].changed
- _result.results[2].changed
- not _result.results[0].failed
- not _result.results[1].failed
- not _result.results[2].failed

- name: Virtualenv virtualenv-test1 is present
register: _result
mafalb.ansible.virtualenv:
virtualenv: ~/.virtualenvs/virtualenv-test1
name:
- _ansible
- selinux

- name: Debug _result
ansible.builtin.debug:
var: _result

- name: Assertions
ansible.builtin.assert:
that:
- _result.changed
- not _result.failed
- not _result.results[0].changed
- _result.results[1].changed
- _result.results[2].changed
- not _result.results[0].failed
- not _result.results[1].failed
- not _result.results[2].failed

- name: Virtualenv virtualenv-test1 is present | Idempotence
register: _result
mafalb.ansible.virtualenv:
virtualenv: ~/.virtualenvs/virtualenv-test1
name:
- _ansible
- selinux

- name: Assertions | Idempotence
ansible.builtin.assert:
that:
- not _result.changed
- not _result.failed
- not _result.results[0].changed
- not _result.results[1].changed
- not _result.results[2].changed
- not _result.results[0].failed
- not _result.results[1].failed
- not _result.results[2].failed

- name: Get ansible version
ansible.builtin.command:
cmd: ~/.virtualenvs/virtualenv-test1/bin/ansible --version
changed_when: false
register: _result

- name: Debug ansible
ansible.builtin.debug:
var: _result

...
2 changes: 2 additions & 0 deletions tests/unit/plugins/filter/test_best_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@
(['_ansible'], '3.7', data['latest_ansible_version']['2.11']),
(['_ansible~=2.11.6', '_ansible_test'], '3.8',
data['latest_ansible_version']['2.11']),
(['ansible'], '3.12', data['latest_ansible_version']['2.16']),
)

FAIL_CASES = (
(['_ansible=="2.9"'], AnsibleFilterError),
(['ansible=="2.9"'], AnsibleFilterError),
(['ansible-core', 'selinux'], AnsibleFilterError),
)


Expand Down

0 comments on commit 5651de5

Please sign in to comment.