From b79993c3311d3d1081413326caaafb98896723d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Tue, 11 May 2021 09:22:02 +0200 Subject: [PATCH] ansible: add versioncheck.py script to verify role versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was originally introduced to `infra-nimbus` and proved robust. Signed-off-by: Jakub SokoĊ‚owski --- Makefile | 9 +++-- ansible/bootstrap.yml | 10 ++++++ ansible/main.yml | 10 ++++++ ansible/requirements.yml | 8 +++++ ansible/versioncheck.py | 71 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 2 deletions(-) create mode 100755 ansible/versioncheck.py diff --git a/Makefile b/Makefile index d44f606..5c27807 100644 --- a/Makefile +++ b/Makefile @@ -19,8 +19,13 @@ PROVISIONER_PATH = $(TF_PLUGINS_DIR)/$(ARCH)/$(PROVISIONER_NAME)_$(PROVISIONER_V all: requirements install-provisioner secrets init-terraform @echo "Success!" -requirements: - ansible-galaxy install --ignore-errors --force -r ansible/requirements.yml +requirements-install: + ansible-galaxy install --keep-scm-meta --ignore-errors --force -r ansible/requirements.yml + +requirements-check: + ansible/versioncheck.py + +requirements: requirements-install requirements-check $(PROVISIONER_PATH): @mkdir -p $(TF_PLUGINS_DIR)/$(ARCH); \ diff --git a/ansible/bootstrap.yml b/ansible/bootstrap.yml index 7f9486b..e7cdc88 100644 --- a/ansible/bootstrap.yml +++ b/ansible/bootstrap.yml @@ -9,6 +9,16 @@ # # This is run on every newly provisioned host. # +- name: Verify Ansible versions + hosts: all + tags: always + become: false + run_once: true + gather_facts: false + tasks: + - local_action: command ./versioncheck.py + changed_when: false + - name: Bootstrap Python support for Ansible gather_facts: False hosts: all diff --git a/ansible/main.yml b/ansible/main.yml index df414b9..ef90dc9 100644 --- a/ansible/main.yml +++ b/ansible/main.yml @@ -1,4 +1,14 @@ --- +- name: Verify Ansible versions + hosts: all + tags: always + become: false + run_once: true + gather_facts: false + tasks: + - local_action: command ./versioncheck.py + changed_when: false + - name: Install certs, open ports, add SWAP hosts: faucet-master roles: diff --git a/ansible/requirements.yml b/ansible/requirements.yml index 0218fbe..507dd22 100644 --- a/ansible/requirements.yml +++ b/ansible/requirements.yml @@ -1,31 +1,39 @@ - name: nginx src: git@github.com:status-im/ansible-role-nginx.git + version: 3043c998cbc92a634a71dc48363b3e2525696d26 scm: git - name: origin-certs src: git@github.com:status-im/infra-role-origin-certs.git + version: 71c3cca0f250f86754d54ec74ddaddbc34f81ebb scm: git - name: open-ports src: git@github.com:status-im/infra-role-open-ports.git + version: 54125c7d291289aaea51ca313fc694d057d803fa scm: git - name: infra-role-tinc src: git@github.com:status-im/infra-role-tinc.git + version: bca648485def8e7a34ed5403bbaf403a2537279a scm: git - name: infra-role-bootstrap src: git@github.com:status-im/infra-role-bootstrap.git + version: 244ed6a740d6c20250024de9ae1a0232d71b1f57 scm: git - name: consul-service src: git@github.com:status-im/infra-role-consul-service.git + version: b1d5ad5caa7d7a036fd175292fa497175bb7c54c scm: git - name: infra-role-geth src: git@github.com:status-im/infra-role-geth.git + version: f76e6f37792dc39302d175017f79a4711ecf33df scm: git - name: infra-role-geth-exporter src: git+git@github.com:status-im/infra-role-geth-exporter.git + version: b187f16ad9e3dcf1e3024c6189994b71f26f5fde scm: git diff --git a/ansible/versioncheck.py b/ansible/versioncheck.py new file mode 100755 index 0000000..d88a47e --- /dev/null +++ b/ansible/versioncheck.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# WARNING: If importing this fails set PYTHONPATH. +import yaml +import ansible +import subprocess +from os import path, environ +from packaging import version + +SCRIPT_DIR = path.dirname(path.realpath(__file__)) +# Where Ansible looks for installed roles. +ANSIBLE_ROLES_PATH = path.join(environ['HOME'], '.ansible/roles') + + +class Role: + def __init__(self, name, version): + self.name = name + self.version = version + + @property + def path(self): + return path.join(ANSIBLE_ROLES_PATH, self.name) + + def exists(self): + return path.isdir(self.path) + + def local_version(self): + cmd = subprocess.run( + ['git', 'rev-parse', 'HEAD'], + capture_output=True, + cwd=self.path + ) + cmd.check_returncode() + return str(cmd.stdout.strip(), 'utf-8') + + +# Verify Ansible version is 2.8 or newer. +if version.parse(ansible.__version__) < version.parse("2.8"): + print('Your Ansible version is lower than 2.8. Upgrade it.') + exit(1) + +# Read Ansible requirements file. +with open(path.join(SCRIPT_DIR, 'requirements.yml'), 'r') as f: + requirements = yaml.load(f, Loader=yaml.FullLoader) + +# Check if each Ansible role is installed and has correct version. +errors = 0 +for req in requirements: + role = Role(req['name'], req.get('version')) + + if not role.exists(): + print('%25s - MISSING!' % role.name) + errors += 1 + continue + + # For now we allow not specifying versions for everyhing. + if role.version is None: + print('%25s - No version!' % role.name) + continue + + local_version = role.local_version() + if role.version != local_version: + print('%25s - MISMATCH: %s != %s' % + (role.name, role.version[:8], local_version[:8])) + errors += 1 + continue + + print('%25s - VALID' % role.name) + +# Any issue with any role should cause failure. +if errors > 0: + exit(1)