.gitignore
@@ -31,3 +31,6 @@ .vscode/settings.json __pycache__ *.pyc dynamic-cache dynamic-roles ansible/ansible.cfg
@@ -1,6 +1,6 @@ [defaults] nocows = 1 roles_path = roles-infra:ansible/roles-infra:roles:ansible/roles roles_path = dynamic-roles:roles-infra:ansible/roles-infra:roles:ansible/roles forks = 50 become = False gathering = smart ansible/install_galaxy_roles.yml
@@ -44,3 +44,7 @@ and r_requirements_content | length > 0 and r_requirements_content is mapping and "collections" in r_requirements_content - name: Install dynamic sources include_role: name: agnosticd_dynamic ansible/roles/agnosticd_dynamic/README.adoc
New file @@ -0,0 +1,35 @@ = agnosticd_dynamic This Ansible role is used during AgnosticD setup to download dynamic sources from Ansible Galaxy and Git. == Variables `agnosticd_dynamic_roles_dir` - Directory in which to install Ansible roles. This directory should be included in the `ANSIBLE_ROLES_PATH`, which may be set by the `roles_path` in the `[defaults]` section of `ansible.cfg`. Default value `{{ playbook_dir }}/dynamic-roles`. `agnosticd_dynamic_cache_dir` - Directory in which to install sources which should be saved between executions. Default value `{{ playbook_dir }}/dynamic-cache`, but should be configured outside of the playbook directory to preserve data when executing inside Ansible Tower. `agnosticd_dynamic_role_galaxy_sources` - List of Ansible Galaxy role sources. Values are specified as in an Ansible `requirements.yml` (https://galaxy.ansible.com/docs/using/installing.html). If the version is specified with a semantic version syntax then the role source is saved to a cache directory and a link is created from the roles directory. -------------------- agnosticd_dynamic_role_galaxy_sources: - name: k8s_config src: redhat-cop.k8s_config version: 0.2.0 -------------------- `agnosticd_dynamic_role_git_sources` - List of Git sources to install. Each source is specified using options to the `git` module (https://docs.ansible.com/ansible/latest/modules/git_module.html). In addition, `role_paths` may be specified as a dictionary of names and paths within the repository: -------------------- agnosticd_dynamic_role_git_sources: - repo: https://github.com/redhat-cop/agnosticd.git version: ocp4-workshop-prod-1.41 role_paths: ocp4-workload-infra-nodes: ansible/roles/ocp4-workload-infra-nodes -------------------- ansible/roles/agnosticd_dynamic/defaults/main.yml
New file @@ -0,0 +1,6 @@ --- agnosticd_dynamic_cache_dir: "{{ playbook_dir }}/dynamic-cache" agnosticd_dynamic_roles_dir: "{{ playbook_dir }}/dynamic-roles" agnosticd_dynamic_role_galaxy_sources: [] agnosticd_dynamic_role_git_sources: [] #agnosticd_dynamic_git_executable: ... ansible/roles/agnosticd_dynamic/filter_plugins/agnosticd_dynamic.py
New file @@ -0,0 +1,46 @@ # Copyright (c) 2020 Red Hat # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import (absolute_import, division, print_function) __metaclass__ = type ANSIBLE_METADATA = { 'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community' } import hashlib import re from ansible.errors import AnsibleFilterError def agnosticd_dynamic_source_name(source): if 'name' in source: return source['name'] if re.match('[\w\-]+\.([\w\-]+)$', source['src']): return source['src'] m = re.search(r'/([\w\-]+)(\.git)?$', source['src']) if m: return m.group(1) raise AnsibleFilterError("Unable to determine source name from {}, name must be provided".format(source['src'])) def agnosticd_dynamic_source_version(source): return source.get('version', 'latest') def agnosticd_dynamic_git_source_name(source): m = re.search(r'/([^/]+)(\.git)?$', source['repo']) prefix = m.group(1) + '-' if 'version' in source: prefix += source['version'] + '-' return prefix + hashlib.sha256(( source['repo'] + ':' + source.get('version', '') ).encode('utf-8')).hexdigest() # ---- Ansible filters ---- class FilterModule(object): def filters(self): return { 'agnosticd_dynamic_source_name': agnosticd_dynamic_source_name, 'agnosticd_dynamic_source_version': agnosticd_dynamic_source_version, 'agnosticd_dynamic_git_source_name': agnosticd_dynamic_git_source_name } ansible/roles/agnosticd_dynamic/tasks/install-galaxy-source-to-cache.yaml
New file @@ -0,0 +1,30 @@ --- - when: not _source_cache_path is exists block: - name: Write dynamic requirements.yaml copy: content: | --- roles: - name: {{ _source_name_version | to_json }} src: {{ _source.src | to_json }} {% if _source_version != 'latest' %} version: {{ _source_version | to_json }} {% endif %} {% if 'scm' in _source %} scm: {{ _source.scm }} {% endif %} dest: "{{ _requirements_yaml }}" - name: Install ansible-galaxy source for {{ _source_name }} command: >- ansible-galaxy install --no-deps --role-file {{ _requirements_yaml | quote }} --roles-path {{ agnosticd_dynamic_cache_dir | quote }} - name: Create link to role cache for {{ _source_name }} file: state: link path: "{{ agnosticd_dynamic_roles_dir }}/{{ _source_name }}" src: "{{ _source_cache_path | relpath(agnosticd_dynamic_roles_dir) }}" ansible/roles/agnosticd_dynamic/tasks/install-galaxy-sources-to-dynamic-roles-dir.yaml
New file @@ -0,0 +1,23 @@ --- - name: Write dynamic requirements.yaml copy: content: | --- roles: {% for _source in _sources %} - name: {{ _source | agnosticd_dynamic_source_name | to_json }} src: {{ _source.src | to_json }} {% if 'scm' in _source %} scm: {{ _source.scm }} {% endif %} {% if 'version' in _source %} version: {{ _source.version }} {% endif %} {% endfor %} dest: "{{ agnosticd_dynamic_roles_dir }}/requirements.yaml" - name: Install ansible-galaxy sources command: >- ansible-galaxy install --no-deps --role-file {{ (agnosticd_dynamic_roles_dir ~ '/requirements.yaml') | quote }} --roles-path {{ agnosticd_dynamic_roles_dir | quote }} ansible/roles/agnosticd_dynamic/tasks/install-git-source.yaml
New file @@ -0,0 +1,37 @@ --- - name: Git clone for {{ _source_name }} git: dest: "{{ _install_path }}" # Pass-through options to git module accept_hostkey: "{{ _source.accept_hostkey | default(omit) }}" #archive - not appropriate for this usage #bare - not appropriate for this usage #clone - always default to yes depth: "{{ _source.depth | default(omit) }}" executable: "{{ agnosticd_dynamic_git_executable | default(omit) }}" force: "{{ _source.force | default(omit) }}" gpg_whitelist: "{{ _source.gpg_whitelist | default(omit) }}" key_file: "{{ _source.key_file | default(omit) }}" recursive: "{{ _source.recursive | default(omit) }}" reference: "{{ _source.reference | default(omit) }}" refspec: "{{ _source.refspec | default(omit) }}" remote: "{{ _source.remote | default(omit) }}" repo: "{{ _source.repo | default(omit) }}" #separate_git_dir - not appropriate for this usage ssh_opts: "{{ _source.ssh_opts | default(omit) }}" track_submodules: "{{ _source.track_submodules | default(omit) }}" umask: "{{ _source.umask | default(omit) }}" update: "{{ _source.get('update', omit) }}" verify_commit: "{{ _source.verify_commit | default(omit) }}" version: "{{ _source.version | default(omit) }}" when: not _install_path is exists - name: Create role links to git repo for {{ _source_name }} file: state: link path: "{{ agnosticd_dynamic_roles_dir }}/{{ _role.key }}" src: "{{ (_install_path ~ '/' ~ _role.value | default('')) | relpath(_install_dir) }}" loop: "{{ _source.role_paths | default({}) | dict2items }}" loop_control: loop_var: _role label: "{{ _role.key }}" ansible/roles/agnosticd_dynamic/tasks/main.yml
New file @@ -0,0 +1,44 @@ --- - name: Create dynamic-cache and dynamic-roles directories file: path: "{{ _dir }}" state: directory loop: - "{{ agnosticd_dynamic_cache_dir }}" - "{{ agnosticd_dynamic_roles_dir }}" loop_control: loop_var: _dir - name: Install ansible-galaxy sources to dynamic roles dir include_tasks: install-galaxy-sources-to-dynamic-roles-dir.yaml vars: _sources: >- {{ agnosticd_dynamic_role_galaxy_sources | select('agnosticd_dynamic_cache_disabled') | list }} when: _sources != [] - name: Install ansible-galaxy sources to cache include_tasks: install-galaxy-source-to-cache.yaml loop: >- {{ agnosticd_dynamic_role_galaxy_sources | select('agnosticd_dynamic_cache_enabled') | list }} loop_control: loop_var: _source label: "{{ _source_name }}" vars: _source_name: "{{ _source | agnosticd_dynamic_source_name }}" _source_version: "{{ _source | agnosticd_dynamic_source_version }}" _source_name_version: "{{ _source_name ~ '-' ~ _source_version }}" _source_cache_path: "{{ agnosticd_dynamic_cache_dir }}/{{ _source_name_version }}" _requirements_yaml: "{{ agnosticd_dynamic_roles_dir }}/{{ _source_name }}-requirements.yaml" - name: Install git sources include_tasks: install-git-source.yaml loop: "{{ agnosticd_dynamic_role_git_sources }}" loop_control: loop_var: _source label: "{{ _source_name }}" vars: _source_name: "{{ _source | agnosticd_dynamic_role_git_source_name }}" _install_dir: >- {{ agnosticd_dynamic_cache_dir if _source is agnosticd_dynamic_cache_enabled else agnosticd_dynamic_roles_dir }} _install_path: >- {{ _install_dir }}/{{ _source_name }} ansible/roles/agnosticd_dynamic/test_plugins/agnosticd_dynamic.py
New file @@ -0,0 +1,43 @@ # Copyright (c) 2020 Red Hat # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import (absolute_import, division, print_function) __metaclass__ = type ANSIBLE_METADATA = { 'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community' } import re from ansible import errors def agnosticd_dynamic_cache_enabled(source): ''' Return whether cache is enabled for this source. Cache may be enabled explicitly or otherwise detected from the version string. Versions that appear to use semantic versioning will be enabled for cache. ''' if 'cache' in source: return bool(source['cache']) if 'version' not in source: return False elif re.search(r'\d+\.\d+\.\d+', source['version']): return True else: return False def agnosticd_dynamic_cache_disabled(source): ''' Return whether cache is disbled for this source. ''' return not agnosticd_dynamic_cache_enabled(source) class TestModule(object): def tests(self): return dict( agnosticd_dynamic_cache_enabled=agnosticd_dynamic_cache_enabled, agnosticd_dynamic_cache_disabled=agnosticd_dynamic_cache_disabled )