From 9765cdd6d0a092dc5a2760f46282aced444a0121 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Thu, 23 May 2019 12:40:30 +1000 Subject: [PATCH] DCD-224: Rework version logic to allow upgrades to override the cached version value. --- roles/product_install/defaults/main.yml | 8 +- .../jira_cached_with_downgrade/Dockerfile.j2 | 14 +++ .../jira_cached_with_downgrade/molecule.yml | 33 ++++++ .../jira_cached_with_downgrade/playbook.yml | 25 ++++ .../tests/test_default.py | 26 +++++ .../jira_cached_with_upgrade/Dockerfile.j2 | 14 +++ .../jira_cached_with_upgrade/molecule.yml | 33 ++++++ .../jira_cached_with_upgrade/playbook.yml | 25 ++++ .../tests/test_default.py | 26 +++++ .../jira_version_from_file/playbook.yml | 3 +- .../tasks/jira-servicedesk_version_latest.yml | 2 +- roles/product_install/tasks/main.yml | 109 ++++++++++++++---- .../tasks/product_version_latest.yml | 2 +- 13 files changed, 293 insertions(+), 27 deletions(-) create mode 100644 roles/product_install/molecule/jira_cached_with_downgrade/Dockerfile.j2 create mode 100644 roles/product_install/molecule/jira_cached_with_downgrade/molecule.yml create mode 100644 roles/product_install/molecule/jira_cached_with_downgrade/playbook.yml create mode 100644 roles/product_install/molecule/jira_cached_with_downgrade/tests/test_default.py create mode 100644 roles/product_install/molecule/jira_cached_with_upgrade/Dockerfile.j2 create mode 100644 roles/product_install/molecule/jira_cached_with_upgrade/molecule.yml create mode 100644 roles/product_install/molecule/jira_cached_with_upgrade/playbook.yml create mode 100644 roles/product_install/molecule/jira_cached_with_upgrade/tests/test_default.py diff --git a/roles/product_install/defaults/main.yml b/roles/product_install/defaults/main.yml index 3024352..9b26675 100644 --- a/roles/product_install/defaults/main.yml +++ b/roles/product_install/defaults/main.yml @@ -1,14 +1,18 @@ --- +# Empty values to simplify logic (no undefineds) +atl_latest_version: '' +atl_cached_version: '' + atl_product_latest_version_url: "https://marketplace.atlassian.com/rest/2/applications/{{ atl_product_family }}/versions/latest" atl_product_version_cache_dir: "{{ atl_product_home_shared }}" atl_product_version_cache: "{{ atl_product_home_shared }}/{{ atl_product_edition }}.version" atl_release_base_url: "https://product-downloads.atlassian.com/software" atl_product_base_url: "{{ atl_release_base_url }}/{{ atl_product_family }}/downloads" -atl_product_download_url: "{{ atl_product_base_url }}/atlassian-{{ atl_download_edition | default(atl_product_edition) }}-{{ atl_download_version | default(atl_product_version) }}-x64.bin" +atl_product_download_url: "{{ atl_product_base_url }}/atlassian-{{ atl_download_edition | default(atl_product_edition) }}-{{ atl_product_version }}-x64.bin" -atl_product_download_filename: "{{ atl_download_edition | default(atl_product_edition) }}.{{ atl_download_version | default(atl_product_version) }}.bin" +atl_product_download_filename: "{{ atl_download_edition | default(atl_product_edition) }}.{{ atl_product_version }}.bin" atl_product_download: "{{ atl_installer_temp }}/{{ atl_product_download_filename }}" atl_product_varfile: "{{ atl_installer_temp }}/{{ atl_product_family }}.varfile" diff --git a/roles/product_install/molecule/jira_cached_with_downgrade/Dockerfile.j2 b/roles/product_install/molecule/jira_cached_with_downgrade/Dockerfile.j2 new file mode 100644 index 0000000..e6aa95d --- /dev/null +++ b/roles/product_install/molecule/jira_cached_with_downgrade/Dockerfile.j2 @@ -0,0 +1,14 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi diff --git a/roles/product_install/molecule/jira_cached_with_downgrade/molecule.yml b/roles/product_install/molecule/jira_cached_with_downgrade/molecule.yml new file mode 100644 index 0000000..2caa40b --- /dev/null +++ b/roles/product_install/molecule/jira_cached_with_downgrade/molecule.yml @@ -0,0 +1,33 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint +platforms: + - name: amazon_linux2 + image: amazonlinux:2 + groups: + - aws_node_local + - name: ubuntu_lts + image: ubuntu:bionic + groups: + - aws_node_local +provisioner: + name: ansible + options: + vvv: true + skip-tags: runtime_pkg + lint: + name: ansible-lint + inventory: + links: + group_vars: ../../../../group_vars/ +verifier: + name: testinfra + additional_files_or_dirs: + - ../../resources/tests/test_*.py + lint: + name: flake8 + enabled: false diff --git a/roles/product_install/molecule/jira_cached_with_downgrade/playbook.yml b/roles/product_install/molecule/jira_cached_with_downgrade/playbook.yml new file mode 100644 index 0000000..ed658e6 --- /dev/null +++ b/roles/product_install/molecule/jira_cached_with_downgrade/playbook.yml @@ -0,0 +1,25 @@ +--- +- name: Converge + hosts: all + vars: + atl_product_family: "jira" + atl_product_edition: "jira-core" + atl_product_user: "jira" + # NOTE: This should be honoured as it is higher than the cached version below. + atl_product_version: "7.10.1" + + pre_tasks: + - name: Create cache dir + file: + path: '/media/atl/jira/shared/' + state: directory + - name: Seed version + copy: + dest: '/media/atl/jira/shared/jira-core.version' + content: "7.10.2" + force: false # For idempotency check + + roles: + - role: linux_common + - role: product_common + - role: product_install diff --git a/roles/product_install/molecule/jira_cached_with_downgrade/tests/test_default.py b/roles/product_install/molecule/jira_cached_with_downgrade/tests/test_default.py new file mode 100644 index 0000000..98cd175 --- /dev/null +++ b/roles/product_install/molecule/jira_cached_with_downgrade/tests/test_default.py @@ -0,0 +1,26 @@ +import os +import urllib.request + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_version_is_correct(host): + verfile = host.file('/media/atl/jira/shared/jira-core.version') + assert verfile.exists + + assert verfile.content.decode("UTF-8").strip() == "7.10.2" + +def test_is_downloaded(host): + installer = host.file('/opt/atlassian/tmp/jira-core.7.10.2.bin') + assert installer.exists + assert installer.user == 'root' + +def test_is_unpacked(host): + installer = host.file('/opt/atlassian/jira-core/7.10.2/atlassian-jira/') + assert installer.exists + assert installer.is_directory + assert installer.user == 'jira' + assert installer.mode == 0o0755 diff --git a/roles/product_install/molecule/jira_cached_with_upgrade/Dockerfile.j2 b/roles/product_install/molecule/jira_cached_with_upgrade/Dockerfile.j2 new file mode 100644 index 0000000..e6aa95d --- /dev/null +++ b/roles/product_install/molecule/jira_cached_with_upgrade/Dockerfile.j2 @@ -0,0 +1,14 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi diff --git a/roles/product_install/molecule/jira_cached_with_upgrade/molecule.yml b/roles/product_install/molecule/jira_cached_with_upgrade/molecule.yml new file mode 100644 index 0000000..2caa40b --- /dev/null +++ b/roles/product_install/molecule/jira_cached_with_upgrade/molecule.yml @@ -0,0 +1,33 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint +platforms: + - name: amazon_linux2 + image: amazonlinux:2 + groups: + - aws_node_local + - name: ubuntu_lts + image: ubuntu:bionic + groups: + - aws_node_local +provisioner: + name: ansible + options: + vvv: true + skip-tags: runtime_pkg + lint: + name: ansible-lint + inventory: + links: + group_vars: ../../../../group_vars/ +verifier: + name: testinfra + additional_files_or_dirs: + - ../../resources/tests/test_*.py + lint: + name: flake8 + enabled: false diff --git a/roles/product_install/molecule/jira_cached_with_upgrade/playbook.yml b/roles/product_install/molecule/jira_cached_with_upgrade/playbook.yml new file mode 100644 index 0000000..dcf29a6 --- /dev/null +++ b/roles/product_install/molecule/jira_cached_with_upgrade/playbook.yml @@ -0,0 +1,25 @@ +--- +- name: Converge + hosts: all + vars: + atl_product_family: "jira" + atl_product_edition: "jira-core" + atl_product_user: "jira" + # NOTE: This should be honoured as it is higher than the cached version below. + atl_product_version: "7.10.1" + + pre_tasks: + - name: Create cache dir + file: + path: '/media/atl/jira/shared/' + state: directory + - name: Seed version + copy: + dest: '/media/atl/jira/shared/jira-core.version' + content: "7.9.0" + force: false # For idempotency check + + roles: + - role: linux_common + - role: product_common + - role: product_install diff --git a/roles/product_install/molecule/jira_cached_with_upgrade/tests/test_default.py b/roles/product_install/molecule/jira_cached_with_upgrade/tests/test_default.py new file mode 100644 index 0000000..4e96866 --- /dev/null +++ b/roles/product_install/molecule/jira_cached_with_upgrade/tests/test_default.py @@ -0,0 +1,26 @@ +import os +import urllib.request + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_version_is_correct(host): + verfile = host.file('/media/atl/jira/shared/jira-core.version') + assert verfile.exists + + assert verfile.content.decode("UTF-8").strip() == "7.10.1" + +def test_is_downloaded(host): + installer = host.file('/opt/atlassian/tmp/jira-core.7.10.1.bin') + assert installer.exists + assert installer.user == 'root' + +def test_is_unpacked(host): + installer = host.file('/opt/atlassian/jira-core/7.10.1/atlassian-jira/') + assert installer.exists + assert installer.is_directory + assert installer.user == 'jira' + assert installer.mode == 0o0755 diff --git a/roles/product_install/molecule/jira_version_from_file/playbook.yml b/roles/product_install/molecule/jira_version_from_file/playbook.yml index 8190b68..271343f 100644 --- a/roles/product_install/molecule/jira_version_from_file/playbook.yml +++ b/roles/product_install/molecule/jira_version_from_file/playbook.yml @@ -5,7 +5,7 @@ atl_product_family: "jira" atl_product_edition: "jira-core" atl_product_user: "jira" - # NOTE: This should be ignored because the version file exists. + # NOTE: This should be ignored because the version file exists (below). atl_product_version: "latest" pre_tasks: @@ -17,6 +17,7 @@ copy: dest: '/media/atl/jira/shared/jira-core.version' content: "7.9.0" + force: false # For idempotency check roles: - role: linux_common diff --git a/roles/product_install/tasks/jira-servicedesk_version_latest.yml b/roles/product_install/tasks/jira-servicedesk_version_latest.yml index eb87868..e7256ed 100644 --- a/roles/product_install/tasks/jira-servicedesk_version_latest.yml +++ b/roles/product_install/tasks/jira-servicedesk_version_latest.yml @@ -6,4 +6,4 @@ - name: Set the version for ServiceDesk set_fact: - atl_product_version: "{{ atl_servicedesk_version_json.name }}" + atl_latest_version: "{{ atl_servicedesk_version_json.name }}" diff --git a/roles/product_install/tasks/main.yml b/roles/product_install/tasks/main.yml index b0edfe3..67a5251 100644 --- a/roles/product_install/tasks/main.yml +++ b/roles/product_install/tasks/main.yml @@ -1,20 +1,5 @@ --- -- name: Create installation directories - file: - path: "{{ item }}" - state: directory - mode: 0750 - owner: "{{ atl_product_user }}" - group: "{{ atl_product_user }}" - with_items: - - "{{ atl_installer_temp }}" - - "{{ atl_product_home }}" - - "{{ atl_product_installation_versioned }}" - - "{{ atl_product_version_cache_dir }}" - changed_when: false # For Molecule idempotence check - - - name: Check for existing version cache file stat: path: "{{ atl_product_version_cache }}" @@ -31,11 +16,17 @@ - name: Set the local var to cached version set_fact: - atl_product_version: "{{ atl_product_version_file.stdout }}" + atl_cached_version: "{{ atl_product_version_file.stdout }}" when: cached.stat.exists +- name: Determine if requested version is 'latest' + set_fact: + version_is_latest: "{{ atl_product_version is undefined or + not atl_product_version or + atl_product_version == 'latest' }}" + # Case: File doesn't exist and no version has been set; find latest. - name: Fetch and cache latest version when no override block: @@ -43,23 +34,97 @@ - name: Fetch the latest edition version include_tasks: "{{ atl_product_edition }}_version_latest.yml" - when: - not cached.stat.exists and - (atl_product_version is undefined or - not atl_product_version or - atl_product_version == "latest") + when: not cached.stat.exists and version_is_latest + + +###################################################################### +# Version logic: +# +# At this point we have 3 values (possibly empty): +# +# * atl_product_version (supplied) +# * atl_cached_version +# * atl_latest_version +# +# If no cached value, use the supplied value or 'latest' if unset. +# +# If a cached file exists, and the requested version is 'latest' (or +# unset), cache wins. +# +# If a version is set, then it is honoured _if_ it is higher than the +# cached value (i.e. upgrade path). + +- name: "Case: Version is latest" + block: + + - name: "Case: Cached version exists, has precedence over 'latest'" + set_fact: + atl_download_version: "{{ atl_cached_version }}" + when: cached.stat.exists + + - name: "Case: No cached version, use latest" + set_fact: + atl_download_version: "{{ atl_latest_version }}" + when: not cached.stat.exists + + when: version_is_latest + +- name: "Case: Version is not latest" + block: + + - name: "Case: No cached version, or but supplied is higher; use supplied" + set_fact: + atl_download_version: "{{ atl_product_version }}" + when: (not cached.stat.exists) or + atl_product_version is version(atl_cached_version, '>') + + - name: "Case: Cached version is higher, ignore supplied" + set_fact: + atl_download_version: "{{ atl_cached_version }}" + when: cached.stat.exists and + atl_product_version is version(atl_cached_version, '<=') + + when: not version_is_latest + + +- name: "Fallthrough guard: Use cached or supplied version if nothing set" + set_fact: + atl_download_version: "{{ atl_cached_version or atl_product_version }}" + when: atl_download_version is not defined or + atl_download_version|length == 0 + +- name: Override the supplied version with the calculated one + set_fact: + atl_product_version: "{{ atl_download_version }}" + +###################################################################### - name: Perform any additional per-edition version setup include_tasks: "{{ atl_product_edition }}_extra_tasks.yml" +- name: Create installation directories + file: + path: "{{ item }}" + state: directory + mode: 0750 + owner: "{{ atl_product_user }}" + group: "{{ atl_product_user }}" + with_items: + - "{{ atl_installer_temp }}" + - "{{ atl_product_home }}" + - "{{ atl_product_installation_versioned }}" + - "{{ atl_product_version_cache_dir }}" + changed_when: false # For Molecule idempotence check + + # At this point atl_product_version should be set, cache if necessary. - name: Write override cached version when specified template: src: version.j2 dest: "{{ atl_product_version_cache }}" - force: false + force: true # Note: We don't the cache binary in the shared drive to the complexity # around download race-conditions if multiple nodes are starting at diff --git a/roles/product_install/tasks/product_version_latest.yml b/roles/product_install/tasks/product_version_latest.yml index ecad36f..9c77711 100644 --- a/roles/product_install/tasks/product_version_latest.yml +++ b/roles/product_install/tasks/product_version_latest.yml @@ -10,4 +10,4 @@ - name: Set the local var to retrieved version set_fact: - atl_product_version: "{{ atl_product_version_json.version }}" + atl_latest_version: "{{ atl_product_version_json.version }}"