diff --git a/README.rst b/README.rst index b49fb27..a1b7055 100644 --- a/README.rst +++ b/README.rst @@ -13,6 +13,25 @@ OpenStack-Ansible python_venv_build This Ansible role prepares a python venv for use in OpenStack-Ansible. +The role requires the following to be present prior to execution: + +* pip >= 7.1 (to support using the constraints option) +* virtualenv >= 13.0.0 (to support using the no-pip, no-setuptools, no-wheels + options) + +Use-cases +~~~~~~~~~ + +This role is built to cater to the following use-cases: + +# Execute a build against a build host, then serve the venvs from a web + server. +# Execute a build against the first host in a group, then serving the + venvs from the deployment host. + +References +~~~~~~~~~~ + Documentation for the project can be found at: https://docs.openstack.org/openstack-ansible-python_venv_build/latest/ diff --git a/defaults/main.yml b/defaults/main.yml index 2c453e3..9b26b01 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -19,7 +19,7 @@ # The path where venvs are extracted to # on the target host during an install, for example: -# venv_destination_path: "/openstack/venvs/myvenv" +# venv_install_destination_path: "/openstack/venvs/myvenv" # # Optional variables @@ -27,70 +27,59 @@ # Distribution packages which must be installed # on the host for the purpose of building the venv. -distro_package_list: [] +venv_build_distro_package_list: [] + +# Distribution packages which must be installed +# on the host when installing the venv. +venv_install_distro_package_list: [] # Set the package install state for packages # Options are 'present' and 'latest' -distro_package_state: "latest" -pip_package_state: "latest" +venv_distro_package_state: "latest" +venv_pip_package_state: "latest" # The time in seconds that the distribution package # cache is valid for. This is only used by the apt # and zypper package managers. -distro_cache_valid_time: 600 - -# Python packages which must be installed -# on to the host for the purpose of building -# the venv. -host_pip_packages: [] - -# Arguments to pass to the installation -# of pip packages on the host. -host_pip_install_args: "" +venv_distro_cache_valid_time: 600 # Python packages which must be installed # into the venv. venv_pip_packages: [] -# Arguments to pass to the venv build +# Arguments to pass to pip when installing into the venv venv_pip_install_args: "" -# Enable the reuse of venvs across multiple hosts. -# This sets the build process to copy the venv to -# the deployment host once it's built, then to -# re-use the venv in subsequent deployments. -venv_reuse_enable: yes +# The python executable to use for creating the venv +venv_python_executable: "python2" # Enable the ability to *only* do the build, so that -# the deploy host can be pre-populated with the venvs. -venv_reuse_build_only: no +# the build host can be pre-populated with the venvs. +venv_build_only: no + +# Enable the packaging of venvs, so that they can +# be used for installation. +venv_build_package: yes # Enable the use of wheels to speed up the venv # build process, especially when building multiple # venvs. -venv_reuse_build_wheels: yes +venv_build_wheels: yes -# The path where a built venv is stored on the By default, -# a path on the deployment host is used which ensures that -# the location separates venvs per distribution and architecture -# to prevent re-use of venvs between them. If the path set -# begins with http(s):// then the install process will -# recognise this and deploy from a URL instead of the -# deployment host. -venv_reuse_download_venv_path: "{{ lookup('env', 'HOME') | default('/opt', true) }}/cache/venvs/{{ venv_reuse_download_subfolder }}" - -# NOTE(hwoarang): ansible_distribution may return a string with spaces -# such as "openSUSE Leap" so we need to replace the space with underscore -# in order to create a more sensible repo name for the distro. -venv_reuse_download_subfolder: "{{ (ansible_distribution | lower) | replace(' ', '_') }}-{{ ansible_distribution_version.split('.')[:2] | join('.') }}-{{ ansible_architecture | lower }}" - -# The owner of the venv_reuse_download_venv_path if it is -# housed on the deployment host. -venv_reuse_download_path_owner: "{{ lookup('env', 'USER') | default('root', true) }}" - -# The path where the wheels are cached on the target host +# The path where the wheels are cached on the build host # for speeding up the build process. -venv_wheel_destination_path: "/var/cache/python_wheels" +venv_build_wheel_path: "{{ lookup('env', 'HOME') }}/archive/wheels" + +# The path where the venvs are archived on the build host +# to be reused for installations. +venv_build_archive_path: "{{ lookup('env', 'HOME') }}/archive/venvs" + +# The path where a built venv is sourced from when +# installing. If the path set begins with https(s):// +# then the install process will recognise the source +# is a web server. Otherwise the path is assumed to +# be on the deployment host. +venv_install_source_path: "{{ lookup('env', 'HOME') }}/archive/venvs" # The facts to set when the venv changes during a # build, or the installation of a venv. diff --git a/handlers/main.yml b/handlers/main.yml index eec181a..8a88c3c 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -13,6 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -- meta: noop - listen: venv changed +- name: venv changed + meta: noop when: false diff --git a/tasks/main.yml b/tasks/main.yml index ffe3d93..d3268cd 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -20,27 +20,28 @@ # To ensure that only the first host in every distro/architecture # group does the build, and the others make use of that build, # without forcing the use of serialisation, we use a dynamic -# group based on the venv_reuse_download_subfolder which combines +# group based on the venv_distro_arch_grouping which combines # the distribution/architecture and is therefore unique for mixed # environments. - name: Add hosts to dynamic inventory group to ensure build/install serialization group_by: - key: "{{ venv_reuse_download_subfolder }}" + key: "{{ venv_distro_arch_grouping }}" + tags: + - always - include_tasks: "python_venv_build.yml" when: - - (not _src_venv_present.stat.exists | bool) or - (not venv_reuse_enable | bool) - - inventory_hostname == groups[venv_reuse_download_subfolder][0] + - (venv_build_only | bool) or + ((_venv_source == 'file') and + (not _src_venv_present.stat.exists | bool)) + - inventory_hostname == groups[venv_distro_arch_grouping][0] - include_tasks: "python_venv_install.yml" when: - - venv_reuse_enable | bool - - not venv_reuse_build_only | bool - - (_src_venv_present.stat.exists | bool) or - inventory_hostname != groups[venv_reuse_download_subfolder][0] + - not venv_build_only | bool + - inventory_hostname != groups[venv_distro_arch_grouping][0] - include_tasks: "python_venv_set_facts.yml" when: - - not venv_reuse_build_only | bool + - not venv_build_only | bool - venv_facts_when_changed != [] diff --git a/tasks/python_venv_build.yml b/tasks/python_venv_build.yml index 1d11338..809e936 100644 --- a/tasks/python_venv_build.yml +++ b/tasks/python_venv_build.yml @@ -15,44 +15,44 @@ - name: Install distro packages for venv build package: - name: "{{ distro_package_list }}" - state: "{{ distro_package_state }}" + name: "{{ venv_build_distro_package_list + venv_install_distro_package_list }}" + state: "{{ venv_distro_package_state }}" update_cache: "{{ (ansible_pkg_mgr in ['apt', 'zypper']) | ternary('yes', omit) }}" cache_valid_time: "{{ (ansible_pkg_mgr == 'apt') | ternary(distro_cache_valid_time, omit) }}" - when: distro_package_list | length > 0 + when: + - (venv_build_distro_package_list | length > 0) or + (venv_install_distro_package_list | length > 0) register: _install_distro_packages until: _install_distro_packages | success retries: 5 delay: 2 -- name: Install pip packages on the host for venv build - pip: - name: "{{ host_pip_packages }}" - state: "{{ pip_package_state }}" - extra_args: "{{ host_pip_install_args }}" - when: host_pip_packages | length > 0 - register: _install_host_pip_packages - until: _install_host_pip_packages | success - retries: 5 - delay: 2 +- name: Ensure a fresh venv_install_destination_path if venv_build_only is enabled + file: + path: "{{ venv_install_destination_path }}" + state: absent + when: + - venv_build_only | bool - name: Create wheel/venv directories on the target host file: path: "{{ item }}" state: directory with_items: - - "{{ venv_destination_path }}" - - "{{ venv_wheel_destination_path }}" + - "{{ venv_build_archive_path }}" + - "{{ venv_build_wheel_path }}" + - "{{ venv_install_destination_path }}" - name: Build wheels for the packages to be installed into the venv command: >- pip wheel - --wheel-dir {{ venv_wheel_destination_path }}/ - --find-links {{ venv_wheel_destination_path }}/ + --wheel-dir {{ venv_build_wheel_path }}/ + --find-links {{ venv_build_wheel_path }}/ --log /var/log/python_wheel_build.log {{ venv_pip_install_args }} {{ venv_pip_packages | join(' ') }} - when: venv_reuse_build_wheels | bool + when: + - venv_build_wheels | bool #TODO(odyssey4me): # Split the venv build into multiple parts: @@ -64,11 +64,12 @@ - name: Build venv pip: name: "{{ venv_pip_packages }}" - state: "{{ pip_package_state }}" - virtualenv: "{{ venv_destination_path }}" + state: "{{ venv_pip_package_state }}" + virtualenv: "{{ venv_install_destination_path }}" virtualenv_site_packages: "no" + virtualenv_python: "{{ venv_python_executable }}" extra_args: >- - --find-links {{ venv_wheel_destination_path }}/ + --find-links {{ venv_build_wheel_path }}/ --log /var/log/python_venv_build.log {{ venv_pip_install_args }} register: _install_venv_pip_packages @@ -78,53 +79,66 @@ notify: - venv changed -- name: Package the venv when venv_reuse_enable is enabled +- name: Package the venv when venv_build_package is enabled when: - - venv_reuse_enable | bool + - venv_build_package | bool block: - - name: Clean up the virtualenv before packaging - shell: | - find {{ venv_destination_path }}/bin -type f -name '*.pyc' -delete - when: - - _install_venv_pip_packages is mapping - - _install_venv_pip_packages | changed + - name: Clean up the virtualenv before packaging + shell: | + find {{ venv_install_destination_path }}/bin -type f -name '*.pyc' -delete + when: + - _install_venv_pip_packages is mapping + - _install_venv_pip_packages | changed - # Note(odyssey4me): - # We purposefully use shell instead of the archive module - # here. The archive module's output is far too verbose to - # be practical when debugging. - - name: Package venv - command: | - tar czf '{{ venv_destination_path }}.tgz' -C '{{ venv_destination_path }}' . - args: - chdir: "{{ venv_destination_path }}" - warn: no - register: _venv_package_build - when: - - _install_venv_pip_packages is mapping - - _install_venv_pip_packages | changed + # Note(odyssey4me): + # We purposefully use shell instead of the archive module + # here. The archive module's output is far too verbose to + # be practical when debugging. + - name: Package venv + command: | + tar czf '{{ venv_build_archive_path }}/{{ venv_install_destination_path | basename }}.tgz' -C '{{ venv_install_destination_path }}' . + args: + chdir: "{{ venv_install_destination_path }}" + warn: no + register: _venv_package_build + when: + - _install_venv_pip_packages is mapping + - _install_venv_pip_packages | changed - - name: Prepare checksum for packaged venv - shell: | - sha1sum '{{ venv_destination_path }}.tgz' | awk '{print $1}' > '{{ venv_destination_path }}.checksum' - args: - executable: /bin/bash - when: - - _venv_package_build is mapping - - _venv_package_build | changed + - name: Prepare checksum for packaged venv + shell: | + sha1sum '{{ venv_build_archive_path }}/{{ venv_install_destination_path | basename }}.tgz' | awk '{print $1}' > '{{ venv_build_archive_path }}/{{ venv_install_destination_path | basename }}.checksum' + args: + executable: /bin/bash + when: + - _venv_package_build is mapping + - _venv_package_build | changed - - name: Copy the packaged venv and checksum file to the deployment host - fetch: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - flat: yes - with_items: - - src: "{{ venv_destination_path }}.tgz" - dest: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.tgz" - - src: "{{ venv_destination_path }}.checksum" - dest: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.checksum" - when: - - _venv_source == 'file' - - _venv_package_build is mapping - - _venv_package_build | changed + - name: Ensure that venv_install_source_path exists on the deployment host + file: + path: "{{ venv_install_source_path }}" + state: directory + owner: "{{ lookup('env', 'USER') }}" + recurse: yes + delegate_to: localhost + run_once: yes + when: + - _venv_source == 'file' + - inventory_hostname != 'localhost' + + - name: Copy the packaged venv and checksum file to the deployment host + fetch: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + flat: yes + with_items: + - src: "{{ venv_build_archive_path }}/{{ venv_install_destination_path | basename }}.tgz" + dest: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.tgz" + - src: "{{ venv_build_archive_path }}/{{ venv_install_destination_path | basename }}.checksum" + dest: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.checksum" + when: + - _venv_source == 'file' + - _venv_package_build is mapping + - _venv_package_build | changed + - inventory_hostname != 'localhost' diff --git a/tasks/python_venv_install.yml b/tasks/python_venv_install.yml index f4c8961..13b4ae0 100644 --- a/tasks/python_venv_install.yml +++ b/tasks/python_venv_install.yml @@ -13,34 +13,59 @@ # See the License for the specific language governing permissions and # limitations under the License. -- name: Copy the venv checksum file to the target host +- name: Install distro packages for venv install + package: + name: "{{ venv_install_distro_package_list }}" + state: "{{ venv_distro_package_state }}" + update_cache: "{{ (ansible_pkg_mgr in ['apt', 'zypper']) | ternary('yes', omit) }}" + cache_valid_time: "{{ (ansible_pkg_mgr == 'apt') | ternary(distro_cache_valid_time, omit) }}" + when: + - venv_install_distro_package_list | length > 0 + register: _install_distro_packages + until: _install_distro_packages | success + retries: 5 + delay: 2 + +- name: Create venv parent directories on the target host + file: + path: "{{ venv_install_destination_path | dirname }}" + state: directory + +- name: Copy the venv archive checksum copy: - src: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.checksum" - dest: "{{ venv_destination_path | dirname }}/" + src: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.checksum" + dest: "{{ venv_install_destination_path | dirname }}/" register: _venv_checksum_copy when: - _venv_source == 'file' -- name: Retrieve checksum for venv download +- name: Copy the venv archive + copy: + src: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.tgz" + dest: "{{ venv_install_destination_path | dirname }}/" + when: + - _venv_source == 'file' + +- name: Download the venv archive checksum uri: - url: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.checksum" - dest: "{{ venv_destination_path | dirname }}/" + url: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.checksum" + dest: "{{ venv_install_destination_path | dirname }}/" return_content: yes register: _venv_checksum_download when: - _venv_source == 'url' -- name: Attempt venv download +- name: Download the venv archive get_url: - url: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.tgz" - dest: "{{ venv_destination_path | dirname }}/" + url: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.tgz" + dest: "{{ venv_install_destination_path | dirname }}/" checksum: "sha1:{{ _venv_checksum_download.content | trim }}" when: - _venv_source == 'url' - name: Remove existing venv on target host if it is changing file: - path: "{{ venv_destination_path }}" + path: "{{ venv_install_destination_path }}" state: absent when: - (_venv_checksum_copy is mapping and _venv_checksum_copy | changed) or @@ -48,15 +73,15 @@ - name: Create venv directory on the target host file: - path: "{{ venv_destination_path }}" + path: "{{ venv_install_destination_path }}" state: directory register: _venv_dir_create - name: Unarchive pre-built venv unarchive: - src: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.tgz" - dest: "{{ venv_destination_path }}" - remote_src: no + src: "{{ venv_install_destination_path }}.tgz" + dest: "{{ venv_install_destination_path }}" + remote_src: yes when: - (_venv_checksum_copy is mapping and _venv_checksum_copy | changed) or (_venv_checksum_download is mapping and _venv_checksum_download | changed) or @@ -73,8 +98,8 @@ # to https://github.com/pypa/virtualenv/issues/565 - name: Update virtualenv python and paths shell: | - sed -si '1s/^.*python.*$/#!{{ (venv_destination_path ~ '/bin') | replace ('/','\/') }}\/python/' {{ venv_destination_path }}/bin/* - virtualenv {{ venv_destination_path }} \ + sed -si '1s/^.*python.*$/#!{{ (venv_install_destination_path ~ '/bin') | replace ('/','\/') }}\/python/' {{ venv_install_destination_path }}/bin/* + virtualenv {{ venv_install_destination_path }} \ {{ (ansible_pkg_mgr == 'apt') | ternary('--always-copy', '') }} \ --no-pip \ --no-setuptools \ diff --git a/tasks/python_venv_preflight.yml b/tasks/python_venv_preflight.yml index 7c04d9d..259d4de 100644 --- a/tasks/python_venv_preflight.yml +++ b/tasks/python_venv_preflight.yml @@ -13,43 +13,59 @@ # See the License for the specific language governing permissions and # limitations under the License. -- name: Verify that venv_destination_path has been provided +- name: Verify that venv_install_destination_path has been provided fail: msg: | - The variable venv_destination_path is required and - has not been set + The variable venv_install_destination_path is required and + has not been set. when: - - venv_destination_path is not defined + - venv_install_destination_path is not defined -- name: Verify that venv_reuse_enable and venv_reuse_build_only are not interfering with each other +- name: Collect the version of virtualenv + shell: | + virtualenv --version 2>/dev/null || echo 'none' + args: + executable: /bin/bash + changed_when: false + failed_when: false + register: _virtualenv_version + +- name: Collect the version of pip + shell: | + pip --version 2>/dev/null | awk '{print $2}' || echo 'none' + args: + executable: /bin/bash + changed_when: false + failed_when: false + register: _pip_version + +- name: Fail when required virtualenv version is not present fail: - msg: | - If venv_reuse_build_only is enabled, then venv_reuse_enable must also - be enabled. - The variable venv_reuse_enable is set to {{ venv_reuse_enable }}. - The variable venv_reuse_build_only is set to {{ venv_reuse_build_only }}. + msg: >- + The required virtualenv version is not present. + The minimum version of 13.0.0 is required, but + {{ _virtualenv_version.stdout }} is installed. when: - - venv_reuse_build_only | bool - - not venv_reuse_enable | bool + - ((_virtualenv_version.stdout | trim) == 'none') or + ((_virtualenv_version.stdout | trim) is version_compare('13.0.0', '<')) -- name: Check whether the venv_reuse_download_venv_path is a URL or a file path +- name: Fail when required pip version is not present + fail: + msg: >- + The required virtualenv version is not present. + The minimum version of 7.1 is required, but + {{ _pip_version.stdout }} is installed. + when: + - ((_pip_version.stdout | trim) == 'none') or + ((_pip_version.stdout | trim) is version_compare('7.1', '<')) + +- name: Check whether the venv_install_source_path is a URL or a file path set_fact: - _venv_source: "{{ (venv_reuse_download_venv_path is match('^https?://.*')) | ternary('url', 'file') }}" - -- name: Ensure that venv_reuse_download_path exists on the deployment host - file: - path: "{{ venv_reuse_download_venv_path }}" - state: directory - owner: "{{ venv_reuse_download_path_owner }}" - delegate_to: localhost - run_once: yes - when: - - _venv_source == 'file' - - venv_reuse_enable | bool + _venv_source: "{{ ((venv_install_source_path | trim) is match('^https?://.*')) | ternary('url', 'file') }}" - name: Check if venv tgz is present on the deployment host stat: - path: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.tgz" + path: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.tgz" get_attributes: no get_checksum: no get_md5: no @@ -59,14 +75,3 @@ run_once: yes when: - _venv_source == 'file' - - venv_reuse_enable | bool - -- name: Ensure that virtualenv is installed on the destination host - pip: - name: virtualenv - state: "{{ pip_package_state }}" - extra_args: "{{ host_pip_install_args }}" - register: _install_host_pip_virtualenv - until: _install_host_pip_virtualenv | success - retries: 5 - delay: 2 diff --git a/tests/inventory b/tests/inventory index adb0bbb..47621f2 100644 --- a/tests/inventory +++ b/tests/inventory @@ -3,18 +3,8 @@ localhost container1 container2 container3 -container4 [all_containers] container1 container2 container3 -container4 - -[test1] -container1 -container2 - -[test2] -container3 -container4 diff --git a/tests/test-functional.yml b/tests/test-functional.yml index 811e15e..6994101 100644 --- a/tests/test-functional.yml +++ b/tests/test-functional.yml @@ -14,7 +14,7 @@ # limitations under the License. - name: Clean up from previous tests - hosts: "{{ target_host_group_name }}:localhost" + hosts: "{{ build_host }}:{{ install_hosts }}" become: yes any_errors_fatal: yes tasks: @@ -22,42 +22,87 @@ file: path: "{{ item.path }}" state: absent - when: item.condition | default(omit) with_items: - - path: "{{ lookup('env', 'HOME') | default('/opt', true) }}/venvs" - - path: "{{ lookup('env', 'HOME') | default('/opt', true) }}/cache/venvs" - - path: "{{ lookup('env', 'HOME') | default('/opt', true) }}/cache/wheels" - condition: "{{ target_host_group_name == 'test1' }}" - - path: "/var/cache/python_wheels" + - path: "{{ lookup('env', 'HOME') }}/archive" + - path: "{{ lookup('env', 'HOME') }}/venvs" - name: Clean up facts from previous tests ini_file: path: "/etc/ansible/facts.d/openstack_ansible.fact" - section: "{{ target_host_group_name }}" + section: "{{ item }}" state: absent + with_items: "{{ build_host.split(':') + install_hosts.split(':') }}" - name: Refresh the inventory to clear the added groups meta: refresh_inventory -- name: Execute role test and verify target host content - hosts: "{{ target_host_group_name }}" + - name: Set venv_build_archive_path and venv_install_source_path + set_fact: + venv_build_archive_path: >- + {%- if build_host == "container1" %} + {%- if ansible_distribution == "Ubuntu" %} + {%- set _path = "/var/www/html" %} + {%- elif ansible_distribution == "CentOS" %} + {%- set _path = "/usr/share/nginx/html" %} + {%- else %} + {%- set _path = "/srv/www/htdocs" %} + {%- endif %} + {%- else -%} + {%- set _path = lookup('env', 'HOME') ~ "/archive/venvs" -%} + {%- endif -%} + {{- _path }} + venv_install_source_path: >- + {%- if build_host == "container1" -%} + http://{{ hostvars['container1'].ansible_default_ipv4.address }} + {%- else -%} + {{- lookup('env', 'HOME') }}/archive/venvs + {%- endif -%} + + - name: Install distro packages + package: + name: "nginx" + update_cache: "{{ (ansible_pkg_mgr in ['apt', 'zypper']) | ternary('yes', omit) }}" + register: install + until: install | success + retries: 5 + delay: 2 + when: + - inventory_hostname == 'container1' + + - name: Enable and start nginx + service: + name: nginx + enabled: yes + daemon_reload: yes + state: restarted + when: + - inventory_hostname == 'container1' + +- name: Execute build + hosts: "{{ build_host }}" become: yes any_errors_fatal: yes - serial: "{{ target_serial }}" - vars: - base_directory: "{{ lookup('env', 'HOME') | default('/opt', true) }}" tasks: - - - name: Execute role + - name: Execute venv build + include_role: + name: "python_venv_build" + private: yes + vars: + venv_build_only: yes + +- name: Execute install + hosts: "{{ install_hosts }}" + become: yes + any_errors_fatal: yes + tasks: + + - name: Execute venv install include_role: name: "python_venv_build" private: yes vars: - venv_pip_packages: - - "Jinja2==2.10" - venv_destination_path: "{{ base_directory }}/venvs/{{ target_host_group_name }}" venv_facts_when_changed: - - section: "{{ target_host_group_name }}" + - section: "{{ inventory_hostname }}" option: "test" value: True @@ -73,7 +118,7 @@ - name: Verify that the facts were set assert: that: - - ansible_local['openstack_ansible'][target_host_group_name]['test'] | bool + - ansible_local['openstack_ansible'][inventory_hostname]['test'] | bool - name: Find files/folders on targets find: @@ -81,17 +126,12 @@ get_checksum: no recurse: no paths: - - "{{ base_directory }}/venvs" + - "{{ venv_install_destination_path | dirname }}" register: _target_folders - name: Compile the folder list from the targets set_fact: - _target_folder_list: >- - {%- set folder_list = [] %} - {%- for item in _target_folders['files'] %} - {%- set _ = folder_list.append(item['path']) %} - {%- endfor %} - {{ folder_list }} + _target_folder_list: "{{ _target_folders['files'] | map(attribute='path') | list }}" - name: Show the files/folder from the targets debug: @@ -100,43 +140,4 @@ - name: Verify the folder list from the targets assert: that: - - "{{ base_directory ~ '/venvs/' ~ target_host_group_name in _target_folder_list }}" - -- name: Verify deploy host content - hosts: localhost - connection: local - become: yes - any_errors_fatal: yes - vars: - base_directory: "{{ lookup('env', 'HOME') | default('/opt', true) }}" - sub_directory: "{{ (ansible_distribution | lower) | replace(' ', '_') }}-{{ ansible_distribution_version.split('.')[:2] | join('.') }}-{{ ansible_architecture | lower }}" - package_file_path: "{{ base_directory }}/cache/venvs/{{ sub_directory }}/{{ target_host_group_name }}" - tasks: - - - name: Find files/folders on deploy host - find: - file_type: any - get_checksum: no - recurse: yes - paths: - - "{{ base_directory }}/cache" - register: _localhost_folders - - - name: Compile the folder list from the deploy host - set_fact: - _localhost_folder_list: >- - {%- set folder_list = [] %} - {%- for item in _localhost_folders['files'] %} - {%- set _ = folder_list.append(item['path']) %} - {%- endfor %} - {{ folder_list }} - - - name: Show the files/folders from the deploy host - debug: - var: _localhost_folder_list - - - name: Verify the folder list from the deploy host - assert: - that: - - "{{ package_file_path ~ '.tgz' in _localhost_folder_list }}" - - "{{ package_file_path ~ '.checksum' in _localhost_folder_list }}" + - "{{ venv_install_destination_path in _target_folder_list }}" diff --git a/tests/test.yml b/tests/test.yml index 5a46348..9c0200c 100644 --- a/tests/test.yml +++ b/tests/test.yml @@ -16,14 +16,38 @@ - name: Prepare the host/containers include: common/test-setup-host.yml -- name: Verify that the role works with a serial playbook - include: test-functional.yml +- name: Verify building on a web server, and installing using a URL + import_playbook: test-functional.yml vars: - target_host_group_name: test1 - target_serial: 1 + build_host: container1 + install_hosts: "container2:container3" + venv_pip_packages: + - "Jinja2==2.10" + venv_install_destination_path: "{{ lookup('env', 'HOME') }}/venvs/test-venv" -- name: Verify that the role works with a parallel playbook - include: test-functional.yml +- name: Verify building on localhost, and installing using a copy + import_playbook: test-functional.yml vars: - target_host_group_name: test2 - target_serial: "100%" + build_host: localhost + install_hosts: "container1:container2:container3" + venv_pip_packages: + - "Jinja2==2.10" + venv_install_destination_path: "{{ lookup('env', 'HOME') }}/venvs/test-venv" + +- name: Verify building on a build host, and installing using a copy + import_playbook: test-functional.yml + vars: + build_host: container2 + install_hosts: "container1:container3" + venv_pip_packages: + - "Jinja2==2.10" + venv_install_destination_path: "{{ lookup('env', 'HOME') }}/venvs/test-venv" + +- name: Verify setting multiple build hosts behaves correctly + import_playbook: test-functional.yml + vars: + build_host: "localhost:container1" + install_hosts: "container2:container3" + venv_pip_packages: + - "Jinja2==2.10" + venv_install_destination_path: "{{ lookup('env', 'HOME') }}/venvs/test-venv" diff --git a/tox.ini b/tox.ini index 19dcf89..9dfc784 100644 --- a/tox.ini +++ b/tox.ini @@ -28,6 +28,8 @@ setenv = ROLE_NAME=python_venv_build VIRTUAL_ENV={envdir} WORKING_DIR={toxinidir} + # TODO(odyssey4me): remove after debugging is completed + ANSIBLE_PARAMETERS=-v [testenv:docs] diff --git a/vars/main.yml b/vars/main.yml new file mode 100644 index 0000000..02b28e6 --- /dev/null +++ b/vars/main.yml @@ -0,0 +1,19 @@ +--- +# Copyright 2018, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# NOTE(hwoarang): ansible_distribution may return a string with spaces +# such as "openSUSE Leap" so we need to replace the space with underscore +# in order to create a more sensible repo name for the distro. +venv_distro_arch_grouping: "{{ (ansible_distribution | lower) | replace(' ', '_') }}-{{ ansible_distribution_version.split('.')[:2] | join('.') }}-{{ ansible_architecture | lower }}"