From 498376149be878ed869df53ea75c98b634a1476a Mon Sep 17 00:00:00 2001 From: Vincent Chov Date: Wed, 1 Jan 2020 15:35:30 -0500 Subject: [PATCH] Improve idempotency by allowing the user to uninstall existing Python interpreters that lack desired Python configure options (#42) * Bump require Ansible version from 1.9.4 to 2.5.0 * Add but don't use custom fact checker that checks if desired Python installations are missing or need to be re-compiled * Use the facts checker to check existing installations for pyenv_python_configure_opts options * Uninstall existing python installations that have the wrong configure flags * Install python versions using the 'environment' and 'args' keys and also use the creates options * Uninstall Python intrepreters w/ wrong configure opts only when the user chooses to --- .travis.yml | 2 +- defaults/main.yml | 7 +++-- meta/main.yml | 2 +- tasks/custom_facts.yml | 25 +++++++++++++++++ tasks/install.yml | 16 +++++++++-- tasks/main.yml | 15 +++++++--- templates/check-configure-options.py.j2 | 6 ++++ templates/pyenv_python_installations.fact.j2 | 29 ++++++++++++++++++++ 8 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 tasks/custom_facts.yml create mode 100644 templates/check-configure-options.py.j2 create mode 100644 templates/pyenv_python_installations.fact.j2 diff --git a/.travis.yml b/.travis.yml index 5653b85..ef8bed7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ before_install: - sudo apt-get update -qq - sudo apt-get install -qq python-apt python-pycurl install: - - pip install ansible==1.9.4 + - pip install ansible==2.5.0 script: - echo localhost > inventory - ansible-playbook -i inventory test.yml --syntax-check diff --git a/defaults/main.yml b/defaults/main.yml index 10f8c3e..c2222df 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -17,6 +17,7 @@ pyenv_update: no # additional options for the build process, e.g "--enable-shared" pyenv_python_configure_opts: "" +pyenv_uninstall_python_w_wrong_configure_opts: no pyenv_debian_packages: - build-essential @@ -30,9 +31,9 @@ pyenv_debian_packages: - libsqlite3-dev - libreadline-dev - zlib1g-dev - - wget - - llvm - - libncurses5-dev + - wget + - llvm + - libncurses5-dev - xz-utils - tk-dev - libxml2-dev diff --git a/meta/main.yml b/meta/main.yml index db0a19d..5a3a8be 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -11,7 +11,7 @@ galaxy_info: # - Apache # - CC-BY license: MIT - min_ansible_version: 2.0 + min_ansible_version: 2.5 # # Below are all platforms currently available. Just uncomment # the ones that apply to your role. If you don't see your diff --git a/tasks/custom_facts.yml b/tasks/custom_facts.yml new file mode 100644 index 0000000..8ee43b8 --- /dev/null +++ b/tasks/custom_facts.yml @@ -0,0 +1,25 @@ +--- +- name: Create folder for custom facts + file: + path: /etc/ansible/facts.d + state: directory + +- name: Copy over check-configure-options.py + template: + src: templates/check-configure-options.py.j2 + dest: /etc/ansible/facts.d/check-configure-options.py + owner: "{{ pyenv_owner }}" + group: "{{ pyenv_owner }}" + mode: "0755" + +- name: Copy over python_check fact file + template: + src: templates/pyenv_python_installations.fact.j2 + dest: /etc/ansible/facts.d/pyenv_python_installations.fact + owner: "{{ pyenv_owner }}" + group: "{{ pyenv_owner }}" + mode: "0755" + +- name: Reload setup to gather custom facts + setup: + filter: ansible_local diff --git a/tasks/install.yml b/tasks/install.yml index 2351254..f733a78 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -42,10 +42,20 @@ - name: Update Pyenv interpreter list shell: . {{ pyenv_path }}/.pyenvrc && pyenv update when: pyenv_update - + +- name: Uninstall existing Python interpreters w/ wrong compilation flags + shell: ". {{ pyenv_path }}/.pyenvrc && pyenv uninstall -f {{ item }}" + args: + removes: "{{ pyenv_path }}/versions/{{ item }}/bin/python" + loop: "{{ ansible_local['pyenv_python_installations']['to_reinstall'] | default([]) }}" + when: pyenv_uninstall_python_w_wrong_configure_opts + - name: Install Python interpreters "{{ pyenv_python_versions }}" - shell: . {{ pyenv_path }}/.pyenvrc && env PYTHON_CONFIGURE_OPTS="{{ pyenv_python_configure_opts }}" pyenv install {{ item }} - creates="{{ pyenv_path }}/versions/{{ item }}/bin/python" + shell: ". {{ pyenv_path }}/.pyenvrc && pyenv install {{ item }}" + environment: + PYTHON_CONFIGURE_OPTS: "{{ pyenv_python_configure_opts }}" + args: + creates: "{{ pyenv_path }}/versions/{{ item }}/bin/python" with_items: "{{ pyenv_python_versions }}" - name: Create virtual environments diff --git a/tasks/main.yml b/tasks/main.yml index 60cff72..9403ad0 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,20 +1,27 @@ --- +- include: custom_facts.yml + become: true + become_user: "{{ pyenv_owner }}" + when: pyenv_env == "user" + +- include: custom_facts.yml + become: true + when: pyenv_env == "system" + - include: Darwin.yml when: ansible_os_family == "Darwin" - include: Debian.yml when: ansible_os_family == "Debian" - + - include: RedHat.yml when: ansible_os_family == "RedHat" - - include: install.yml become: true become_user: "{{ pyenv_owner }}" when: pyenv_env == "user" - + - include: install.yml become: true when: pyenv_env == "system" - diff --git a/templates/check-configure-options.py.j2 b/templates/check-configure-options.py.j2 new file mode 100644 index 0000000..4b12957 --- /dev/null +++ b/templates/check-configure-options.py.j2 @@ -0,0 +1,6 @@ +import sysconfig + +config_args = sysconfig.get_config_var("CONFIG_ARGS") +config_args = config_args.replace("'", "").split() +required_args = {{ pyenv_python_configure_opts.split() }} +print(all(s in config_args for s in required_args)) diff --git a/templates/pyenv_python_installations.fact.j2 b/templates/pyenv_python_installations.fact.j2 new file mode 100644 index 0000000..2355933 --- /dev/null +++ b/templates/pyenv_python_installations.fact.j2 @@ -0,0 +1,29 @@ +#!/bin/bash + +configure_opts_checker="/etc/ansible/facts.d/check-configure-options.py" + +declare -a installs_to_check=({{ " ".join(pyenv_python_versions) }}) +declare -a to_reinstall=() +declare -a to_install=() + +# Join array to string +function join { local IFS="$1"; shift; echo "[$*]"; } + +for version in "${installs_to_check[@]}" +do +py_installation="{{ pyenv_path }}/versions/$version/bin/python" + + if [[ -x "$py_installation" ]]; then + is_valid_install=$("$py_installation" "$configure_opts_checker") + + if [[ $is_valid_install =~ "False" ]]; then + to_reinstall+=("\"$version\"") + fi + else + to_install+=("\"$version\"") + fi +done + +to_reinstall_str=$(join , ${to_reinstall[@]}) +to_install_str=$(join , ${to_install[@]}) +printf "{ \"to_reinstall\": "$to_reinstall_str", \"to_install\": "$to_install_str" }\n"