Revise the role to properly cater to use-cases

1. Variables have been renamed to make it easier to
   understand their purpose.
2. Unnecessary variables have been removed.
3. The role no longer caters to installing pip packages
   on the host. This should never be necessary - if it
   is, then something should do so beforehand.
4. The expected versions of pip/virtualenv are documented
   and a check has been added to ensure that they exist.
5. The handler has been named to make debug logs less
   confusing.
6. The default storage path for venvs/wheels is no longer
   opinionated. If paths based on distro/architecture are
   required then different paths should be provided to
   the role.

Change-Id: I9eb96e9db22f918b00456af943d81f66050107ce
This commit is contained in:
Jesse Pretorius 2018-04-27 15:15:40 +01:00
parent 19e2573be8
commit d169906c68
12 changed files with 347 additions and 258 deletions

View File

@ -13,6 +13,25 @@ OpenStack-Ansible python_venv_build
This Ansible role prepares a python venv for use in OpenStack-Ansible. 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: Documentation for the project can be found at:
https://docs.openstack.org/openstack-ansible-python_venv_build/latest/ https://docs.openstack.org/openstack-ansible-python_venv_build/latest/

View File

@ -19,7 +19,7 @@
# The path where venvs are extracted to # The path where venvs are extracted to
# on the target host during an install, for example: # on the target host during an install, for example:
# venv_destination_path: "/openstack/venvs/myvenv" # venv_install_destination_path: "/openstack/venvs/myvenv"
# #
# Optional variables # Optional variables
@ -27,70 +27,59 @@
# Distribution packages which must be installed # Distribution packages which must be installed
# on the host for the purpose of building the venv. # 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 # Set the package install state for packages
# Options are 'present' and 'latest' # Options are 'present' and 'latest'
distro_package_state: "latest" venv_distro_package_state: "latest"
pip_package_state: "latest" venv_pip_package_state: "latest"
# The time in seconds that the distribution package # The time in seconds that the distribution package
# cache is valid for. This is only used by the apt # cache is valid for. This is only used by the apt
# and zypper package managers. # and zypper package managers.
distro_cache_valid_time: 600 venv_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: ""
# Python packages which must be installed # Python packages which must be installed
# into the venv. # into the venv.
venv_pip_packages: [] venv_pip_packages: []
# Arguments to pass to the venv build # Arguments to pass to pip when installing into the venv
venv_pip_install_args: "" venv_pip_install_args: ""
# Enable the reuse of venvs across multiple hosts. # The python executable to use for creating the venv
# This sets the build process to copy the venv to venv_python_executable: "python2"
# the deployment host once it's built, then to
# re-use the venv in subsequent deployments.
venv_reuse_enable: yes
# Enable the ability to *only* do the build, so that # Enable the ability to *only* do the build, so that
# the deploy host can be pre-populated with the venvs. # the build host can be pre-populated with the venvs.
venv_reuse_build_only: no 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 # Enable the use of wheels to speed up the venv
# build process, especially when building multiple # build process, especially when building multiple
# venvs. # venvs.
venv_reuse_build_wheels: yes venv_build_wheels: yes
# The path where a built venv is stored on the By default, # The path where the wheels are cached on the build host
# 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
# for speeding up the build process. # 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 # The facts to set when the venv changes during a
# build, or the installation of a venv. # build, or the installation of a venv.

View File

@ -13,6 +13,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
- meta: noop - name: venv changed
listen: venv changed meta: noop
when: false when: false

View File

