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 fe949ba..c8f6189 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: Configure Avalanche hosts hosts: avalanche roles: diff --git a/ansible/requirements.yml b/ansible/requirements.yml index 053081c..c9c55bd 100644 --- a/ansible/requirements.yml +++ b/ansible/requirements.yml @@ -1,20 +1,20 @@ --- - name: open-ports src: git@github.com:status-im/infra-role-open-ports.git - scm: git - -- name: infra-role-tinc - src: git@github.com:status-im/infra-role-tinc.git + version: 54125c7d291289aaea51ca313fc694d057d803fa scm: git - name: infra-role-bootstrap src: git@github.com:status-im/infra-role-bootstrap.git + version: efd7dd1f249bc4cb4f9dcc9ee2ff4ce04f9ac3bd scm: git - name: consul-service src: git@github.com:status-im/infra-role-consul-service.git + version: b1d5ad5caa7d7a036fd175292fa497175bb7c54c scm: git - name: swap-file src: git@github.com:status-im/infra-role-swap-file.git + version: 7b63fb7b5f0c525aa191e1a410fd79f7eab8d11a 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)