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:
parent
19e2573be8
commit
d169906c68
19
README.rst
19
README.rst
@ -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/
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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 != []
|
||||||
|
@ -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'
|
||||||
|
@ -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 \
|
||||||
|
@ -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
|
|
||||||
|
@ -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
|
|
||||||
|
@ -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 }}"
|
|
||||||
|
@ -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"
|
||||||
|
2
tox.ini
2
tox.ini
@ -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
19
vars/main.yml
Normal 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 }}"
|
Loading…
Reference in New Issue
Block a user