@ -20,27 +20,28 @@
# To ensure that only the first host in every distro/architecture # To ensure that only the first host in every distro/architecture
# group does the build, and the others make use of that build, # group does the build, and the others make use of that build,
# without forcing the use of serialisation, we use a dynamic # 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 # the distribution/architecture and is therefore unique for mixed
# environments. # environments.
- name: Add hosts to dynamic inventory group to ensure build/install serialization - name: Add hosts to dynamic inventory group to ensure build/install serialization
group_by: group_by:
key: "{{ venv_reuse_download_subfolder }}" key: "{{ venv_distro_arch_grouping }}"
tags:
- always
- include_tasks: "python_venv_build.yml" - include_tasks: "python_venv_build.yml"
when: when:
- (not _src_venv_present.stat.exists | bool) or - (venv_build_only | bool) or
(not venv_reuse_enable | bool) ((_venv_source == 'file') and
- inventory_hostname == groups[venv_reuse_download_subfolder][0] (not _src_venv_present.stat.exists | bool))
- inventory_hostname == groups[venv_distro_arch_grouping][0]
- include_tasks: "python_venv_install.yml" - include_tasks: "python_venv_install.yml"
when: when:
- venv_reuse_enable | bool - not venv_build_only | bool
- not venv_reuse_build_only | bool - inventory_hostname != groups[venv_distro_arch_grouping][0]
- (_src_venv_present.stat.exists | bool) or
inventory_hostname != groups[venv_reuse_download_subfolder][0]
- include_tasks: "python_venv_set_facts.yml" - include_tasks: "python_venv_set_facts.yml"
when: when:
- not venv_reuse_build_only | bool - not venv_build_only | bool
- venv_facts_when_changed != [] - venv_facts_when_changed != []

View File

@ -15,44 +15,44 @@
- name: Install distro packages for venv build - name: Install distro packages for venv build
package: package:
name: "{{ distro_package_list }}" name: "{{ venv_build_distro_package_list + venv_install_distro_package_list }}"
state: "{{ distro_package_state }}" state: "{{ venv_distro_package_state }}"
update_cache: "{{ (ansible_pkg_mgr in ['apt', 'zypper']) | ternary('yes', omit) }}" update_cache: "{{ (ansible_pkg_mgr in ['apt', 'zypper']) | ternary('yes', omit) }}"
cache_valid_time: "{{ (ansible_pkg_mgr == 'apt') | ternary(distro_cache_valid_time, 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 register: _install_distro_packages
until: _install_distro_packages | success until: _install_distro_packages | success
retries: 5 retries: 5
delay: 2 delay: 2
- name: Install pip packages on the host for venv build - name: Ensure a fresh venv_install_destination_path if venv_build_only is enabled
pip: file:
name: "{{ host_pip_packages }}" path: "{{ venv_install_destination_path }}"
state: "{{ pip_package_state }}" state: absent
extra_args: "{{ host_pip_install_args }}" when:
when: host_pip_packages | length > 0 - venv_build_only | bool
register: _install_host_pip_packages
until: _install_host_pip_packages | success
retries: 5
delay: 2
- name: Create wheel/venv directories on the target host - name: Create wheel/venv directories on the target host
file: file:
path: "{{ item }}" path: "{{ item }}"
state: directory state: directory
with_items: with_items:
- "{{ venv_destination_path }}" - "{{ venv_build_archive_path }}"
- "{{ venv_wheel_destination_path }}" - "{{ venv_build_wheel_path }}"
- "{{ venv_install_destination_path }}"
- name: Build wheels for the packages to be installed into the venv - name: Build wheels for the packages to be installed into the venv
command: >- command: >-
pip wheel pip wheel
--wheel-dir {{ venv_wheel_destination_path }}/ --wheel-dir {{ venv_build_wheel_path }}/
--find-links {{ venv_wheel_destination_path }}/ --find-links {{ venv_build_wheel_path }}/
--log /var/log/python_wheel_build.log --log /var/log/python_wheel_build.log
{{ venv_pip_install_args }} {{ venv_pip_install_args }}
{{ venv_pip_packages | join(' ') }} {{ venv_pip_packages | join(' ') }}
when: venv_reuse_build_wheels | bool when:
- venv_build_wheels | bool
#TODO(odyssey4me): #TODO(odyssey4me):
# Split the venv build into multiple parts: # Split the venv build into multiple parts:
@ -64,11 +64,12 @@
- name: Build venv - name: Build venv
pip: pip:
name: "{{ venv_pip_packages }}" name: "{{ venv_pip_packages }}"
state: "{{ pip_package_state }}" state: "{{ venv_pip_package_state }}"
virtualenv: "{{ venv_destination_path }}" virtualenv: "{{ venv_install_destination_path }}"
virtualenv_site_packages: "no" virtualenv_site_packages: "no"
virtualenv_python: "{{ venv_python_executable }}"
extra_args: >- extra_args: >-
--find-links {{ venv_wheel_destination_path }}/ --find-links {{ venv_build_wheel_path }}/
--log /var/log/python_venv_build.log --log /var/log/python_venv_build.log
{{ venv_pip_install_args }} {{ venv_pip_install_args }}
register: _install_venv_pip_packages register: _install_venv_pip_packages
@ -78,53 +79,66 @@
notify: notify:
- venv changed - venv changed
- name: Package the venv when venv_reuse_enable is enabled - name: Package the venv when venv_build_package is enabled
when: when:
- venv_reuse_enable | bool - venv_build_package | bool
block: block:
- name: Clean up the virtualenv before packaging - name: Clean up the virtualenv before packaging
shell: | shell: |
find {{ venv_destination_path }}/bin -type f -name '*.pyc' -delete find {{ venv_install_destination_path }}/bin -type f -name '*.pyc' -delete
when: when:
- _install_venv_pip_packages is mapping - _install_venv_pip_packages is mapping
- _install_venv_pip_packages | changed - _install_venv_pip_packages | changed
# Note(odyssey4me): # Note(odyssey4me):
# We purposefully use shell instead of the archive module # We purposefully use shell instead of the archive module
# here. The archive module's output is far too verbose to # here. The archive module's output is far too verbose to
# be practical when debugging. # be practical when debugging.
- name: Package venv - name: Package venv
command: | command: |
tar czf '{{ venv_destination_path }}.tgz' -C '{{ venv_destination_path }}' . tar czf '{{ venv_build_archive_path }}/{{ venv_install_destination_path | basename }}.tgz' -C '{{ venv_install_destination_path }}' .
args: args:
chdir: "{{ venv_destination_path }}" chdir: "{{ venv_install_destination_path }}"
warn: no warn: no
register: _venv_package_build register: _venv_package_build
when: when:
- _install_venv_pip_packages is mapping - _install_venv_pip_packages is mapping
- _install_venv_pip_packages | changed - _install_venv_pip_packages | changed
- name: Prepare checksum for packaged venv - name: Prepare checksum for packaged venv
shell: | shell: |
sha1sum '{{ venv_destination_path }}.tgz' | awk '{print $1}' > '{{ venv_destination_path }}.checksum' 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: args:
executable: /bin/bash executable: /bin/bash
when: when:
- _venv_package_build is mapping - _venv_package_build is mapping
- _venv_package_build | changed - _venv_package_build | changed
- name: Copy the packaged venv and checksum file to the deployment host - name: Ensure that venv_install_source_path exists on the deployment host
fetch: file:
src: "{{ item.src }}" path: "{{ venv_install_source_path }}"
dest: "{{ item.dest }}" state: directory
flat: yes owner: "{{ lookup('env', 'USER') }}"
with_items: recurse: yes
- src: "{{ venv_destination_path }}.tgz" delegate_to: localhost
dest: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.tgz" run_once: yes
- src: "{{ venv_destination_path }}.checksum" when:
dest: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.checksum" - _venv_source == 'file'
when: - inventory_hostname != 'localhost'
- _venv_source == 'file'
- _venv_package_build is mapping - name: Copy the packaged venv and checksum file to the deployment host
- _venv_package_build | changed 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'

View File

@ -13,34 +13,59 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # 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: copy:
src: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.checksum" src: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.checksum"
dest: "{{ venv_destination_path | dirname }}/" dest: "{{ venv_install_destination_path | dirname }}/"
register: _venv_checksum_copy register: _venv_checksum_copy
when: when:
- _venv_source == 'file' - _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: uri:
url: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.checksum" url: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.checksum"
dest: "{{ venv_destination_path | dirname }}/" dest: "{{ venv_install_destination_path | dirname }}/"
return_content: yes return_content: yes
register: _venv_checksum_download register: _venv_checksum_download
when: when:
- _venv_source == 'url' - _venv_source == 'url'
- name: Attempt venv download - name: Download the venv archive
get_url: get_url:
url: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.tgz" url: "{{ venv_install_source_path }}/{{ venv_install_destination_path | basename }}.tgz"
dest: "{{ venv_destination_path | dirname }}/" dest: "{{ venv_install_destination_path | dirname }}/"
checksum: "sha1:{{ _venv_checksum_download.content | trim }}" checksum: "sha1:{{ _venv_checksum_download.content | trim }}"
when: when:
- _venv_source == 'url' - _venv_source == 'url'
- name: Remove existing venv on target host if it is changing - name: Remove existing venv on target host if it is changing
file: file:
path: "{{ venv_destination_path }}" path: "{{ venv_install_destination_path }}"
state: absent state: absent
when: when:
- (_venv_checksum_copy is mapping and _venv_checksum_copy | changed) or - (_venv_checksum_copy is mapping and _venv_checksum_copy | changed) or
@ -48,15 +73,15 @@
- name: Create venv directory on the target host - name: Create venv directory on the target host
file: file:
path: "{{ venv_destination_path }}" path: "{{ venv_install_destination_path }}"
state: directory state: directory
register: _venv_dir_create register: _venv_dir_create
- name: Unarchive pre-built venv - name: Unarchive pre-built venv
unarchive: unarchive:
src: "{{ venv_reuse_download_venv_path }}/{{ venv_destination_path | basename }}.tgz" src: "{{ venv_install_destination_path }}.tgz"
dest: "{{ venv_destination_path }}" dest: "{{ venv_install_destination_path }}"
remote_src: no remote_src: yes
when: when:
- (_venv_checksum_copy is mapping and _venv_checksum_copy | changed) or - (_venv_checksum_copy is mapping and _venv_checksum_copy | changed) or
(_venv_checksum_download is mapping and _venv_checksum_download | 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 # to https://github.com/pypa/virtualenv/issues/565
- name: Update virtualenv python and paths - name: Update virtualenv python and paths
shell: | shell: |
sed -si '1s/^.*python.*$/#!{{ (venv_destination_path ~ '/bin') | replace ('/','\/') }}\/python/' {{ venv_destination_path }}/bin/* sed -si '1s/^.*python.*$/#!{{ (venv_install_destination_path ~ '/bin') | replace ('/','\/') }}\/python/' {{ venv_install_destination_path }}/bin/*
virtualenv {{ venv_destination_path }} \ virtualenv {{ venv_install_destination_path }} \
{{ (ansible_pkg_mgr == 'apt') | ternary('--always-copy', '') }} \ {{ (ansible_pkg_mgr == 'apt') | ternary('--always-copy', '') }} \
--no-pip \ --no-pip \
--no-setuptools \ --no-setuptools \

View File

@ -13,43 +13,59 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
- name: Verify that venv_destination_path has been provided - name: Verify that venv_install_destination_path has been provided
fail: fail:
msg: | msg: |
The variable venv_destination_path is required and The variable venv_install_destination_path is required and
has not been set has not been set.
when: 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: fail:
msg: | msg: >-
If venv_reuse_build_only is enabled, then venv_reuse_enable must also The required virtualenv version is not present.
be enabled. The minimum version of 13.0.0 is required, but
The variable venv_reuse_enable is set to {{ venv_reuse_enable }}. {{ _virtualenv_version.stdout }} is installed.
The variable venv_reuse_build_only is set to {{ venv_reuse_build_only }}.
when: when:
- venv_reuse_build_only | bool - ((_virtualenv_version.stdout | trim) == 'none') or
- not venv_reuse_enable | bool ((_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: set_fact:
_venv_source: "{{ (venv_reuse_download_venv_path is match('^https?://.*')) | ternary('url', 'file') }}" _venv_source: "{{ ((venv_install_source_path | trim) 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
- name: Check if venv tgz is present on the deployment host - name: Check if venv tgz is present on the deployment host
stat: 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_attributes: no
get_checksum: no get_checksum: no
get_md5: no get_md5: no
@ -59,14 +75,3 @@
run_once: yes run_once: yes
when: when:
- _venv_source == 'file' - _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

View File

@ -3,18 +3,8 @@ localhost
container1 container1
container2 container2
container3 container3
container4
[all_containers] [all_containers]
container1 container1
container2 container2
container3 container3
container4
[test1]
container1
container2
[test2]
container3
container4

View File

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
- name: Clean up from previous tests - name: Clean up from previous tests
hosts: "{{ target_host_group_name }}:localhost" hosts: "{{ build_host }}:{{ install_hosts }}"
become: yes become: yes
any_errors_fatal: yes any_errors_fatal: yes
tasks: tasks:
@ -22,42 +22,87 @@
file: file:
path: "{{ item.path }}" path: "{{ item.path }}"
state: absent state: absent
when: item.condition | default(omit)
with_items: with_items:
- path: "{{ lookup('env', 'HOME') | default('/opt', true) }}/venvs" - path: "{{ lookup('env', 'HOME') }}/archive"
- path: "{{ lookup('env', 'HOME') | default('/opt', true) }}/cache/venvs" - path: "{{ lookup('env', 'HOME') }}/venvs"
- path: "{{ lookup('env', 'HOME') | default('/opt', true) }}/cache/wheels"
condition: "{{ target_host_group_name == 'test1' }}"
- path: "/var/cache/python_wheels"
- name: Clean up facts from previous tests - name: Clean up facts from previous tests
ini_file: ini_file:
path: "/etc/ansible/facts.d/openstack_ansible.fact" path: "/etc/ansible/facts.d/openstack_ansible.fact"
section: "{{ target_host_group_name }}" section: "{{ item }}"
state: absent state: absent
with_items: "{{ build_host.split(':') + install_hosts.split(':') }}"
- name: Refresh the inventory to clear the added groups - name: Refresh the inventory to clear the added groups
meta: refresh_inventory meta: refresh_inventory
- name: Execute role test and verify target host content - name: Set venv_build_archive_path and venv_install_source_path
hosts: "{{ target_host_group_name }}" 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 become: yes
any_errors_fatal: yes any_errors_fatal: yes
serial: "{{ target_serial }}"
vars:
base_directory: "{{ lookup('env', 'HOME') | default('/opt', true) }}"
tasks: tasks:
- name: Execute venv build
- name: Execute role 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: include_role:
name: "python_venv_build" name: "python_venv_build"
private: yes private: yes
vars: vars:
venv_pip_packages:
- "Jinja2==2.10"
venv_destination_path: "{{ base_directory }}/venvs/{{ target_host_group_name }}"
venv_facts_when_changed: venv_facts_when_changed:
- section: "{{ target_host_group_name }}" - section: "{{ inventory_hostname }}"
option: "test" option: "test"
value: True value: True
@ -73,7 +118,7 @@
- name: Verify that the facts were set - name: Verify that the facts were set
assert: assert:
that: 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 - name: Find files/folders on targets
find: find:
@ -81,17 +126,12 @@
get_checksum: no get_checksum: no
recurse: no recurse: no
paths: paths:
- "{{ base_directory }}/venvs" - "{{ venv_install_destination_path | dirname }}"
register: _target_folders register: _target_folders
- name: Compile the folder list from the targets - name: Compile the folder list from the targets
set_fact: set_fact:
_target_folder_list: >- _target_folder_list: "{{ _target_folders['files'] | map(attribute='path') | list }}"
{%- set folder_list = [] %}
{%- for item in _target_folders['files'] %}
{%- set _ = folder_list.append(item['path']) %}
{%- endfor %}
{{ folder_list }}
- name: Show the files/folder from the targets - name: Show the files/folder from the targets
debug: debug:
@ -100,43 +140,4 @@
- name: Verify the folder list from the targets - name: Verify the folder list from the targets
assert: assert:
that: that:
- "{{ base_directory ~ '/venvs/' ~ target_host_group_name in _target_folder_list }}" - "{{ venv_install_destination_path 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 }}"

View File

@ -16,14 +16,38 @@
- name: Prepare the host/containers - name: Prepare the host/containers
include: common/test-setup-host.yml include: common/test-setup-host.yml
- name: Verify that the role works with a serial playbook - name: Verify building on a web server, and installing using a URL
include: test-functional.yml import_playbook: test-functional.yml
vars: vars:
target_host_group_name: test1 build_host: container1
target_serial: 1 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 - name: Verify building on localhost, and installing using a copy
include: test-functional.yml import_playbook: test-functional.yml
vars: vars:
target_host_group_name: test2 build_host: localhost
target_serial: "100%" 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"

View File

@ -28,6 +28,8 @@ setenv =
ROLE_NAME=python_venv_build ROLE_NAME=python_venv_build
VIRTUAL_ENV={envdir} VIRTUAL_ENV={envdir}
WORKING_DIR={toxinidir} WORKING_DIR={toxinidir}
# TODO(odyssey4me): remove after debugging is completed
ANSIBLE_PARAMETERS=-v
[testenv:docs] [testenv:docs]

19
vars/main.yml Normal file
View File

@ -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 }}"