summaryrefslogtreecommitdiffstats
path: root/test/integration/targets/ansible-galaxy-collection/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'test/integration/targets/ansible-galaxy-collection/tasks')
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/build.yml74
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/download.yml176
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/fail_fast_resolvelib.yml45
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/init.yml124
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/install.yml1035
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/install_offline.yml137
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/list.yml167
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/main.yml220
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/publish.yml33
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/pulp.yml11
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/revoke_gpg_key.yml14
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/setup_gpg.yml24
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/supported_resolvelib.yml44
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/unsupported_resolvelib.yml44
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml282
-rw-r--r--test/integration/targets/ansible-galaxy-collection/tasks/verify.yml475
16 files changed, 2905 insertions, 0 deletions
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/build.yml b/test/integration/targets/ansible-galaxy-collection/tasks/build.yml
new file mode 100644
index 0000000..8140d46
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/build.yml
@@ -0,0 +1,74 @@
+---
+- name: build basic collection based on current directory
+ command: ansible-galaxy collection build {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}/scratch/ansible_test/my_collection'
+ register: build_current_dir
+
+- name: get result of build basic collection on current directory
+ stat:
+ path: '{{ galaxy_dir }}/scratch/ansible_test/my_collection/ansible_test-my_collection-1.0.0.tar.gz'
+ register: build_current_dir_actual
+
+- name: assert build basic collection based on current directory
+ assert:
+ that:
+ - '"Created collection for ansible_test.my_collection" in build_current_dir.stdout'
+ - build_current_dir_actual.stat.exists
+
+- name: build basic collection based on relative dir
+ command: ansible-galaxy collection build scratch/ansible_test/my_collection {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}'
+ register: build_relative_dir
+
+- name: get result of build basic collection based on relative dir
+ stat:
+ path: '{{ galaxy_dir }}/ansible_test-my_collection-1.0.0.tar.gz'
+ register: build_relative_dir_actual
+
+- name: assert build basic collection based on relative dir
+ assert:
+ that:
+ - '"Created collection for ansible_test.my_collection" in build_relative_dir.stdout'
+ - build_relative_dir_actual.stat.exists
+
+- name: fail to build existing collection without force
+ command: ansible-galaxy collection build scratch/ansible_test/my_collection {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}'
+ ignore_errors: yes
+ register: build_existing_no_force
+
+- name: build existing collection with force
+ command: ansible-galaxy collection build scratch/ansible_test/my_collection --force {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}'
+ register: build_existing_force
+
+- name: assert build existing collection
+ assert:
+ that:
+ - '"use --force to re-create the collection artifact" in build_existing_no_force.stderr'
+ - '"Created collection for ansible_test.my_collection" in build_existing_force.stdout'
+
+- name: build collection containing ignored files
+ command: ansible-galaxy collection build
+ args:
+ chdir: '{{ galaxy_dir }}/scratch/ansible_test/ignore'
+
+- name: list the created tar contents
+ command: tar -tf {{ galaxy_dir }}/scratch/ansible_test/ignore/ansible_test-ignore-1.0.0.tar.gz
+ register: tar_output
+
+- name: assert ignored files are not present in the archive
+ assert:
+ that:
+ - item not in tar_output.stdout_lines
+ loop: '{{ collection_ignored_files }}'
+
+- name: assert ignored directories are not present in the archive
+ assert:
+ that:
+ - item not in tar_output.stdout_lines
+ loop: '{{ collection_ignored_directories }}'
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/download.yml b/test/integration/targets/ansible-galaxy-collection/tasks/download.yml
new file mode 100644
index 0000000..b651a73
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/download.yml
@@ -0,0 +1,176 @@
+---
+- name: create test download dir
+ file:
+ path: '{{ galaxy_dir }}/download'
+ state: directory
+
+- name: download collection with multiple dependencies with --no-deps
+ command: ansible-galaxy collection download parent_dep.parent_collection:1.0.0 --no-deps -s pulp_v2 {{ galaxy_verbosity }}
+ register: download_collection
+ args:
+ chdir: '{{ galaxy_dir }}/download'
+
+- name: get result of download collection with multiple dependencies
+ find:
+ path: '{{ galaxy_dir }}/download/collections'
+ file_type: file
+ register: download_collection_actual
+
+- name: assert download collection with multiple dependencies --no-deps
+ assert:
+ that:
+ - >-
+ "Downloading collection 'parent_dep.parent_collection:1.0.0' to '/tmp/"
+ in download_collection.stdout
+ - >-
+ "Downloading collection 'child_dep.child_collection"
+ not in download_collection.stdout
+ - >-
+ "Downloading collection 'child_dep.child_dep2"
+ not in download_collection.stdout
+ - download_collection_actual.examined == 2
+ - download_collection_actual.matched == 2
+ - (download_collection_actual.files[0].path | basename) in ['requirements.yml', 'parent_dep-parent_collection-1.0.0.tar.gz']
+ - (download_collection_actual.files[1].path | basename) in ['requirements.yml', 'parent_dep-parent_collection-1.0.0.tar.gz']
+
+- name: download collection with multiple dependencies
+ command: ansible-galaxy collection download parent_dep.parent_collection:1.0.0 -s pulp_v2 {{ galaxy_verbosity }}
+ register: download_collection
+ args:
+ chdir: '{{ galaxy_dir }}/download'
+
+- name: get result of download collection with multiple dependencies
+ find:
+ path: '{{ galaxy_dir }}/download/collections'
+ file_type: file
+ register: download_collection_actual
+
+- name: assert download collection with multiple dependencies
+ assert:
+ that:
+ - '"Downloading collection ''parent_dep.parent_collection:1.0.0'' to" in download_collection.stdout'
+ - '"Downloading collection ''child_dep.child_collection:0.9.9'' to" in download_collection.stdout'
+ - '"Downloading collection ''child_dep.child_dep2:1.2.2'' to" in download_collection.stdout'
+ - download_collection_actual.examined == 4
+ - download_collection_actual.matched == 4
+ - (download_collection_actual.files[0].path | basename) in ['requirements.yml', 'child_dep-child_dep2-1.2.2.tar.gz', 'child_dep-child_collection-0.9.9.tar.gz', 'parent_dep-parent_collection-1.0.0.tar.gz']
+ - (download_collection_actual.files[1].path | basename) in ['requirements.yml', 'child_dep-child_dep2-1.2.2.tar.gz', 'child_dep-child_collection-0.9.9.tar.gz', 'parent_dep-parent_collection-1.0.0.tar.gz']
+ - (download_collection_actual.files[2].path | basename) in ['requirements.yml', 'child_dep-child_dep2-1.2.2.tar.gz', 'child_dep-child_collection-0.9.9.tar.gz', 'parent_dep-parent_collection-1.0.0.tar.gz']
+ - (download_collection_actual.files[3].path | basename) in ['requirements.yml', 'child_dep-child_dep2-1.2.2.tar.gz', 'child_dep-child_collection-0.9.9.tar.gz', 'parent_dep-parent_collection-1.0.0.tar.gz']
+
+- name: test install of download requirements file
+ command: ansible-galaxy collection install -r requirements.yml -p '{{ galaxy_dir }}/download' {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}/download/collections'
+ register: install_download
+
+- name: get result of test install of download requirements file
+ slurp:
+ path: '{{ galaxy_dir }}/download/ansible_collections/{{ collection.namespace }}/{{ collection.name }}/MANIFEST.json'
+ register: install_download_actual
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace: parent_dep
+ name: parent_collection
+ - namespace: child_dep
+ name: child_collection
+ - namespace: child_dep
+ name: child_dep2
+
+- name: assert test install of download requirements file
+ assert:
+ that:
+ - '"Installing ''parent_dep.parent_collection:1.0.0'' to" in install_download.stdout'
+ - '"Installing ''child_dep.child_collection:0.9.9'' to" in install_download.stdout'
+ - '"Installing ''child_dep.child_dep2:1.2.2'' to" in install_download.stdout'
+ - (install_download_actual.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_download_actual.results[1].content | b64decode | from_json).collection_info.version == '0.9.9'
+ - (install_download_actual.results[2].content | b64decode | from_json).collection_info.version == '1.2.2'
+
+- name: create test requirements file for download
+ copy:
+ content: |
+ collections:
+ - name: namespace1.name1
+ version: 1.1.0-beta.1
+
+ dest: '{{ galaxy_dir }}/download/download.yml'
+
+- name: download collection with req to custom dir
+ command: ansible-galaxy collection download -r '{{ galaxy_dir }}/download/download.yml' -s galaxy_ng -p '{{ galaxy_dir }}/download/collections-custom' {{ galaxy_verbosity }}
+ register: download_req_custom_path
+
+- name: get result of download collection with req to custom dir
+ find:
+ path: '{{ galaxy_dir }}/download/collections-custom'
+ file_type: file
+ register: download_req_custom_path_actual
+
+- name: assert download collection with multiple dependencies
+ assert:
+ that:
+ - '"Downloading collection ''namespace1.name1:1.1.0-beta.1'' to" in download_req_custom_path.stdout'
+ - download_req_custom_path_actual.examined == 2
+ - download_req_custom_path_actual.matched == 2
+ - (download_req_custom_path_actual.files[0].path | basename) in ['requirements.yml', 'namespace1-name1-1.1.0-beta.1.tar.gz']
+ - (download_req_custom_path_actual.files[1].path | basename) in ['requirements.yml', 'namespace1-name1-1.1.0-beta.1.tar.gz']
+
+# https://github.com/ansible/ansible/issues/68186
+- name: create test requirements file without roles and collections
+ copy:
+ content: |
+ collections:
+ roles:
+
+ dest: '{{ galaxy_dir }}/download/no_roles_no_collections.yml'
+
+- name: install collection with requirements
+ command: ansible-galaxy collection install -r '{{ galaxy_dir }}/download/no_roles_no_collections.yml' {{ galaxy_verbosity }}
+ register: install_no_requirements
+
+- name: assert install collection with no roles and no collections in requirements
+ assert:
+ that:
+ - '"Skipping install, no requirements found" in install_no_requirements.stdout'
+
+- name: Test downloading a tar.gz collection artifact
+ block:
+
+ - name: get result of build basic collection on current directory
+ stat:
+ path: '{{ galaxy_dir }}/scratch/ansible_test/my_collection/ansible_test-my_collection-1.0.0.tar.gz'
+ register: result
+
+ - name: create default skeleton
+ command: ansible-galaxy collection init ansible_test.my_collection {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}/scratch'
+ when: not result.stat.exists
+
+ - name: build the tar.gz
+ command: ansible-galaxy collection build {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}/scratch/ansible_test/my_collection'
+ when: not result.stat.exists
+
+ - name: download a tar.gz file
+ command: ansible-galaxy collection download '{{ galaxy_dir }}/scratch/ansible_test/my_collection/ansible_test-my_collection-1.0.0.tar.gz'
+ args:
+ chdir: '{{ galaxy_dir }}/download'
+ register: download_collection
+
+ - name: get result of downloaded tar.gz
+ stat:
+ path: '{{ galaxy_dir }}/download/collections/ansible_test-my_collection-1.0.0.tar.gz'
+ register: download_collection_actual
+
+ - assert:
+ that:
+ - '"Downloading collection ''ansible_test.my_collection:1.0.0'' to" in download_collection.stdout'
+ - download_collection_actual.stat.exists
+
+- name: remove test download dir
+ file:
+ path: '{{ galaxy_dir }}/download'
+ state: absent
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/fail_fast_resolvelib.yml b/test/integration/targets/ansible-galaxy-collection/tasks/fail_fast_resolvelib.yml
new file mode 100644
index 0000000..eb471f8
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/fail_fast_resolvelib.yml
@@ -0,0 +1,45 @@
+# resolvelib>=0.6.0 added an 'incompatibilities' parameter to find_matches
+# If incompatibilities aren't removed from the viable candidates, this example causes infinite resursion
+- name: test resolvelib removes incompatibilites in find_matches and errors quickly (prevent infinite recursion)
+ block:
+ - name: create collection dir
+ file:
+ dest: "{{ galaxy_dir }}/resolvelib/ns/coll"
+ state: directory
+
+ - name: create galaxy.yml with a dependecy on a galaxy-sourced collection
+ copy:
+ dest: "{{ galaxy_dir }}/resolvelib/ns/coll/galaxy.yml"
+ content: |
+ namespace: ns
+ name: coll
+ authors:
+ - ansible-core
+ readme: README.md
+ version: "1.0.0"
+ dependencies:
+ namespace1.name1: "0.0.5"
+
+ - name: build the collection
+ command: ansible-galaxy collection build ns/coll
+ args:
+ chdir: "{{ galaxy_dir }}/resolvelib"
+
+ - name: install a conflicting version of the dep with the tarfile (expected failure)
+ command: ansible-galaxy collection install namespace1.name1:1.0.9 ns-coll-1.0.0.tar.gz -vvvvv -s {{ test_name }} -p collections/
+ args:
+ chdir: "{{ galaxy_dir }}/resolvelib"
+ timeout: 30
+ ignore_errors: yes
+ register: incompatible
+
+ - assert:
+ that:
+ - incompatible.failed
+ - not incompatible.msg.startswith("The command action failed to execute in the expected time frame")
+
+ always:
+ - name: cleanup resolvelib test
+ file:
+ dest: "{{ galaxy_dir }}/resolvelib"
+ state: absent
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/init.yml b/test/integration/targets/ansible-galaxy-collection/tasks/init.yml
new file mode 100644
index 0000000..17a000d
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/init.yml
@@ -0,0 +1,124 @@
+---
+- name: create default skeleton
+ command: ansible-galaxy collection init ansible_test.my_collection {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}/scratch'
+ register: init_relative
+
+- name: get result of create default skeleton
+ find:
+ path: '{{ galaxy_dir }}/scratch/ansible_test/my_collection'
+ recurse: yes
+ file_type: directory
+ register: init_relative_actual
+
+- debug:
+ var: init_relative_actual.files | map(attribute='path') | list
+
+- name: assert create default skeleton
+ assert:
+ that:
+ - '"Collection ansible_test.my_collection was created successfully" in init_relative.stdout'
+ - init_relative_actual.files | length == 4
+ - (init_relative_actual.files | map(attribute='path') | list)[0] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_relative_actual.files | map(attribute='path') | list)[1] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_relative_actual.files | map(attribute='path') | list)[2] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_relative_actual.files | map(attribute='path') | list)[3] | basename in ['docs', 'plugins', 'roles', 'meta']
+
+- name: create collection with custom init path
+ command: ansible-galaxy collection init ansible_test2.my_collection --init-path "{{ galaxy_dir }}/scratch/custom-init-dir" {{ galaxy_verbosity }}
+ register: init_custom_path
+
+- name: get result of create default skeleton
+ find:
+ path: '{{ galaxy_dir }}/scratch/custom-init-dir/ansible_test2/my_collection'
+ file_type: directory
+ register: init_custom_path_actual
+
+- name: assert create collection with custom init path
+ assert:
+ that:
+ - '"Collection ansible_test2.my_collection was created successfully" in init_custom_path.stdout'
+ - init_custom_path_actual.files | length == 4
+ - (init_custom_path_actual.files | map(attribute='path') | list)[0] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[1] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[2] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[3] | basename in ['docs', 'plugins', 'roles', 'meta']
+
+- name: add a directory to the init collection path to test that --force removes it
+ file:
+ state: directory
+ path: "{{ galaxy_dir }}/scratch/custom-init-dir/ansible_test2/my_collection/remove_me"
+
+- name: create collection with custom init path
+ command: ansible-galaxy collection init ansible_test2.my_collection --init-path "{{ galaxy_dir }}/scratch/custom-init-dir" --force {{ galaxy_verbosity }}
+ register: init_custom_path
+
+- name: get result of create default skeleton
+ find:
+ path: '{{ galaxy_dir }}/scratch/custom-init-dir/ansible_test2/my_collection'
+ file_type: directory
+ register: init_custom_path_actual
+
+- name: assert create collection with custom init path
+ assert:
+ that:
+ - '"Collection ansible_test2.my_collection was created successfully" in init_custom_path.stdout'
+ - init_custom_path_actual.files | length == 4
+ - (init_custom_path_actual.files | map(attribute='path') | list)[0] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[1] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[2] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[3] | basename in ['docs', 'plugins', 'roles', 'meta']
+
+- name: create collection in cwd with custom init path
+ command: ansible-galaxy collection init ansible_test2.my_collection --init-path ../../ --force {{ galaxy_verbosity }}
+ args:
+ chdir: "{{ galaxy_dir }}/scratch/custom-init-dir/ansible_test2/my_collection"
+ register: init_custom_path
+
+- name: get result of create default skeleton
+ find:
+ path: '{{ galaxy_dir }}/scratch/custom-init-dir/ansible_test2/my_collection'
+ file_type: directory
+ register: init_custom_path_actual
+
+- name: assert create collection with custom init path
+ assert:
+ that:
+ - '"Collection ansible_test2.my_collection was created successfully" in init_custom_path.stdout'
+ - init_custom_path_actual.files | length == 4
+ - (init_custom_path_actual.files | map(attribute='path') | list)[0] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[1] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[2] | basename in ['docs', 'plugins', 'roles', 'meta']
+ - (init_custom_path_actual.files | map(attribute='path') | list)[3] | basename in ['docs', 'plugins', 'roles', 'meta']
+
+- name: create collection for ignored files and folders
+ command: ansible-galaxy collection init ansible_test.ignore
+ args:
+ chdir: '{{ galaxy_dir }}/scratch'
+
+- name: create list of ignored files
+ set_fact:
+ collection_ignored_files:
+ - plugins/compiled.pyc
+ - something.retry
+ - .git
+
+- name: plant ignored files into the ansible_test.ignore collection
+ copy:
+ dest: '{{ galaxy_dir }}/scratch/ansible_test/ignore/{{ item }}'
+ content: '{{ item }}'
+ loop: '{{ collection_ignored_files }}'
+
+- name: create list of ignored directories
+ set_fact:
+ collection_ignored_directories:
+ - docs/.git
+ - plugins/doc_fragments/__pycache__
+ - .svn
+
+- name: plant ignored folders into the ansible_test.ignore collection
+ file:
+ path: '{{ galaxy_dir }}/scratch/ansible_test/ignore/{{ item }}'
+ state: directory
+ loop: '{{ collection_ignored_directories }}'
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/install.yml b/test/integration/targets/ansible-galaxy-collection/tasks/install.yml
new file mode 100644
index 0000000..8916faf
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/install.yml
@@ -0,0 +1,1035 @@
+---
+- name: create test collection install directory - {{ test_id }}
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections'
+ state: directory
+
+- name: install simple collection from first accessible server
+ command: ansible-galaxy collection install namespace1.name1 {{ galaxy_verbosity }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ register: from_first_good_server
+
+- name: get installed files of install simple collection from first good server
+ find:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1'
+ file_type: file
+ register: install_normal_files
+
+- name: get the manifest of install simple collection from first good server
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1/MANIFEST.json'
+ register: install_normal_manifest
+
+- name: assert install simple collection from first good server
+ assert:
+ that:
+ - '"Installing ''namespace1.name1:1.0.9'' to" in from_first_good_server.stdout'
+ - install_normal_files.files | length == 3
+ - install_normal_files.files[0].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - install_normal_files.files[1].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - install_normal_files.files[2].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - (install_normal_manifest.content | b64decode | from_json).collection_info.version == '1.0.9'
+
+- name: Remove the collection
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1'
+ state: absent
+
+- name: install simple collection with implicit path - {{ test_id }}
+ command: ansible-galaxy collection install namespace1.name1 -s '{{ test_name }}' {{ galaxy_verbosity }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ register: install_normal
+
+- name: get installed files of install simple collection with implicit path - {{ test_id }}
+ find:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1'
+ file_type: file
+ register: install_normal_files
+
+- name: get the manifest of install simple collection with implicit path - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1/MANIFEST.json'
+ register: install_normal_manifest
+
+- name: assert install simple collection with implicit path - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace1.name1:1.0.9'' to" in install_normal.stdout'
+ - install_normal_files.files | length == 3
+ - install_normal_files.files[0].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - install_normal_files.files[1].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - install_normal_files.files[2].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - (install_normal_manifest.content | b64decode | from_json).collection_info.version == '1.0.9'
+
+- name: install existing without --force - {{ test_id }}
+ command: ansible-galaxy collection install namespace1.name1 -s '{{ test_name }}' {{ galaxy_verbosity }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ register: install_existing_no_force
+
+- name: assert install existing without --force - {{ test_id }}
+ assert:
+ that:
+ - '"Nothing to do. All requested collections are already installed" in install_existing_no_force.stdout'
+
+- name: install existing with --force - {{ test_id }}
+ command: ansible-galaxy collection install namespace1.name1 -s '{{ test_name }}' --force {{ galaxy_verbosity }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ register: install_existing_force
+
+- name: assert install existing with --force - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace1.name1:1.0.9'' to" in install_existing_force.stdout'
+
+- name: remove test installed collection - {{ test_id }}
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1'
+ state: absent
+
+- name: install pre-release as explicit version to custom dir - {{ test_id }}
+ command: ansible-galaxy collection install 'namespace1.name1:1.1.0-beta.1' -s '{{ test_name }}' -p '{{ galaxy_dir }}/ansible_collections' {{ galaxy_verbosity }}
+ register: install_prerelease
+
+- name: get result of install pre-release as explicit version to custom dir - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1/MANIFEST.json'
+ register: install_prerelease_actual
+
+- name: assert install pre-release as explicit version to custom dir - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace1.name1:1.1.0-beta.1'' to" in install_prerelease.stdout'
+ - (install_prerelease_actual.content | b64decode | from_json).collection_info.version == '1.1.0-beta.1'
+
+- name: Remove beta
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1'
+ state: absent
+
+- name: install pre-release version with --pre to custom dir - {{ test_id }}
+ command: ansible-galaxy collection install --pre 'namespace1.name1' -s '{{ test_name }}' -p '{{ galaxy_dir }}/ansible_collections' {{ galaxy_verbosity }}
+ register: install_prerelease
+
+- name: get result of install pre-release version with --pre to custom dir - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1/MANIFEST.json'
+ register: install_prerelease_actual
+
+- name: assert install pre-release version with --pre to custom dir - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace1.name1:1.1.0-beta.1'' to" in install_prerelease.stdout'
+ - (install_prerelease_actual.content | b64decode | from_json).collection_info.version == '1.1.0-beta.1'
+
+- name: install multiple collections with dependencies - {{ test_id }}
+ command: ansible-galaxy collection install parent_dep.parent_collection:1.0.0 namespace2.name -s {{ test_name }} {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}/ansible_collections'
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+ register: install_multiple_with_dep
+
+- name: get result of install multiple collections with dependencies - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection.namespace }}/{{ collection.name }}/MANIFEST.json'
+ register: install_multiple_with_dep_actual
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace: namespace2
+ name: name
+ - namespace: parent_dep
+ name: parent_collection
+ - namespace: child_dep
+ name: child_collection
+ - namespace: child_dep
+ name: child_dep2
+
+- name: assert install multiple collections with dependencies - {{ test_id }}
+ assert:
+ that:
+ - (install_multiple_with_dep_actual.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_multiple_with_dep_actual.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_multiple_with_dep_actual.results[2].content | b64decode | from_json).collection_info.version == '0.9.9'
+ - (install_multiple_with_dep_actual.results[3].content | b64decode | from_json).collection_info.version == '1.2.2'
+
+- name: expect failure with dep resolution failure - {{ test_id }}
+ command: ansible-galaxy collection install fail_namespace.fail_collection -s {{ test_name }} {{ galaxy_verbosity }}
+ register: fail_dep_mismatch
+ failed_when:
+ - '"Could not satisfy the following requirements" not in fail_dep_mismatch.stderr'
+ - '" fail_dep2.name:<0.0.5 (dependency of fail_namespace.fail_collection:2.1.2)" not in fail_dep_mismatch.stderr'
+
+- name: Find artifact url for namespace3.name
+ uri:
+ url: '{{ test_server }}{{ vX }}collections/namespace3/name/versions/1.0.0/'
+ user: '{{ pulp_user }}'
+ password: '{{ pulp_password }}'
+ force_basic_auth: true
+ register: artifact_url_response
+
+- name: download a collection for an offline install - {{ test_id }}
+ get_url:
+ url: '{{ artifact_url_response.json.download_url }}'
+ dest: '{{ galaxy_dir }}/namespace3.tar.gz'
+
+- name: install a collection from a tarball - {{ test_id }}
+ command: ansible-galaxy collection install '{{ galaxy_dir }}/namespace3.tar.gz' {{ galaxy_verbosity }}
+ register: install_tarball
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+
+- name: get result of install collection from a tarball - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace3/name/MANIFEST.json'
+ register: install_tarball_actual
+
+- name: assert install a collection from a tarball - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace3.name:1.0.0'' to" in install_tarball.stdout'
+ - (install_tarball_actual.content | b64decode | from_json).collection_info.version == '1.0.0'
+
+- name: write a requirements file using the artifact and a conflicting version
+ copy:
+ content: |
+ collections:
+ - name: {{ galaxy_dir }}/namespace3.tar.gz
+ version: 1.2.0
+ dest: '{{ galaxy_dir }}/test_req.yml'
+
+- name: install the requirements file with mismatched versions
+ command: ansible-galaxy collection install -r '{{ galaxy_dir }}/test_req.yml' {{ galaxy_verbosity }}
+ ignore_errors: True
+ register: result
+ environment:
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- name: remove the requirements file
+ file:
+ path: '{{ galaxy_dir }}/test_req.yml'
+ state: absent
+
+- assert:
+ that: error == expected_error
+ vars:
+ error: "{{ result.stderr | regex_replace('\\n', ' ') }}"
+ expected_error: >-
+ ERROR! Failed to resolve the requested dependencies map.
+ Got the candidate namespace3.name:1.0.0 (direct request)
+ which didn't satisfy all of the following requirements:
+ * namespace3.name:1.2.0
+
+- name: test error for mismatched dependency versions
+ vars:
+ error: "{{ result.stderr | regex_replace('\\n', ' ') }}"
+ expected_error: >-
+ ERROR! Failed to resolve the requested dependencies map.
+ Got the candidate namespace3.name:1.0.0 (dependency of tmp_parent.name:1.0.0)
+ which didn't satisfy all of the following requirements:
+ * namespace3.name:1.2.0
+ environment:
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+ block:
+ - name: init a new parent collection
+ command: ansible-galaxy collection init tmp_parent.name --init-path '{{ galaxy_dir }}/scratch'
+
+ - name: replace the dependencies
+ lineinfile:
+ path: "{{ galaxy_dir }}/scratch/tmp_parent/name/galaxy.yml"
+ regexp: "^dependencies:*"
+ line: "dependencies: { '{{ galaxy_dir }}/namespace3.tar.gz': '1.2.0' }"
+
+ - name: build the new artifact
+ command: ansible-galaxy collection build {{ galaxy_dir }}/scratch/tmp_parent/name
+ args:
+ chdir: "{{ galaxy_dir }}"
+
+ - name: install the artifact to verify the error is handled
+ command: ansible-galaxy collection install '{{ galaxy_dir }}/tmp_parent-name-1.0.0.tar.gz'
+ ignore_errors: yes
+ register: result
+
+ - debug: msg="Actual - {{ error }}"
+
+ - debug: msg="Expected - {{ expected_error }}"
+
+ - assert:
+ that: error == expected_error
+ always:
+ - name: clean up collection skeleton and artifact
+ file:
+ state: absent
+ path: "{{ item }}"
+ loop:
+ - "{{ galaxy_dir }}/scratch/tmp_parent/"
+ - "{{ galaxy_dir }}/tmp_parent-name-1.0.0.tar.gz"
+
+- name: setup bad tarball - {{ test_id }}
+ script: build_bad_tar.py {{ galaxy_dir | quote }}
+
+- name: fail to install a collection from a bad tarball - {{ test_id }}
+ command: ansible-galaxy collection install '{{ galaxy_dir }}/suspicious-test-1.0.0.tar.gz' {{ galaxy_verbosity }}
+ register: fail_bad_tar
+ failed_when: fail_bad_tar.rc != 1 and "Cannot extract tar entry '../../outside.sh' as it will be placed outside the collection directory" not in fail_bad_tar.stderr
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+
+- name: get result of failed collection install - {{ test_id }}
+ stat:
+ path: '{{ galaxy_dir }}/ansible_collections\suspicious'
+ register: fail_bad_tar_actual
+
+- name: assert result of failed collection install - {{ test_id }}
+ assert:
+ that:
+ - not fail_bad_tar_actual.stat.exists
+
+- name: Find artifact url for namespace4.name
+ uri:
+ url: '{{ test_server }}{{ vX }}collections/namespace4/name/versions/1.0.0/'
+ user: '{{ pulp_user }}'
+ password: '{{ pulp_password }}'
+ force_basic_auth: true
+ register: artifact_url_response
+
+- name: install a collection from a URI - {{ test_id }}
+ command: ansible-galaxy collection install {{ artifact_url_response.json.download_url}} {{ galaxy_verbosity }}
+ register: install_uri
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+
+- name: get result of install collection from a URI - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace4/name/MANIFEST.json'
+ register: install_uri_actual
+
+- name: assert install a collection from a URI - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace4.name:1.0.0'' to" in install_uri.stdout'
+ - (install_uri_actual.content | b64decode | from_json).collection_info.version == '1.0.0'
+
+- name: fail to install a collection with an undefined URL - {{ test_id }}
+ command: ansible-galaxy collection install namespace5.name {{ galaxy_verbosity }}
+ register: fail_undefined_server
+ failed_when: '"No setting was provided for required configuration plugin_type: galaxy_server plugin: undefined" not in fail_undefined_server.stderr'
+ environment:
+ ANSIBLE_GALAXY_SERVER_LIST: undefined
+
+- when: not requires_auth
+ block:
+ - name: install a collection with an empty server list - {{ test_id }}
+ command: ansible-galaxy collection install namespace5.name -s '{{ test_server }}' {{ galaxy_verbosity }}
+ register: install_empty_server_list
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_GALAXY_SERVER_LIST: ''
+
+ - name: get result of a collection with an empty server list - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace5/name/MANIFEST.json'
+ register: install_empty_server_list_actual
+
+ - name: assert install a collection with an empty server list - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace5.name:1.0.0'' to" in install_empty_server_list.stdout'
+ - (install_empty_server_list_actual.content | b64decode | from_json).collection_info.version == '1.0.0'
+
+- name: create test requirements file with both roles and collections - {{ test_id }}
+ copy:
+ content: |
+ collections:
+ - namespace6.name
+ - name: namespace7.name
+ roles:
+ - skip.me
+ dest: '{{ galaxy_dir }}/ansible_collections/requirements-with-role.yml'
+
+- name: install roles from requirements file with collection-only keyring option
+ command: ansible-galaxy role install -r {{ req_file }} -s {{ test_name }} --keyring {{ keyring }}
+ vars:
+ req_file: '{{ galaxy_dir }}/ansible_collections/requirements-with-role.yml'
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ ignore_errors: yes
+ register: invalid_opt
+
+- assert:
+ that:
+ - invalid_opt is failed
+ - "'unrecognized arguments: --keyring' in invalid_opt.stderr"
+
+# Need to run with -vvv to validate the roles will be skipped msg
+- name: install collections only with requirements-with-role.yml - {{ test_id }}
+ command: ansible-galaxy collection install -r '{{ galaxy_dir }}/ansible_collections/requirements-with-role.yml' -s '{{ test_name }}' -vvv
+ register: install_req_collection
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+
+- name: get result of install collections only with requirements-with-roles.yml - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name/MANIFEST.json'
+ register: install_req_collection_actual
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace6
+ - namespace7
+
+- name: assert install collections only with requirements-with-role.yml - {{ test_id }}
+ assert:
+ that:
+ - '"contains roles which will be ignored" in install_req_collection.stdout'
+ - '"Installing ''namespace6.name:1.0.0'' to" in install_req_collection.stdout'
+ - '"Installing ''namespace7.name:1.0.0'' to" in install_req_collection.stdout'
+ - (install_req_collection_actual.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_req_collection_actual.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+
+- name: create test requirements file with just collections - {{ test_id }}
+ copy:
+ content: |
+ collections:
+ - namespace8.name
+ - name: namespace9.name
+ dest: '{{ galaxy_dir }}/ansible_collections/requirements.yaml'
+
+- name: install collections with ansible-galaxy install - {{ test_id }}
+ command: ansible-galaxy install -r '{{ galaxy_dir }}/ansible_collections/requirements.yaml' -s '{{ test_name }}'
+ register: install_req
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+
+- name: get result of install collections with ansible-galaxy install - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name/MANIFEST.json'
+ register: install_req_actual
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace8
+ - namespace9
+
+- name: assert install collections with ansible-galaxy install - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace8.name:1.0.0'' to" in install_req.stdout'
+ - '"Installing ''namespace9.name:1.0.0'' to" in install_req.stdout'
+ - (install_req_actual.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_req_actual.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+
+- name: Test deviations on -r and --role-file without collection or role sub command
+ command: '{{ cmd }}'
+ loop:
+ - ansible-galaxy install -vr '{{ galaxy_dir }}/ansible_collections/requirements.yaml' -s '{{ test_name }}' -vv
+ - ansible-galaxy install --role-file '{{ galaxy_dir }}/ansible_collections/requirements.yaml' -s '{{ test_name }}' -vvv
+ - ansible-galaxy install --role-file='{{ galaxy_dir }}/ansible_collections/requirements.yaml' -s '{{ test_name }}' -vvv
+ loop_control:
+ loop_var: cmd
+
+- name: uninstall collections for next requirements file test
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name'
+ state: absent
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace7
+ - namespace8
+ - namespace9
+
+- name: rewrite requirements file with collections and signatures
+ copy:
+ content: |
+ collections:
+ - name: namespace7.name
+ version: "1.0.0"
+ signatures:
+ - "{{ not_mine }}"
+ - "{{ also_not_mine }}"
+ - "file://{{ gpg_homedir }}/namespace7-name-1.0.0-MANIFEST.json.asc"
+ - namespace8.name
+ - name: namespace9.name
+ signatures:
+ - "file://{{ gpg_homedir }}/namespace9-name-1.0.0-MANIFEST.json.asc"
+ dest: '{{ galaxy_dir }}/ansible_collections/requirements.yaml'
+ vars:
+ not_mine: "file://{{ gpg_homedir }}/namespace1-name1-1.0.0-MANIFEST.json.asc"
+ also_not_mine: "file://{{ gpg_homedir }}/namespace1-name1-1.0.9-MANIFEST.json.asc"
+
+- name: installing only roles does not fail if keyring for collections is not provided
+ command: ansible-galaxy role install -r {{ galaxy_dir }}/ansible_collections/requirements.yaml
+ register: roles_only
+
+- assert:
+ that:
+ - roles_only is success
+
+- name: installing only roles implicitly does not fail if keyring for collections is not provided
+ # if -p/--roles-path are specified, only roles are installed
+ command: ansible-galaxy install -r {{ galaxy_dir }}/ansible_collections/requirements.yaml }} -p {{ galaxy_dir }}
+ register: roles_only
+
+- assert:
+ that:
+ - roles_only is success
+
+- name: installing roles and collections requires keyring if collections have signatures
+ command: ansible-galaxy install -r {{ galaxy_dir }}/ansible_collections/requirements.yaml }}
+ ignore_errors: yes
+ register: collections_and_roles
+
+- assert:
+ that:
+ - collections_and_roles is failed
+ - "'no keyring was configured' in collections_and_roles.stderr"
+
+- name: install collection with mutually exclusive options
+ command: ansible-galaxy collection install -r {{ req_file }} -s {{ test_name }} {{ cli_signature }}
+ vars:
+ req_file: "{{ galaxy_dir }}/ansible_collections/requirements.yaml"
+ # --signature is an ansible-galaxy collection install subcommand, but mutually exclusive with -r
+ cli_signature: "--signature file://{{ gpg_homedir }}/namespace7-name-1.0.0-MANIFEST.json.asc"
+ ignore_errors: yes
+ register: mutually_exclusive_opts
+
+- assert:
+ that:
+ - mutually_exclusive_opts is failed
+ - expected_error in actual_error
+ vars:
+ expected_error: >-
+ The --signatures option and --requirements-file are mutually exclusive.
+ Use the --signatures with positional collection_name args or provide a
+ 'signatures' key for requirements in the --requirements-file.
+ actual_error: "{{ mutually_exclusive_opts.stderr }}"
+
+- name: install a collection with user-supplied signatures for verification but no keyring
+ command: ansible-galaxy collection install namespace1.name1:1.0.0 {{ cli_signature }}
+ vars:
+ cli_signature: "--signature file://{{ gpg_homedir }}/namespace1-name1-1.0.0-MANIFEST.json.asc"
+ ignore_errors: yes
+ register: required_together
+
+- assert:
+ that:
+ - required_together is failed
+ - '"ERROR! Signatures were provided to verify namespace1.name1 but no keyring was configured." in required_together.stderr'
+
+- name: install collections with ansible-galaxy install -r with invalid signatures - {{ test_id }}
+ # Note that --keyring is a valid option for 'ansible-galaxy install -r ...', not just 'ansible-galaxy collection ...'
+ command: ansible-galaxy install -r {{ req_file }} -s {{ test_name }} --keyring {{ keyring }} {{ galaxy_verbosity }}
+ register: install_req
+ ignore_errors: yes
+ vars:
+ req_file: "{{ galaxy_dir }}/ansible_collections/requirements.yaml"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: all
+
+- name: assert invalid signature is fatal with ansible-galaxy install - {{ test_id }}
+ assert:
+ that:
+ - install_req is failed
+ - '"Installing ''namespace7.name:1.0.0'' to" in install_req.stdout'
+ - '"Not installing namespace7.name because GnuPG signature verification failed" in install_req.stderr'
+ # The other collections shouldn't be installed because they're listed
+ # after the failing collection and --ignore-errors was not provided
+ - '"Installing ''namespace8.name:1.0.0'' to" not in install_req.stdout'
+ - '"Installing ''namespace9.name:1.0.0'' to" not in install_req.stdout'
+
+# This command is hardcoded with -vvvv purposefully to evaluate extra verbosity messages
+- name: install collections with ansible-galaxy install and --ignore-errors - {{ test_id }}
+ command: ansible-galaxy install -r {{ req_file }} {{ cli_opts }} -vvvv
+ register: install_req
+ vars:
+ req_file: "{{ galaxy_dir }}/ansible_collections/requirements.yaml"
+ cli_opts: "-s {{ test_name }} --keyring {{ keyring }} --ignore-errors"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: all
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- name: get result of install collections with ansible-galaxy install - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name/MANIFEST.json'
+ register: install_req_actual
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace8
+ - namespace9
+
+# SIVEL
+- name: assert invalid signature is not fatal with ansible-galaxy install --ignore-errors - {{ test_id }}
+ assert:
+ that:
+ - install_req is success
+ - '"Installing ''namespace7.name:1.0.0'' to" in install_req.stdout'
+ - '"Signature verification failed for ''namespace7.name'' (return code 1)" in install_req.stdout'
+ - '"Not installing namespace7.name because GnuPG signature verification failed." in install_stderr'
+ - '"Failed to install collection namespace7.name:1.0.0 but skipping due to --ignore-errors being set." in install_stderr'
+ - '"Installing ''namespace8.name:1.0.0'' to" in install_req.stdout'
+ - '"Installing ''namespace9.name:1.0.0'' to" in install_req.stdout'
+ - (install_req_actual.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_req_actual.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+ vars:
+ install_stderr: "{{ install_req.stderr | regex_replace('\\n', ' ') }}"
+
+- name: clean up collections from last test
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name'
+ state: absent
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace8
+ - namespace9
+
+- name: install collections with only one valid signature using ansible-galaxy install - {{ test_id }}
+ command: ansible-galaxy install -r {{ req_file }} {{ cli_opts }} {{ galaxy_verbosity }}
+ register: install_req
+ vars:
+ req_file: "{{ galaxy_dir }}/ansible_collections/requirements.yaml"
+ cli_opts: "-s {{ test_name }} --keyring {{ keyring }}"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- name: get result of install collections with ansible-galaxy install - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name/MANIFEST.json'
+ register: install_req_actual
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace7
+ - namespace8
+ - namespace9
+
+- name: assert just one valid signature is not fatal with ansible-galaxy install - {{ test_id }}
+ assert:
+ that:
+ - install_req is success
+ - '"Installing ''namespace7.name:1.0.0'' to" in install_req.stdout'
+ - '"Signature verification failed for ''namespace7.name'' (return code 1)" not in install_req.stdout'
+ - '"Not installing namespace7.name because GnuPG signature verification failed." not in install_stderr'
+ - '"Installing ''namespace8.name:1.0.0'' to" in install_req.stdout'
+ - '"Installing ''namespace9.name:1.0.0'' to" in install_req.stdout'
+ - (install_req_actual.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_req_actual.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_req_actual.results[2].content | b64decode | from_json).collection_info.version == '1.0.0'
+ vars:
+ install_stderr: "{{ install_req.stderr | regex_replace('\\n', ' ') }}"
+
+- name: clean up collections from last test
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name'
+ state: absent
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace7
+ - namespace8
+ - namespace9
+
+- name: install collections with only one valid signature by ignoring the other errors
+ command: ansible-galaxy install -r {{ req_file }} {{ cli_opts }} {{ galaxy_verbosity }} --ignore-signature-status-code FAILURE
+ register: install_req
+ vars:
+ req_file: "{{ galaxy_dir }}/ansible_collections/requirements.yaml"
+ cli_opts: "-s {{ test_name }} --keyring {{ keyring }}"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: all
+ ANSIBLE_GALAXY_IGNORE_SIGNATURE_STATUS_CODES: BADSIG # cli option is appended and both status codes are ignored
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- name: get result of install collections with ansible-galaxy install - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name/MANIFEST.json'
+ register: install_req_actual
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace7
+ - namespace8
+ - namespace9
+
+- name: assert invalid signature is not fatal with ansible-galaxy install - {{ test_id }}
+ assert:
+ that:
+ - install_req is success
+ - '"Installing ''namespace7.name:1.0.0'' to" in install_req.stdout'
+ - '"Signature verification failed for ''namespace7.name'' (return code 1)" not in install_req.stdout'
+ - '"Not installing namespace7.name because GnuPG signature verification failed." not in install_stderr'
+ - '"Installing ''namespace8.name:1.0.0'' to" in install_req.stdout'
+ - '"Installing ''namespace9.name:1.0.0'' to" in install_req.stdout'
+ - (install_req_actual.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_req_actual.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_req_actual.results[2].content | b64decode | from_json).collection_info.version == '1.0.0'
+ vars:
+ install_stderr: "{{ install_req.stderr | regex_replace('\\n', ' ') }}"
+
+- name: clean up collections from last test
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/name'
+ state: absent
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace7
+ - namespace8
+ - namespace9
+
+# Uncomment once pulp container is at pulp>=0.5.0
+#- name: install cache.cache at the current latest version
+# command: ansible-galaxy collection install cache.cache -s '{{ test_name }}' -vvv
+# environment:
+# ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+#
+#- set_fact:
+# cache_version_build: '{{ (cache_version_build | int) + 1 }}'
+#
+#- name: publish update for cache.cache test
+# setup_collections:
+# server: galaxy_ng
+# collections:
+# - namespace: cache
+# name: cache
+# version: 1.0.{{ cache_version_build }}
+#
+#- name: make sure the cache version list is ignored on a collection version change - {{ test_id }}
+# command: ansible-galaxy collection install cache.cache -s '{{ test_name }}' --force -vvv
+# register: install_cached_update
+# environment:
+# ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+#
+#- name: get result of cache version list is ignored on a collection version change - {{ test_id }}
+# slurp:
+# path: '{{ galaxy_dir }}/ansible_collections/cache/cache/MANIFEST.json'
+# register: install_cached_update_actual
+#
+#- name: assert cache version list is ignored on a collection version change - {{ test_id }}
+# assert:
+# that:
+# - '"Installing ''cache.cache:1.0.{{ cache_version_build }}'' to" in install_cached_update.stdout'
+# - (install_cached_update_actual.content | b64decode | from_json).collection_info.version == '1.0.' ~ cache_version_build
+
+- name: install collection with symlink - {{ test_id }}
+ command: ansible-galaxy collection install symlink.symlink -s '{{ test_name }}' {{ galaxy_verbosity }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATHS: '{{ galaxy_dir }}/ansible_collections'
+ register: install_symlink
+
+- find:
+ paths: '{{ galaxy_dir }}/ansible_collections/symlink/symlink'
+ recurse: yes
+ file_type: any
+
+- name: get result of install collection with symlink - {{ test_id }}
+ stat:
+ path: '{{ galaxy_dir }}/ansible_collections/symlink/symlink/{{ path }}'
+ register: install_symlink_actual
+ loop_control:
+ loop_var: path
+ loop:
+ - REÅDMÈ.md-link
+ - docs/REÅDMÈ.md
+ - plugins/REÅDMÈ.md
+ - REÅDMÈ.md-outside-link
+ - docs-link
+ - docs-link/REÅDMÈ.md
+
+- name: assert install collection with symlink - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''symlink.symlink:1.0.0'' to" in install_symlink.stdout'
+ - install_symlink_actual.results[0].stat.islnk
+ - install_symlink_actual.results[0].stat.lnk_target == 'REÅDMÈ.md'
+ - install_symlink_actual.results[1].stat.islnk
+ - install_symlink_actual.results[1].stat.lnk_target == '../REÅDMÈ.md'
+ - install_symlink_actual.results[2].stat.islnk
+ - install_symlink_actual.results[2].stat.lnk_target == '../REÅDMÈ.md'
+ - install_symlink_actual.results[3].stat.isreg
+ - install_symlink_actual.results[4].stat.islnk
+ - install_symlink_actual.results[4].stat.lnk_target == 'docs'
+ - install_symlink_actual.results[5].stat.islnk
+ - install_symlink_actual.results[5].stat.lnk_target == '../REÅDMÈ.md'
+
+- name: remove install directory for the next test because parent_dep.parent_collection was installed - {{ test_id }}
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections'
+ state: absent
+
+- name: install collection and dep compatible with multiple requirements - {{ test_id }}
+ command: ansible-galaxy collection install parent_dep.parent_collection parent_dep2.parent_collection
+ environment:
+ ANSIBLE_COLLECTIONS_PATHS: '{{ galaxy_dir }}/ansible_collections'
+ register: install_req
+
+- name: assert install collections with ansible-galaxy install - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''parent_dep.parent_collection:1.0.0'' to" in install_req.stdout'
+ - '"Installing ''parent_dep2.parent_collection:1.0.0'' to" in install_req.stdout'
+ - '"Installing ''child_dep.child_collection:0.5.0'' to" in install_req.stdout'
+
+- name: install a collection to a directory that contains another collection with no metadata
+ block:
+
+ # Collections are usable in ansible without a galaxy.yml or MANIFEST.json
+ - name: create a collection directory
+ file:
+ state: directory
+ path: '{{ galaxy_dir }}/ansible_collections/unrelated_namespace/collection_without_metadata/plugins'
+
+ - name: install a collection to the same installation directory - {{ test_id }}
+ command: ansible-galaxy collection install namespace1.name1
+ environment:
+ ANSIBLE_COLLECTIONS_PATHS: '{{ galaxy_dir }}/ansible_collections'
+ register: install_req
+
+ - name: assert installed collections with ansible-galaxy install - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace1.name1:1.0.9'' to" in install_req.stdout'
+
+- name: remove test collection install directory - {{ test_id }}
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections'
+ state: absent
+
+# This command is hardcoded with -vvvv purposefully to evaluate extra verbosity messages
+- name: install collection with signature with invalid keyring
+ command: ansible-galaxy collection install namespace1.name1 -vvvv {{ signature_option }} {{ keyring_option }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+ vars:
+ signature_option: "--signature file://{{ gpg_homedir }}/namespace1-name1-1.0.9-MANIFEST.json.asc"
+ keyring_option: '--keyring {{ gpg_homedir }}/i_do_not_exist.kbx'
+ ignore_errors: yes
+ register: keyring_error
+
+- assert:
+ that:
+ - keyring_error is failed
+ - expected_errors[0] in actual_error
+ - expected_errors[1] in actual_error
+ - expected_errors[2] in actual_error
+ - unexpected_warning not in actual_warning
+ vars:
+ keyring: "{{ gpg_homedir }}/i_do_not_exist.kbx"
+ expected_errors:
+ - "Signature verification failed for 'namespace1.name1' (return code 2):"
+ - "* The public key is not available."
+ - >-
+ * It was not possible to check the signature. This may be caused
+ by a missing public key or an unsupported algorithm. A RC of 4
+ indicates unknown algorithm, a 9 indicates a missing public key.
+ unexpected_warning: >-
+ The GnuPG keyring used for collection signature
+ verification was not configured but signatures were
+ provided by the Galaxy server to verify authenticity.
+ Configure a keyring for ansible-galaxy to use
+ or disable signature verification.
+ Skipping signature verification.
+ actual_warning: "{{ keyring_error.stderr | regex_replace('\\n', ' ') }}"
+ # Remove formatting from the reason so it's one line
+ actual_error: "{{ keyring_error.stdout | regex_replace('\"') | regex_replace('\\n') | regex_replace(' ', ' ') }}"
+
+# TODO: Uncomment once signatures are provided by pulp-galaxy-ng
+#- name: install collection with signature provided by Galaxy server (no keyring)
+# command: ansible-galaxy collection install namespace1.name1 {{ galaxy_verbosity }}
+# environment:
+# ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+# ANSIBLE_NOCOLOR: True
+# ANSIBLE_FORCE_COLOR: False
+# ignore_errors: yes
+# register: keyring_warning
+#
+#- name: assert a warning was given but signature verification did not occur without configuring the keyring
+# assert:
+# that:
+# - keyring_warning is not failed
+# - - '"Installing ''namespace1.name1:1.0.9'' to" in keyring_warning.stdout'
+# # TODO: Don't just check the stdout, make sure the collection was installed.
+# - expected_warning in actual_warning
+# vars:
+# expected_warning: >-
+# The GnuPG keyring used for collection signature
+# verification was not configured but signatures were
+# provided by the Galaxy server to verify authenticity.
+# Configure a keyring for ansible-galaxy to use
+# or disable signature verification.
+# Skipping signature verification.
+# actual_warning: "{{ keyring_warning.stderr | regex_replace('\\n', ' ') }}"
+
+- name: install simple collection from first accessible server with valid detached signature
+ command: ansible-galaxy collection install namespace1.name1 {{ galaxy_verbosity }} {{ signature_options }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }}"
+ signature: "file://{{ gpg_homedir }}/namespace1-name1-1.0.9-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ register: from_first_good_server
+
+- name: get installed files of install simple collection from first good server
+ find:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1'
+ file_type: file
+ register: install_normal_files
+
+- name: get the manifest of install simple collection from first good server
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1/MANIFEST.json'
+ register: install_normal_manifest
+
+- name: assert install simple collection from first good server
+ assert:
+ that:
+ - '"Installing ''namespace1.name1:1.0.9'' to" in from_first_good_server.stdout'
+ - install_normal_files.files | length == 3
+ - install_normal_files.files[0].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - install_normal_files.files[1].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - install_normal_files.files[2].path | basename in ['MANIFEST.json', 'FILES.json', 'README.md']
+ - (install_normal_manifest.content | b64decode | from_json).collection_info.version == '1.0.9'
+
+- name: Remove the collection
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1'
+ state: absent
+
+# This command is hardcoded with -vvvv purposefully to evaluate extra verbosity messages
+- name: install simple collection with invalid detached signature
+ command: ansible-galaxy collection install namespace1.name1 -vvvv {{ signature_options }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }}"
+ signature: "file://{{ gpg_homedir }}/namespace2-name-1.0.0-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ ignore_errors: yes
+ register: invalid_signature
+
+- assert:
+ that:
+ - invalid_signature is failed
+ - "'Not installing namespace1.name1 because GnuPG signature verification failed.' in invalid_signature.stderr"
+ - expected_errors[0] in install_stdout
+ - expected_errors[1] in install_stdout
+ vars:
+ expected_errors:
+ - "* This is the counterpart to SUCCESS and used to indicate a program failure."
+ - "* The signature with the keyid has not been verified okay."
+ # Remove formatting from the reason so it's one line
+ install_stdout: "{{ invalid_signature.stdout | regex_replace('\"') | regex_replace('\\n') | regex_replace(' ', ' ') }}"
+
+- name: validate collection directory was not created
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1'
+ state: absent
+ register: collection_dir
+ check_mode: yes
+ failed_when: collection_dir is changed
+
+- name: disable signature verification and install simple collection with invalid detached signature
+ command: ansible-galaxy collection install namespace1.name1 {{ galaxy_verbosity }} {{ signature_options }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }} --disable-gpg-verify"
+ signature: "file://{{ gpg_homedir }}/namespace2-name-1.0.0-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ ignore_errors: yes
+ register: ignore_invalid_signature
+
+- assert:
+ that:
+ - ignore_invalid_signature is success
+ - '"Installing ''namespace1.name1:1.0.9'' to" in ignore_invalid_signature.stdout'
+
+- name: use lenient signature verification (default) without providing signatures
+ command: ansible-galaxy collection install namespace1.name1:1.0.0 -vvvv --keyring {{ gpg_homedir }}/pubring.kbx --force
+ environment:
+ ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: "all"
+ register: missing_signature
+
+- assert:
+ that:
+ - missing_signature is success
+ - missing_signature.rc == 0
+ - '"namespace1.name1:1.0.0 was installed successfully" in missing_signature.stdout'
+ - '"Signature verification failed for ''namespace1.name1'': no successful signatures" not in missing_signature.stdout'
+
+- name: use strict signature verification without providing signatures
+ command: ansible-galaxy collection install namespace1.name1:1.0.0 -vvvv --keyring {{ gpg_homedir }}/pubring.kbx --force
+ environment:
+ ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: "+1"
+ ignore_errors: yes
+ register: missing_signature
+
+- assert:
+ that:
+ - missing_signature is failed
+ - missing_signature.rc == 1
+ - '"Signature verification failed for ''namespace1.name1'': no successful signatures" in missing_signature.stdout'
+ - '"Not installing namespace1.name1 because GnuPG signature verification failed" in missing_signature.stderr'
+
+- name: Remove the collection
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1'
+ state: absent
+
+- name: download collections with pre-release dep - {{ test_id }}
+ command: ansible-galaxy collection download dep_with_beta.parent namespace1.name1:1.1.0-beta.1 -p '{{ galaxy_dir }}/scratch'
+
+- name: install collection with concrete pre-release dep - {{ test_id }}
+ command: ansible-galaxy collection install -r '{{ galaxy_dir }}/scratch/requirements.yml'
+ args:
+ chdir: '{{ galaxy_dir }}/scratch'
+ environment:
+ ANSIBLE_COLLECTIONS_PATHS: '{{ galaxy_dir }}/ansible_collections'
+ register: install_concrete_pre
+
+- name: get result of install collections with concrete pre-release dep - {{ test_id }}
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ collection }}/MANIFEST.json'
+ register: install_concrete_pre_actual
+ loop_control:
+ loop_var: collection
+ loop:
+ - namespace1/name1
+ - dep_with_beta/parent
+
+- name: assert install collections with ansible-galaxy install - {{ test_id }}
+ assert:
+ that:
+ - '"Installing ''namespace1.name1:1.1.0-beta.1'' to" in install_concrete_pre.stdout'
+ - '"Installing ''dep_with_beta.parent:1.0.0'' to" in install_concrete_pre.stdout'
+ - (install_concrete_pre_actual.results[0].content | b64decode | from_json).collection_info.version == '1.1.0-beta.1'
+ - (install_concrete_pre_actual.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+
+- name: remove collection dir after round of testing - {{ test_id }}
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections'
+ state: absent
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/install_offline.yml b/test/integration/targets/ansible-galaxy-collection/tasks/install_offline.yml
new file mode 100644
index 0000000..74c9983
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/install_offline.yml
@@ -0,0 +1,137 @@
+- name: test tarfile dependency resolution without querying distribution servers
+ vars:
+ init_dir: "{{ galaxy_dir }}/offline/setup"
+ build_dir: "{{ galaxy_dir }}/offline/build"
+ install_dir: "{{ galaxy_dir }}/offline/collections"
+ block:
+ - name: create test directories
+ file:
+ path: "{{ item }}"
+ state: directory
+ loop:
+ - "{{ init_dir }}"
+ - "{{ build_dir }}"
+ - "{{ install_dir }}"
+
+ - name: initialize two collections
+ command: ansible-galaxy collection init ns.{{ item }} --init-path {{ init_dir }}
+ loop:
+ - coll1
+ - coll2
+
+ - name: add one collection as the dependency of the other
+ lineinfile:
+ path: "{{ galaxy_dir }}/offline/setup/ns/coll1/galaxy.yml"
+ regexp: "^dependencies:*"
+ line: "dependencies: {'ns.coll2': '>=1.0.0'}"
+
+ - name: build both collections
+ command: ansible-galaxy collection build {{ init_dir }}/ns/{{ item }}
+ args:
+ chdir: "{{ build_dir }}"
+ loop:
+ - coll1
+ - coll2
+
+ - name: install the dependency from the tarfile
+ command: ansible-galaxy collection install {{ build_dir }}/ns-coll2-1.0.0.tar.gz -p {{ install_dir }} -s offline
+
+ - name: install the tarfile with the installed dependency
+ command: ansible-galaxy collection install {{ build_dir }}/ns-coll1-1.0.0.tar.gz -p {{ install_dir }} -s offline
+
+ - name: empty the installed collections directory
+ file:
+ path: "{{ install_dir }}"
+ state: "{{ item }}"
+ loop:
+ - absent
+ - directory
+
+ - name: edit skeleton with new versions to test upgrading
+ lineinfile:
+ path: "{{ galaxy_dir }}/offline/setup/ns/{{ item }}/galaxy.yml"
+ regexp: "^version:.*$"
+ line: "version: 2.0.0"
+ loop:
+ - coll1
+ - coll2
+
+ - name: build the tarfiles to test upgrading
+ command: ansible-galaxy collection build {{ init_dir }}/ns/{{ item }}
+ args:
+ chdir: "{{ build_dir }}"
+ loop:
+ - coll1
+ - coll2
+
+ - name: install the tarfile and its dep with an unreachable server (expected error)
+ command: ansible-galaxy collection install {{ build_dir }}/ns-coll1-1.0.0.tar.gz -p {{ install_dir }} -s offline
+ environment:
+ ANSIBLE_FORCE_COLOR: False
+ ANSIBLE_NOCOLOR: True
+ ignore_errors: yes
+ register: missing_dep
+
+ - name: install the tarfile with a missing dependency and --offline
+ command: ansible-galaxy collection install --offline {{ build_dir }}/ns-coll1-1.0.0.tar.gz -p {{ install_dir }} -s offline
+ environment:
+ ANSIBLE_FORCE_COLOR: False
+ ANSIBLE_NOCOLOR: True
+ ignore_errors: yes
+ register: missing_dep_offline
+
+ - assert:
+ that:
+ - missing_dep.failed
+ - missing_dep_offline.failed
+ - galaxy_err in missing_dep.stderr
+ - missing_err in missing_dep_offline.stderr
+ vars:
+ galaxy_err: "ERROR! Unknown error when attempting to call Galaxy at '{{ offline_server }}'"
+ missing_err: |-
+ ERROR! Failed to resolve the requested dependencies map. Could not satisfy the following requirements:
+ * ns.coll2:>=1.0.0 (dependency of ns.coll1:1.0.0)
+
+ - name: install the dependency from the tarfile
+ command: ansible-galaxy collection install {{ build_dir }}/ns-coll2-1.0.0.tar.gz -p {{ install_dir }}
+
+ - name: install the tarfile with --offline for dep resolution
+ command: ansible-galaxy collection install {{ build_dir }}/ns-coll1-1.0.0.tar.gz {{ cli_opts }}
+ vars:
+ cli_opts: "--offline -p {{ install_dir }} -s offline"
+ register: offline_install
+
+ - name: upgrade using tarfile with --offline for dep resolution
+ command: ansible-galaxy collection install {{ build_dir }}/ns-coll1-2.0.0.tar.gz {{ cli_opts }}
+ vars:
+ cli_opts: "--offline --upgrade -p {{ install_dir }} -s offline"
+ register: offline_upgrade
+
+ - name: reinstall ns-coll1-1.0.0 to test upgrading the dependency too
+ command: ansible-galaxy collection install {{ build_dir }}/ns-coll1-1.0.0.tar.gz {{ cli_opts }}
+ vars:
+ cli_opts: "--offline --force -p {{ install_dir }} -s offline"
+
+ - name: upgrade both collections using tarfiles and --offline
+ command: ansible-galaxy collection install {{ collections }} {{ cli_opts }}
+ vars:
+ collections: "{{ build_dir }}/ns-coll1-2.0.0.tar.gz {{ build_dir }}/ns-coll2-2.0.0.tar.gz"
+ cli_opts: "--offline --upgrade -s offline"
+ register: upgrade_all
+
+ - assert:
+ that:
+ - '"ns.coll1:1.0.0 was installed successfully" in offline_install.stdout'
+ - '"ns.coll1:2.0.0 was installed successfully" in offline_upgrade.stdout'
+ - '"ns.coll1:2.0.0 was installed successfully" in upgrade_all.stdout'
+ - '"ns.coll2:2.0.0 was installed successfully" in upgrade_all.stdout'
+
+ always:
+ - name: clean up test directories
+ file:
+ path: "{{ item }}"
+ state: absent
+ loop:
+ - "{{ init_dir }}"
+ - "{{ build_dir }}"
+ - "{{ install_dir }}"
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/list.yml b/test/integration/targets/ansible-galaxy-collection/tasks/list.yml
new file mode 100644
index 0000000..b8d6349
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/list.yml
@@ -0,0 +1,167 @@
+- name: initialize collection structure
+ command: ansible-galaxy collection init {{ item }} --init-path "{{ galaxy_dir }}/dev/ansible_collections" {{ galaxy_verbosity }}
+ loop:
+ - 'dev.collection1'
+ - 'dev.collection2'
+ - 'dev.collection3'
+ - 'dev.collection4'
+ - 'dev.collection5'
+ - 'dev.collection6'
+
+- name: replace the default version of the collections
+ lineinfile:
+ path: "{{ galaxy_dir }}/dev/ansible_collections/dev/{{ item.name }}/galaxy.yml"
+ line: "{{ item.version }}"
+ regexp: "version: .*"
+ loop:
+ - name: "collection1"
+ version: "version: null"
+ - name: "collection2"
+ version: "version: placeholder"
+ - name: "collection3"
+ version: "version: ''"
+
+- name: set the namespace, name, and version keys to None
+ lineinfile:
+ path: "{{ galaxy_dir }}/dev/ansible_collections/dev/collection4/galaxy.yml"
+ line: "{{ item.after }}"
+ regexp: "{{ item.before }}"
+ loop:
+ - before: "^namespace: dev"
+ after: "namespace:"
+ - before: "^name: collection4"
+ after: "name:"
+ - before: "^version: 1.0.0"
+ after: "version:"
+
+- name: replace galaxy.yml content with a string
+ copy:
+ content: "invalid"
+ dest: "{{ galaxy_dir }}/dev/ansible_collections/dev/collection5/galaxy.yml"
+
+- name: remove galaxy.yml key required by build
+ lineinfile:
+ path: "{{ galaxy_dir }}/dev/ansible_collections/dev/collection6/galaxy.yml"
+ line: "version: 1.0.0"
+ state: absent
+
+- name: list collections in development without semver versions
+ command: ansible-galaxy collection list {{ galaxy_verbosity }}
+ register: list_result
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
+
+- assert:
+ that:
+ - "'dev.collection1 *' in list_result.stdout"
+ # Note the version displayed is the 'placeholder' string rather than "*" since it is not falsey
+ - "'dev.collection2 placeholder' in list_result.stdout"
+ - "'dev.collection3 *' in list_result.stdout"
+ - "'dev.collection4 *' in list_result.stdout"
+ - "'dev.collection5 *' in list_result.stdout"
+ - "'dev.collection6 *' in list_result.stdout"
+
+- name: list collections in human format
+ command: ansible-galaxy collection list --format human
+ register: list_result_human
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
+
+- assert:
+ that:
+ - "'dev.collection1 *' in list_result_human.stdout"
+ # Note the version displayed is the 'placeholder' string rather than "*" since it is not falsey
+ - "'dev.collection2 placeholder' in list_result_human.stdout"
+ - "'dev.collection3 *' in list_result_human.stdout"
+ - "'dev.collection5 *' in list_result.stdout"
+ - "'dev.collection6 *' in list_result.stdout"
+
+- name: list collections in yaml format
+ command: ansible-galaxy collection list --format yaml
+ register: list_result_yaml
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
+
+- assert:
+ that:
+ - "item.value | length == 6"
+ - "item.value['dev.collection1'].version == '*'"
+ - "item.value['dev.collection2'].version == 'placeholder'"
+ - "item.value['dev.collection3'].version == '*'"
+ - "item.value['dev.collection5'].version == '*'"
+ - "item.value['dev.collection6'].version == '*'"
+ with_dict: "{{ list_result_yaml.stdout | from_yaml }}"
+
+- name: list collections in json format
+ command: ansible-galaxy collection list --format json
+ register: list_result_json
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
+
+- assert:
+ that:
+ - "item.value | length == 6"
+ - "item.value['dev.collection1'].version == '*'"
+ - "item.value['dev.collection2'].version == 'placeholder'"
+ - "item.value['dev.collection3'].version == '*'"
+ - "item.value['dev.collection5'].version == '*'"
+ - "item.value['dev.collection6'].version == '*'"
+ with_dict: "{{ list_result_json.stdout | from_json }}"
+
+- name: list single collection in json format
+ command: "ansible-galaxy collection list {{ item.key }} --format json"
+ register: list_single_result_json
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
+ with_dict: "{{ { 'dev.collection1': '*', 'dev.collection2': 'placeholder', 'dev.collection3': '*' } }}"
+
+- assert:
+ that:
+ - "(item.stdout | from_json)[galaxy_dir + '/dev/ansible_collections'][item.item.key].version == item.item.value"
+ with_items: "{{ list_single_result_json.results }}"
+
+- name: list single collection in yaml format
+ command: "ansible-galaxy collection list {{ item.key }} --format yaml"
+ register: list_single_result_yaml
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
+ with_dict: "{{ { 'dev.collection1': '*', 'dev.collection2': 'placeholder', 'dev.collection3': '*' } }}"
+
+- assert:
+ that:
+ - "(item.stdout | from_yaml)[galaxy_dir + '/dev/ansible_collections'][item.item.key].version == item.item.value"
+ with_items: "{{ list_single_result_json.results }}"
+
+- name: test that no json is emitted when no collection paths are usable
+ command: "ansible-galaxy collection list --format json"
+ register: list_result_error
+ ignore_errors: True
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: ""
+
+- assert:
+ that:
+ - "'{}' not in list_result_error.stdout"
+
+- name: install an artifact to the second collections path
+ command: ansible-galaxy collection install namespace1.name1 -s galaxy_ng {{ galaxy_verbosity }} -p "{{ galaxy_dir }}/prod"
+ environment:
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+
+- name: replace the artifact version
+ lineinfile:
+ path: "{{ galaxy_dir }}/prod/ansible_collections/namespace1/name1/MANIFEST.json"
+ line: ' "version": null,'
+ regexp: ' "version": .*'
+
+- name: test listing collections in all paths
+ command: ansible-galaxy collection list {{ galaxy_verbosity }}
+ register: list_result
+ ignore_errors: True
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
+
+- assert:
+ that:
+ - list_result is failed
+ - "'is expected to have a valid SemVer version value but got None' in list_result.stderr"
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/main.yml b/test/integration/targets/ansible-galaxy-collection/tasks/main.yml
new file mode 100644
index 0000000..724c861
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/main.yml
@@ -0,0 +1,220 @@
+---
+- name: set some facts for tests
+ set_fact:
+ galaxy_dir: "{{ remote_tmp_dir }}/galaxy"
+
+- name: create scratch dir used for testing
+ file:
+ path: '{{ galaxy_dir }}/scratch'
+ state: directory
+
+- name: run ansible-galaxy collection init tests
+ import_tasks: init.yml
+
+- name: run ansible-galaxy collection build tests
+ import_tasks: build.yml
+
+# The pulp container has a long start up time
+# The first task to interact with pulp needs to wait until it responds appropriately
+- name: list pulp distributions
+ uri:
+ url: '{{ pulp_api }}/pulp/api/v3/distributions/ansible/ansible/'
+ status_code:
+ - 200
+ user: '{{ pulp_user }}'
+ password: '{{ pulp_password }}'
+ force_basic_auth: true
+ register: pulp_distributions
+ until: pulp_distributions is successful
+ delay: 1
+ retries: 60
+
+- name: configure pulp
+ include_tasks: pulp.yml
+
+- name: Get galaxy_ng token
+ uri:
+ url: '{{ galaxy_ng_server }}v3/auth/token/'
+ method: POST
+ body_format: json
+ body: {}
+ status_code:
+ - 200
+ user: '{{ pulp_user }}'
+ password: '{{ pulp_password }}'
+ force_basic_auth: true
+ register: galaxy_ng_token
+
+- name: create test ansible.cfg that contains the Galaxy server list
+ template:
+ src: ansible.cfg.j2
+ dest: '{{ galaxy_dir }}/ansible.cfg'
+
+- name: test install command using an unsupported version of resolvelib
+ include_tasks: unsupported_resolvelib.yml
+ loop: "{{ unsupported_resolvelib_versions }}"
+ loop_control:
+ loop_var: resolvelib_version
+
+- name: run ansible-galaxy collection offline installation tests
+ include_tasks: install_offline.yml
+ args:
+ apply:
+ environment:
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+
+- name: run ansible-galaxy collection publish tests for {{ test_name }}
+ include_tasks: publish.yml
+ args:
+ apply:
+ environment:
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+ vars:
+ test_name: '{{ item.name }}'
+ test_server: '{{ item.server }}'
+ vX: '{{ "v3/" if item.v3|default(false) else "v2/" }}'
+ loop:
+ - name: pulp_v2
+ server: '{{ pulp_server }}published/api/'
+ - name: pulp_v3
+ server: '{{ pulp_server }}published/api/'
+ v3: true
+ - name: galaxy_ng
+ server: '{{ galaxy_ng_server }}'
+ v3: true
+
+- include_tasks: setup_gpg.yml
+
+# We use a module for this so we can speed up the test time.
+# For pulp interactions, we only upload to galaxy_ng which shares
+# the same repo and distribution with pulp_ansible
+# However, we use galaxy_ng only, since collections are unique across
+# pulp repositories, and galaxy_ng maintains a 2nd list of published collections
+- name: setup test collections for install and download test
+ setup_collections:
+ server: galaxy_ng
+ collections: '{{ collection_list }}'
+ signature_dir: '{{ gpg_homedir }}'
+ environment:
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+
+# Stores the cached test version number index as we run install many times
+- set_fact:
+ cache_version_build: 0
+
+- name: run ansible-galaxy collection install tests for {{ test_name }}
+ include_tasks: install.yml
+ vars:
+ test_id: '{{ item.name }}'
+ test_name: '{{ item.name }}'
+ test_server: '{{ item.server }}'
+ vX: '{{ "v3/" if item.v3|default(false) else "v2/" }}'
+ requires_auth: '{{ item.requires_auth|default(false) }}'
+ args:
+ apply:
+ environment:
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+ loop:
+ - name: galaxy_ng
+ server: '{{ galaxy_ng_server }}'
+ v3: true
+ requires_auth: true
+ - name: pulp_v2
+ server: '{{ pulp_server }}published/api/'
+ - name: pulp_v3
+ server: '{{ pulp_server }}published/api/'
+ v3: true
+
+- name: test installing and downloading collections with the range of supported resolvelib versions
+ include_tasks: supported_resolvelib.yml
+ args:
+ apply:
+ environment:
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+ loop: '{{ supported_resolvelib_versions }}'
+ loop_control:
+ loop_var: resolvelib_version
+
+- name: publish collection with a dep on another server
+ setup_collections:
+ server: secondary
+ collections:
+ - namespace: secondary
+ name: name
+ # parent_dep.parent_collection does not exist on the secondary server
+ dependencies:
+ parent_dep.parent_collection: '1.0.0'
+ environment:
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+
+- name: install collection with dep on another server
+ command: ansible-galaxy collection install secondary.name -vvv # 3 -v's will show the source in the stdout
+ register: install_cross_dep
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+
+- name: get result of install collection with dep on another server
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ item.namespace }}/{{ item.name }}/MANIFEST.json'
+ register: install_cross_dep_actual
+ loop:
+ - namespace: secondary
+ name: name
+ - namespace: parent_dep
+ name: parent_collection
+ - namespace: child_dep
+ name: child_collection
+ - namespace: child_dep
+ name: child_dep2
+
+- name: assert result of install collection with dep on another server
+ assert:
+ that:
+ - >-
+ "'secondary.name:1.0.0' obtained from server secondary"
+ in install_cross_dep.stdout
+ # pulp_v2 is highest in the list so it will find it there first
+ - >-
+ "'parent_dep.parent_collection:1.0.0' obtained from server pulp_v2"
+ in install_cross_dep.stdout
+ - >-
+ "'child_dep.child_collection:0.9.9' obtained from server pulp_v2"
+ in install_cross_dep.stdout
+ - >-
+ "'child_dep.child_dep2:1.2.2' obtained from server pulp_v2"
+ in install_cross_dep.stdout
+ - (install_cross_dep_actual.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_cross_dep_actual.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - (install_cross_dep_actual.results[2].content | b64decode | from_json).collection_info.version == '0.9.9'
+ - (install_cross_dep_actual.results[3].content | b64decode | from_json).collection_info.version == '1.2.2'
+
+- name: run ansible-galaxy collection download tests
+ include_tasks: download.yml
+ args:
+ apply:
+ environment:
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+
+- name: run ansible-galaxy collection verify tests for {{ test_name }}
+ include_tasks: verify.yml
+ args:
+ apply:
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}'
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+ vars:
+ test_api_fallback: 'pulp_v2'
+ test_api_fallback_versions: 'v1, v2'
+ test_name: 'galaxy_ng'
+ test_server: '{{ galaxy_ng_server }}'
+
+- name: run ansible-galaxy collection list tests
+ include_tasks: list.yml
+
+- include_tasks: upgrade.yml
+ args:
+ apply:
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}'
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/publish.yml b/test/integration/targets/ansible-galaxy-collection/tasks/publish.yml
new file mode 100644
index 0000000..241eae6
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/publish.yml
@@ -0,0 +1,33 @@
+---
+- name: publish collection - {{ test_name }}
+ command: ansible-galaxy collection publish ansible_test-my_collection-1.0.0.tar.gz -s {{ test_name }} {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}'
+ register: publish_collection
+
+- name: get result of publish collection - {{ test_name }}
+ uri:
+ url: '{{ test_server }}{{ vX }}collections/ansible_test/my_collection/versions/1.0.0/'
+ return_content: yes
+ user: '{{ pulp_user }}'
+ password: '{{ pulp_password }}'
+ force_basic_auth: true
+ register: publish_collection_actual
+
+- name: assert publish collection - {{ test_name }}
+ assert:
+ that:
+ - '"Collection has been successfully published and imported to the Galaxy server" in publish_collection.stdout'
+ - publish_collection_actual.json.collection.name == 'my_collection'
+ - publish_collection_actual.json.namespace.name == 'ansible_test'
+ - publish_collection_actual.json.version == '1.0.0'
+
+- name: fail to publish existing collection version - {{ test_name }}
+ command: ansible-galaxy collection publish ansible_test-my_collection-1.0.0.tar.gz -s {{ test_name }} {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}'
+ register: fail_publish_existing
+ failed_when: fail_publish_existing is not failed
+
+- name: reset published collections - {{ test_name }}
+ include_tasks: pulp.yml
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/pulp.yml b/test/integration/targets/ansible-galaxy-collection/tasks/pulp.yml
new file mode 100644
index 0000000..7b6c5f8
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/pulp.yml
@@ -0,0 +1,11 @@
+# These tasks configure pulp/pulp_ansible so that we can use the container
+# This will also reset pulp between iterations
+# A module is used to make the tests run quicker as this will send lots of API requests.
+- name: reset pulp content
+ reset_pulp:
+ pulp_api: '{{ pulp_api }}'
+ galaxy_ng_server: '{{ galaxy_ng_server }}'
+ url_username: '{{ pulp_user }}'
+ url_password: '{{ pulp_password }}'
+ repositories: '{{ pulp_repositories }}'
+ namespaces: '{{ collection_list|map(attribute="namespace")|unique + publish_namespaces }}'
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/revoke_gpg_key.yml b/test/integration/targets/ansible-galaxy-collection/tasks/revoke_gpg_key.yml
new file mode 100644
index 0000000..7a49eee
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/revoke_gpg_key.yml
@@ -0,0 +1,14 @@
+- name: generate revocation certificate
+ expect:
+ command: "gpg --homedir {{ gpg_homedir }} --pinentry-mode loopback --output {{ gpg_homedir }}/revoke.asc --gen-revoke {{ fingerprint }}"
+ responses:
+ "Create a revocation certificate for this key": "y"
+ "Please select the reason for the revocation": "0"
+ "Enter an optional description": ""
+ "Is this okay": "y"
+
+- name: revoke key
+ command: "gpg --no-tty --homedir {{ gpg_homedir }} --import {{ gpg_homedir }}/revoke.asc"
+
+- name: list keys for debugging
+ command: "gpg --no-tty --homedir {{ gpg_homedir }} --list-keys {{ gpg_user }}"
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/setup_gpg.yml b/test/integration/targets/ansible-galaxy-collection/tasks/setup_gpg.yml
new file mode 100644
index 0000000..ddc4d8a
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/setup_gpg.yml
@@ -0,0 +1,24 @@
+- name: create empty gpg homedir
+ file:
+ state: "{{ item }}"
+ path: "{{ gpg_homedir }}"
+ mode: 0700
+ loop:
+ - absent
+ - directory
+
+- name: get username for generating key
+ command: whoami
+ register: user
+
+- name: generate key for user with gpg
+ command: "gpg --no-tty --homedir {{ gpg_homedir }} --passphrase '' --pinentry-mode loopback --quick-gen-key {{ user.stdout }} default default"
+
+- name: list gpg keys for user
+ command: "gpg --no-tty --homedir {{ gpg_homedir }} --list-keys {{ user.stdout }}"
+ register: gpg_list_keys
+
+- name: save gpg user and fingerprint of new key
+ set_fact:
+ gpg_user: "{{ user.stdout }}"
+ fingerprint: "{{ gpg_list_keys.stdout_lines[1] | trim }}"
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/supported_resolvelib.yml b/test/integration/targets/ansible-galaxy-collection/tasks/supported_resolvelib.yml
new file mode 100644
index 0000000..763c5a1
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/supported_resolvelib.yml
@@ -0,0 +1,44 @@
+- vars:
+ venv_cmd: "{{ ansible_python_interpreter ~ ' -m venv' }}"
+ venv_dest: "{{ galaxy_dir }}/test_venv_{{ resolvelib_version }}"
+ block:
+ - name: install another version of resolvelib that is supported by ansible-galaxy
+ pip:
+ name: resolvelib
+ version: "{{ resolvelib_version }}"
+ state: present
+ virtualenv_command: "{{ venv_cmd }}"
+ virtualenv: "{{ venv_dest }}"
+ virtualenv_site_packages: True
+
+ - include_tasks: fail_fast_resolvelib.yml
+ args:
+ apply:
+ environment:
+ PATH: "{{ venv_dest }}/bin:{{ ansible_env.PATH }}"
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+
+ - include_tasks: install.yml
+ vars:
+ test_name: pulp_v3
+ test_id: '{{ test_name }} (resolvelib {{ resolvelib_version }})'
+ test_server: '{{ pulp_server }}published/api/'
+ vX: "v3/"
+ requires_auth: false
+ args:
+ apply:
+ environment:
+ PATH: "{{ venv_dest }}/bin:{{ ansible_env.PATH }}"
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+
+ - include_tasks: download.yml
+ args:
+ apply:
+ environment:
+ PATH: "{{ venv_dest }}/bin:{{ ansible_env.PATH }}"
+ ANSIBLE_CONFIG: '{{ galaxy_dir }}/ansible.cfg'
+ always:
+ - name: remove test venv
+ file:
+ path: "{{ venv_dest }}"
+ state: absent
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/unsupported_resolvelib.yml b/test/integration/targets/ansible-galaxy-collection/tasks/unsupported_resolvelib.yml
new file mode 100644
index 0000000..a208b29
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/unsupported_resolvelib.yml
@@ -0,0 +1,44 @@
+- vars:
+ venv_cmd: "{{ ansible_python_interpreter ~ ' -m venv' }}"
+ venv_dest: "{{ galaxy_dir }}/test_resolvelib_{{ resolvelib_version }}"
+ block:
+ - name: install another version of resolvelib that is unsupported by ansible-galaxy
+ pip:
+ name: resolvelib
+ version: "{{ resolvelib_version }}"
+ state: present
+ virtualenv_command: "{{ venv_cmd }}"
+ virtualenv: "{{ venv_dest }}"
+ virtualenv_site_packages: True
+
+ - name: create test collection install directory - {{ test_name }}
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections'
+ state: directory
+
+ - name: install simple collection from first accessible server (expected failure)
+ command: "ansible-galaxy collection install namespace1.name1 {{ galaxy_verbosity }}"
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections'
+ PATH: "{{ venv_dest }}/bin:{{ ansible_env.PATH }}"
+ register: resolvelib_version_error
+ ignore_errors: yes
+
+ - assert:
+ that:
+ - resolvelib_version_error is failed
+ - resolvelib_version_error.stderr | regex_search(error)
+ vars:
+ error: "({{ import_error }}|{{ compat_error }})"
+ import_error: "Failed to import resolvelib"
+ compat_error: "ansible-galaxy requires resolvelib<{{major_minor_patch}},>={{major_minor_patch}}"
+ major_minor_patch: "[0-9]\\d*\\.[0-9]\\d*\\.[0-9]\\d*"
+
+ always:
+ - name: cleanup venv and install directory
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections'
+ state: absent
+ loop:
+ - '{{ galaxy_dir }}/ansible_collections'
+ - '{{ venv_dest }}'
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml b/test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml
new file mode 100644
index 0000000..893ea80
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml
@@ -0,0 +1,282 @@
+##### Updating collections with a new version constraint
+
+# No deps
+
+- name: reset installation directory
+ file:
+ state: "{{ item }}"
+ path: "{{ galaxy_dir }}/ansible_collections"
+ loop:
+ - absent
+ - directory
+
+- name: install a collection
+ command: ansible-galaxy collection install namespace1.name1:0.0.1 {{ galaxy_verbosity }}
+ register: result
+ failed_when:
+ - '"namespace1.name1:0.0.1 was installed successfully" not in result.stdout_lines'
+
+- name: install a new version of the collection without --force
+ command: ansible-galaxy collection install namespace1.name1:>0.0.4,<=0.0.5 {{ galaxy_verbosity }}
+ register: result
+
+- name: check the MANIFEST.json to verify the version
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1/MANIFEST.json'
+ register: metadata
+
+- assert:
+ that:
+ - '"namespace1.name1:0.0.5 was installed successfully" in result.stdout_lines'
+ - (metadata.content | b64decode | from_json).collection_info.version == '0.0.5'
+
+- name: don't reinstall the collection in the requirement is compatible
+ command: ansible-galaxy collection install namespace1.name1:>=0.0.5 {{ galaxy_verbosity }}
+ register: result
+
+- assert:
+ that: "\"Nothing to do. All requested collections are already installed.\" in result.stdout"
+
+- name: install a pre-release of the collection without --force
+ command: ansible-galaxy collection install namespace1.name1:1.1.0-beta.1 {{ galaxy_verbosity }}
+ register: result
+
+- name: check the MANIFEST.json to verify the version
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1/MANIFEST.json'
+ register: metadata
+
+- assert:
+ that:
+ - '"namespace1.name1:1.1.0-beta.1 was installed successfully" in result.stdout_lines'
+ - (metadata.content | b64decode | from_json).collection_info.version == '1.1.0-beta.1'
+
+# With deps
+
+- name: reset installation directory
+ file:
+ state: "{{ item }}"
+ path: "{{ galaxy_dir }}/ansible_collections"
+ loop:
+ - absent
+ - directory
+
+- name: install a dep that will need to be upgraded to be compatible with the parent
+ command: ansible-galaxy collection install child_dep.child_collection:0.4.0 --no-deps {{ galaxy_verbosity }}
+ register: result
+ failed_when:
+ - '"child_dep.child_collection:0.4.0 was installed successfully" not in result.stdout_lines'
+
+- name: install a dep of the dep that will need to be upgraded to be compatible
+ command: ansible-galaxy collection install child_dep.child_dep2:>1.2.2 {{ galaxy_verbosity }}
+ register: result
+ failed_when:
+ - '"child_dep.child_dep2:1.2.3 was installed successfully" not in result.stdout_lines'
+
+- name: install the parent without deps to test dep reconciliation during upgrade
+ command: ansible-galaxy collection install parent_dep.parent_collection:0.0.1 {{ galaxy_verbosity }}
+ register: result
+ failed_when:
+ - '"parent_dep.parent_collection:0.0.1 was installed successfully" not in result.stdout_lines'
+
+- name: test upgrading the parent collection and dependencies
+ command: ansible-galaxy collection install parent_dep.parent_collection:>=1.0.0,<1.1.0 {{ galaxy_verbosity }}
+ register: result
+
+- name: check the MANIFEST.json to verify the versions
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ item.namespace }}/{{ item.name }}/MANIFEST.json'
+ register: metadata
+ loop:
+ - namespace: parent_dep
+ name: parent_collection
+ - namespace: child_dep
+ name: child_collection
+ - namespace: child_dep
+ name: child_dep2
+
+- assert:
+ that:
+ - '"parent_dep.parent_collection:1.0.0 was installed successfully" in result.stdout_lines'
+ - (metadata.results[0].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - '"child_dep.child_collection:0.9.9 was installed successfully" in result.stdout_lines'
+ - (metadata.results[1].content | b64decode | from_json).collection_info.version == '0.9.9'
+ - '"child_dep.child_dep2:1.2.2 was installed successfully" in result.stdout_lines'
+ - (metadata.results[2].content | b64decode | from_json).collection_info.version == '1.2.2'
+
+- name: test upgrading a collection only upgrades dependencies if necessary
+ command: ansible-galaxy collection install parent_dep.parent_collection:1.1.0 {{ galaxy_verbosity }}
+ register: result
+
+- name: check the MANIFEST.json to verify the versions
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ item.namespace }}/{{ item.name }}/MANIFEST.json'
+ register: metadata
+ loop:
+ - namespace: parent_dep
+ name: parent_collection
+ - namespace: child_dep
+ name: child_collection
+ - namespace: child_dep
+ name: child_dep2
+
+- assert:
+ that:
+ - '"parent_dep.parent_collection:1.1.0 was installed successfully" in result.stdout_lines'
+ - (metadata.results[0].content | b64decode | from_json).collection_info.version == '1.1.0'
+ - "\"'child_dep.child_collection:0.9.9' is already installed, skipping.\" in result.stdout_lines"
+ - (metadata.results[1].content | b64decode | from_json).collection_info.version == '0.9.9'
+ - "\"'child_dep.child_dep2:1.2.2' is already installed, skipping.\" in result.stdout_lines"
+ - (metadata.results[2].content | b64decode | from_json).collection_info.version == '1.2.2'
+
+##### Updating collections with --upgrade
+
+# No deps
+
+- name: reset installation directory
+ file:
+ state: "{{ item }}"
+ path: "{{ galaxy_dir }}/ansible_collections"
+ loop:
+ - absent
+ - directory
+
+- name: install a collection
+ command: ansible-galaxy collection install namespace1.name1:0.0.1 {{ galaxy_verbosity }}
+ register: result
+ failed_when:
+ - '"namespace1.name1:0.0.1 was installed successfully" not in result.stdout_lines'
+
+- name: install a new version of the collection with --upgrade
+ command: ansible-galaxy collection install namespace1.name1:<=0.0.5 --upgrade {{ galaxy_verbosity }}
+ register: result
+
+- name: check the MANIFEST.json to verify the version
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/namespace1/name1/MANIFEST.json'
+ register: metadata
+
+- assert:
+ that:
+ - '"namespace1.name1:0.0.5 was installed successfully" in result.stdout_lines'
+ - (metadata.content | b64decode | from_json).collection_info.version == '0.0.5'
+
+- name: upgrade the collection
+ command: ansible-galaxy collection install namespace1.name1:<0.0.7 -U {{ galaxy_verbosity }}
+ register: result
+
+- assert:
+ that: '"namespace1.name1:0.0.6 was installed successfully" in result.stdout_lines'
+
+- name: upgrade the collection to the last version excluding prereleases
+ command: ansible-galaxy collection install namespace1.name1 -U {{ galaxy_verbosity }}
+ register: result
+
+- assert:
+ that: '"namespace1.name1:1.0.9 was installed successfully" in result.stdout_lines'
+
+- name: upgrade the collection to the latest available version including prereleases
+ command: ansible-galaxy collection install namespace1.name1 --pre -U {{ galaxy_verbosity }}
+ register: result
+
+- assert:
+ that: '"namespace1.name1:1.1.0-beta.1 was installed successfully" in result.stdout_lines'
+
+- name: run the same command again
+ command: ansible-galaxy collection install namespace1.name1 --pre -U {{ galaxy_verbosity }}
+ register: result
+
+- assert:
+ that: "\"'namespace1.name1:1.1.0-beta.1' is already installed, skipping.\" in result.stdout"
+
+# With deps
+
+- name: reset installation directory
+ file:
+ state: "{{ item }}"
+ path: "{{ galaxy_dir }}/ansible_collections"
+ loop:
+ - absent
+ - directory
+
+- name: install a parent collection and a particular version of its dependency
+ command: ansible-galaxy collection install parent_dep.parent_collection:1.0.0 child_dep.child_collection:0.5.0 {{ galaxy_verbosity }}
+ register: result
+ failed_when:
+ - '"parent_dep.parent_collection:1.0.0 was installed successfully" not in result.stdout_lines'
+ - '"child_dep.child_collection:0.5.0 was installed successfully" not in result.stdout_lines'
+
+- name: upgrade the parent and child - the child's new version has a dependency that should be installed
+ command: ansible-galaxy collection install parent_dep.parent_collection -U {{ galaxy_verbosity }}
+ register: result
+
+- name: check the MANIFEST.json to verify the versions
+ slurp:
+ path: '{{ galaxy_dir }}/ansible_collections/{{ item.namespace }}/{{ item.name }}/MANIFEST.json'
+ register: metadata
+ loop:
+ - namespace: parent_dep
+ name: parent_collection
+ - namespace: child_dep
+ name: child_collection
+ - namespace: child_dep
+ name: child_dep2
+
+- assert:
+ that:
+ - '"parent_dep.parent_collection:2.0.0 was installed successfully" in result.stdout_lines'
+ - (metadata.results[0].content | b64decode | from_json).collection_info.version == '2.0.0'
+ - '"child_dep.child_collection:1.0.0 was installed successfully" in result.stdout_lines'
+ - (metadata.results[1].content | b64decode | from_json).collection_info.version == '1.0.0'
+ - '"child_dep.child_dep2:1.2.2 was installed successfully" in result.stdout_lines'
+ - (metadata.results[2].content | b64decode | from_json).collection_info.version == '1.2.2'
+
+# Test using a requirements.yml file for upgrade
+
+- name: reset installation directory
+ file:
+ state: "{{ item }}"
+ path: "{{ galaxy_dir }}/ansible_collections"
+ loop:
+ - absent
+ - directory
+
+- name: install upgradeable collections
+ command: ansible-galaxy collection install namespace1.name1:1.0.0 parent_dep.parent_collection:0.0.1 {{ galaxy_verbosity }}
+ register: result
+ failed_when:
+ - '"namespace1.name1:1.0.0 was installed successfully" not in result.stdout_lines'
+ - '"parent_dep.parent_collection:0.0.1 was installed successfully" not in result.stdout_lines'
+ - '"child_dep.child_collection:0.4.0 was installed successfully" not in result.stdout_lines'
+
+- name: create test requirements file with both roles and collections - {{ test_name }}
+ copy:
+ content: |
+ collections:
+ - namespace1.name1
+ - name: parent_dep.parent_collection
+ version: <=2.0.0
+ roles:
+ - skip.me
+ dest: '{{ galaxy_dir }}/ansible_collections/requirements.yml'
+
+- name: upgrade collections with the requirements.yml
+ command: ansible-galaxy collection install -r {{ requirements_path }} --upgrade {{ galaxy_verbosity }}
+ vars:
+ requirements_path: '{{ galaxy_dir }}/ansible_collections/requirements.yml'
+ register: result
+
+- assert:
+ that:
+ - '"namespace1.name1:1.0.9 was installed successfully" in result.stdout_lines'
+ - '"parent_dep.parent_collection:2.0.0 was installed successfully" in result.stdout_lines'
+ - '"child_dep.child_collection:1.0.0 was installed successfully" in result.stdout_lines'
+ - '"child_dep.child_dep2:1.2.2 was installed successfully" in result.stdout_lines'
+
+- name: cleanup
+ file:
+ state: "{{ item }}"
+ path: "{{ galaxy_dir }}/ansible_collections"
+ loop:
+ - absent
+ - directory
diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/verify.yml b/test/integration/targets/ansible-galaxy-collection/tasks/verify.yml
new file mode 100644
index 0000000..dfe3d0f
--- /dev/null
+++ b/test/integration/targets/ansible-galaxy-collection/tasks/verify.yml
@@ -0,0 +1,475 @@
+- name: create an empty collection skeleton
+ command: ansible-galaxy collection init ansible_test.verify
+ args:
+ chdir: '{{ galaxy_dir }}/scratch'
+
+- name: build the collection
+ command: ansible-galaxy collection build scratch/ansible_test/verify
+ args:
+ chdir: '{{ galaxy_dir }}'
+
+- name: publish collection - {{ test_name }}
+ command: ansible-galaxy collection publish ansible_test-verify-1.0.0.tar.gz -s {{ test_name }} {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}'
+
+- name: test verifying a tarfile
+ command: ansible-galaxy collection verify {{ galaxy_dir }}/ansible_test-verify-1.0.0.tar.gz
+ register: verify
+ failed_when: verify.rc == 0
+
+- assert:
+ that:
+ - verify.rc != 0
+ - >-
+ "ERROR! 'file' type is not supported. The format namespace.name is expected." in verify.stderr
+
+- name: install the collection from the server
+ command: ansible-galaxy collection install ansible_test.verify:1.0.0 -s {{ test_api_fallback }} {{ galaxy_verbosity }}
+
+# This command is hardcoded with -vvvv purposefully to evaluate extra verbosity messages
+- name: verify the collection against the first valid server
+ command: ansible-galaxy collection verify ansible_test.verify:1.0.0 -vvvv {{ galaxy_verbosity }}
+ register: verify
+
+- assert:
+ that:
+ - verify is success
+ - >-
+ "Found API version '{{ test_api_fallback_versions }}' with Galaxy server {{ test_api_fallback }}" in verify.stdout
+
+- name: verify the installed collection against the server
+ command: ansible-galaxy collection verify ansible_test.verify:1.0.0 -s {{ test_name }} {{ galaxy_verbosity }}
+ register: verify
+
+- assert:
+ that:
+ - verify is success
+ - "'Collection ansible_test.verify contains modified content' not in verify.stdout"
+
+- name: verify the installed collection against the server, with unspecified version in CLI
+ command: ansible-galaxy collection verify ansible_test.verify -s {{ test_name }} {{ galaxy_verbosity }}
+
+- name: verify a collection that doesn't appear to be installed
+ command: ansible-galaxy collection verify ansible_test.verify:1.0.0 -s {{ test_name }} {{ galaxy_verbosity }}
+ environment:
+ ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/nonexistent_dir'
+ register: verify
+ failed_when: verify.rc == 0
+
+- assert:
+ that:
+ - verify.rc != 0
+ - "'Collection ansible_test.verify is not installed in any of the collection paths.' in verify.stderr"
+
+- name: create a modules directory
+ file:
+ state: directory
+ path: '{{ galaxy_dir }}/scratch/ansible_test/verify/plugins/modules'
+
+- name: add a module to the collection
+ copy:
+ src: test_module.py
+ dest: '{{ galaxy_dir }}/scratch/ansible_test/verify/plugins/modules/test_module.py'
+
+- name: update the collection version
+ lineinfile:
+ regexp: "version: .*"
+ line: "version: '2.0.0'"
+ path: '{{ galaxy_dir }}/scratch/ansible_test/verify/galaxy.yml'
+
+- name: build the new version
+ command: ansible-galaxy collection build scratch/ansible_test/verify
+ args:
+ chdir: '{{ galaxy_dir }}'
+
+- name: publish the new version
+ command: ansible-galaxy collection publish ansible_test-verify-2.0.0.tar.gz -s {{ test_name }} {{ galaxy_verbosity }}
+ args:
+ chdir: '{{ galaxy_dir }}'
+
+- name: verify a version of a collection that isn't installed
+ command: ansible-galaxy collection verify ansible_test.verify:2.0.0 -s {{ test_name }} {{ galaxy_verbosity }}
+ register: verify
+ failed_when: verify.rc == 0
+
+- assert:
+ that:
+ - verify.rc != 0
+ - '"ansible_test.verify has the version ''1.0.0'' but is being compared to ''2.0.0''" in verify.stdout'
+
+- name: install the new version from the server
+ command: ansible-galaxy collection install ansible_test.verify:2.0.0 --force -s {{ test_name }} {{ galaxy_verbosity }}
+
+- name: verify the installed collection against the server
+ command: ansible-galaxy collection verify ansible_test.verify:2.0.0 -s {{ test_name }} {{ galaxy_verbosity }}
+ register: verify
+
+- assert:
+ that:
+ - "'Collection ansible_test.verify contains modified content' not in verify.stdout"
+
+# Test a modified collection
+
+- set_fact:
+ manifest_path: '{{ galaxy_dir }}/ansible_collections/ansible_test/verify/MANIFEST.json'
+ file_manifest_path: '{{ galaxy_dir }}/ansible_collections/ansible_test/verify/FILES.json'
+ module_path: '{{ galaxy_dir }}/ansible_collections/ansible_test/verify/plugins/modules/test_module.py'
+
+- name: load the FILES.json
+ set_fact:
+ files_manifest: "{{ lookup('file', file_manifest_path) | from_json }}"
+
+- name: get the real checksum of a particular module
+ stat:
+ path: "{{ module_path }}"
+ checksum_algorithm: sha256
+ register: file
+
+- assert:
+ that:
+ - "file.stat.checksum == item.chksum_sha256"
+ loop: "{{ files_manifest.files }}"
+ when: "item.name == 'plugins/modules/aws_s3.py'"
+
+- name: append a newline to the module to modify the checksum
+ shell: "echo '' >> {{ module_path }}"
+
+- name: get the new checksum
+ stat:
+ path: "{{ module_path }}"
+ checksum_algorithm: sha256
+ register: updated_file
+
+- assert:
+ that:
+ - "updated_file.stat.checksum != file.stat.checksum"
+
+- name: test verifying checksumes of the modified collection
+ command: ansible-galaxy collection verify ansible_test.verify:2.0.0 -s {{ test_name }} {{ galaxy_verbosity }}
+ register: verify
+ failed_when: verify.rc == 0
+
+- assert:
+ that:
+ - verify.rc != 0
+ - "'Collection ansible_test.verify contains modified content in the following files:\n plugins/modules/test_module.py' in verify.stdout"
+
+- name: modify the FILES.json to match the new checksum
+ lineinfile:
+ path: "{{ file_manifest_path }}"
+ regexp: ' "chksum_sha256": "{{ file.stat.checksum }}",'
+ line: ' "chksum_sha256": "{{ updated_file.stat.checksum }}",'
+ state: present
+ diff: true
+
+- name: ensure a modified FILES.json is validated
+ command: ansible-galaxy collection verify ansible_test.verify:2.0.0 -s {{ test_name }} {{ galaxy_verbosity }}
+ register: verify
+ failed_when: verify.rc == 0
+
+- assert:
+ that:
+ - verify.rc != 0
+ - "'Collection ansible_test.verify contains modified content in the following files:\n FILES.json' in verify.stdout"
+
+- name: get the checksum of the FILES.json
+ stat:
+ path: "{{ file_manifest_path }}"
+ checksum_algorithm: sha256
+ register: manifest_info
+
+- name: modify the MANIFEST.json to contain a different checksum for FILES.json
+ lineinfile:
+ regexp: ' "chksum_sha256": *'
+ path: "{{ manifest_path }}"
+ line: ' "chksum_sha256": "{{ manifest_info.stat.checksum }}",'
+
+- name: ensure the MANIFEST.json is validated against the uncorrupted file from the server
+ command: ansible-galaxy collection verify ansible_test.verify:2.0.0 -s {{ test_name }} {{ galaxy_verbosity }}
+ register: verify
+ failed_when: verify.rc == 0
+
+- assert:
+ that:
+ - verify.rc != 0
+ - "'Collection ansible_test.verify contains modified content in the following files:\n MANIFEST.json' in verify.stdout"
+
+- name: remove the artifact metadata to test verifying a collection without it
+ file:
+ path: "{{ item }}"
+ state: absent
+ loop:
+ - "{{ manifest_path }}"
+ - "{{ file_manifest_path }}"
+
+- name: add some development metadata
+ copy:
+ content: |
+ namespace: 'ansible_test'
+ name: 'verify'
+ version: '2.0.0'
+ readme: 'README.md'
+ authors: ['Ansible']
+ dest: '{{ galaxy_dir }}/ansible_collections/ansible_test/verify/galaxy.yml'
+
+- name: test we only verify collections containing a MANIFEST.json with the version on the server
+ command: ansible-galaxy collection verify ansible_test.verify:2.0.0 -s {{ test_name }} {{ galaxy_verbosity }}
+ register: verify
+ failed_when: verify.rc == 0
+
+- assert:
+ that:
+ - verify.rc != 0
+ - "'Collection ansible_test.verify does not have a MANIFEST.json' in verify.stderr"
+
+- name: update the collection version to something not present on the server
+ lineinfile:
+ regexp: "version: .*"
+ line: "version: '3.0.0'"
+ path: '{{ galaxy_dir }}/scratch/ansible_test/verify/galaxy.yml'
+
+- name: build the new version
+ command: ansible-galaxy collection build scratch/ansible_test/verify
+ args:
+ chdir: '{{ galaxy_dir }}'
+
+- name: force-install from local artifact
+ command: ansible-galaxy collection install '{{ galaxy_dir }}/ansible_test-verify-3.0.0.tar.gz' --force
+
+- name: verify locally only, no download or server manifest hash check
+ command: ansible-galaxy collection verify --offline ansible_test.verify
+ register: verify
+
+- assert:
+ that:
+ - >-
+ "Verifying 'ansible_test.verify:3.0.0'." in verify.stdout
+ - '"MANIFEST.json hash: " in verify.stdout'
+ - >-
+ "Successfully verified that checksums for 'ansible_test.verify:3.0.0' are internally consistent with its manifest." in verify.stdout
+
+- name: append a newline to a module to modify the checksum
+ shell: "echo '' >> {{ module_path }}"
+
+- name: create a new module file
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/ansible_test/verify/plugins/modules/test_new_file.py'
+ state: touch
+
+- name: create a new directory
+ file:
+ path: '{{ galaxy_dir }}/ansible_collections/ansible_test/verify/plugins/modules/test_new_dir'
+ state: directory
+
+- name: verify modified collection locally-only (should fail)
+ command: ansible-galaxy collection verify --offline ansible_test.verify
+ register: verify
+ failed_when: verify.rc == 0
+
+- assert:
+ that:
+ - verify.rc != 0
+ - "'Collection ansible_test.verify contains modified content in the following files:' in verify.stdout"
+ - "'plugins/modules/test_module.py' in verify.stdout"
+ - "'plugins/modules/test_new_file.py' in verify.stdout"
+ - "'plugins/modules/test_new_dir' in verify.stdout"
+
+# TODO: add a test for offline Galaxy signature metadata
+
+- name: install a collection that was signed by setup_collections
+ command: ansible-galaxy collection install namespace1.name1:1.0.0
+
+- name: verify the installed collection with a detached signature
+ command: ansible-galaxy collection verify namespace1.name1:1.0.0 {{ galaxy_verbosity }} {{ signature_options }}
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }}"
+ signature: "file://{{ gpg_homedir }}/namespace1-name1-1.0.0-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ register: verify
+
+- assert:
+ that:
+ - verify.rc == 0
+
+# This command is hardcoded with -vvvv purposefully to evaluate extra verbosity messages
+- name: verify the installed collection with invalid detached signature
+ command: ansible-galaxy collection verify namespace1.name1:1.0.0 -vvvv {{ signature_options }}
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }}"
+ signature: "file://{{ gpg_homedir }}/namespace1-name1-1.0.9-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ register: verify
+ ignore_errors: yes
+ environment:
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- assert:
+ that:
+ - verify.rc != 0
+ - '"Signature verification failed for ''namespace1.name1'' (return code 1)" in verify.stdout'
+ - expected_errors[0] in verify_stdout
+ - expected_errors[1] in verify_stdout
+ vars:
+ expected_errors:
+ - "* This is the counterpart to SUCCESS and used to indicate a program failure."
+ - "* The signature with the keyid has not been verified okay."
+ # Remove formatting from the reason so it's one line
+ verify_stdout: "{{ verify.stdout | regex_replace('\"') | regex_replace('\\n') | regex_replace(' ', ' ') }}"
+
+# This command is hardcoded with -vvvv purposefully to evaluate extra verbosity messages
+- name: verify the installed collection with invalid detached signature offline
+ command: ansible-galaxy collection verify namespace1.name1:1.0.0 -vvvv {{ signature_options }} --offline
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }}"
+ signature: "file://{{ gpg_homedir }}/namespace1-name1-1.0.9-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ register: verify
+ ignore_errors: yes
+ environment:
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- assert:
+ that:
+ - verify.rc != 0
+ - '"Signature verification failed for ''namespace1.name1'' (return code 1)" in verify.stdout'
+ - expected_errors[0] in verify_stdout
+ - expected_errors[1] in verify_stdout
+ vars:
+ expected_errors:
+ - "* This is the counterpart to SUCCESS and used to indicate a program failure."
+ - "* The signature with the keyid has not been verified okay."
+ # Remove formatting from the reason so it's one line
+ verify_stdout: "{{ verify.stdout | regex_replace('\"') | regex_replace('\\n') | regex_replace(' ', ' ') }}"
+
+- include_tasks: revoke_gpg_key.yml
+
+# This command is hardcoded with -vvvv purposefully to evaluate extra verbosity messages
+- name: verify the installed collection with a revoked detached signature
+ command: ansible-galaxy collection verify namespace1.name1:1.0.0 -vvvv {{ signature_options }}
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }}"
+ signature: "file://{{ gpg_homedir }}/namespace1-name1-1.0.0-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ register: verify
+ ignore_errors: yes
+ environment:
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- assert:
+ that:
+ - verify.rc != 0
+ - '"Signature verification failed for ''namespace1.name1'' (return code 0)" in verify.stdout'
+ - expected_errors[0] in verify_stdout
+ - expected_errors[1] in verify_stdout
+ vars:
+ expected_errors:
+ - "* The used key has been revoked by its owner."
+ - "* The signature with the keyid is good, but the signature was made by a revoked key."
+ # Remove formatting from the reason so it's one line
+ verify_stdout: "{{ verify.stdout | regex_replace('\"') | regex_replace('\\n') | regex_replace(' ', ' ') }}"
+
+# This command is hardcoded with no verbosity purposefully to evaluate overall gpg failure
+- name: verify that ignoring the signature error and no successful signatures is not successful verification
+ command: ansible-galaxy collection verify namespace1.name1:1.0.0 {{ signature_options }}
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }}"
+ signature: "file://{{ gpg_homedir }}/namespace1-name1-1.0.0-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ register: verify
+ ignore_errors: yes
+ environment:
+ ANSIBLE_GALAXY_IGNORE_SIGNATURE_STATUS_CODES: REVKEYSIG,KEYREVOKED
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- assert:
+ that:
+ - verify.rc != 0
+ - '"Signature verification failed for ''namespace1.name1'': fewer successful signatures than required" in verify.stdout'
+ - ignored_errors[0] not in verify_stdout
+ - ignored_errors[1] not in verify_stdout
+ vars:
+ ignored_errors:
+ - "* The used key has been revoked by its owner."
+ - "* The signature with the keyid is good, but the signature was made by a revoked key."
+ # Remove formatting from the reason so it's one line
+ verify_stdout: "{{ verify.stdout | regex_replace('\"') | regex_replace('\\n') | regex_replace(' ', ' ') }}"
+
+# This command is hardcoded with -vvvv purposefully to evaluate extra verbosity messages
+- name: verify that ignoring the signature error and no successful signatures and required signature count all is successful verification
+ command: ansible-galaxy collection verify namespace1.name1:1.0.0 -vvvv {{ signature_options }}
+ vars:
+ signature_options: "--signature {{ signature }} --keyring {{ keyring }}"
+ signature: "file://{{ gpg_homedir }}/namespace1-name1-1.0.0-MANIFEST.json.asc"
+ keyring: "{{ gpg_homedir }}/pubring.kbx"
+ register: verify
+ ignore_errors: yes
+ environment:
+ ANSIBLE_GALAXY_IGNORE_SIGNATURE_STATUS_CODES: REVKEYSIG,KEYREVOKED
+ ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: all
+ ANSIBLE_NOCOLOR: True
+ ANSIBLE_FORCE_COLOR: False
+
+- assert:
+ that:
+ - verify is success
+ - verify.rc == 0
+ - '"Signature verification failed for ''namespace1.name1'': fewer successful signatures than required" not in verify.stdout'
+ - success_messages[0] in verify_stdout
+ - success_messages[1] in verify_stdout
+ - ignored_errors[0] not in verify_stdout
+ - ignored_errors[1] not in verify_stdout
+ vars:
+ success_messages:
+ - "GnuPG signature verification succeeded, verifying contents of namespace1.name1:1.0.0"
+ - "Successfully verified that checksums for 'namespace1.name1:1.0.0' match the remote collection."
+ ignored_errors:
+ - "* The used key has been revoked by its owner."
+ - "* The signature with the keyid is good, but the signature was made by a revoked key."
+ # Remove formatting from the reason so it's one line
+ verify_stdout: "{{ verify.stdout | regex_replace('\"') | regex_replace('\\n') | regex_replace(' ', ' ') }}"
+
+- name: use lenient signature verification (default) without providing signatures
+ command: ansible-galaxy collection verify namespace1.name1:1.0.0 -vvvv --keyring {{ gpg_homedir }}/pubring.kbx
+ environment:
+ ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: "1"
+ register: verify
+ ignore_errors: yes
+
+- assert:
+ that:
+ - verify is success
+ - verify.rc == 0
+ - error_message not in verify.stdout
+ - success_messages[0] in verify.stdout
+ - success_messages[1] in verify.stdout
+ vars:
+ error_message: "Signature verification failed for 'namespace1.name1': fewer successful signatures than required"
+ success_messages:
+ - "GnuPG signature verification succeeded, verifying contents of namespace1.name1:1.0.0"
+ - "Successfully verified that checksums for 'namespace1.name1:1.0.0' match the remote collection."
+
+- name: use strict signature verification without providing signatures
+ command: ansible-galaxy collection verify namespace1.name1:1.0.0 -vvvv --keyring {{ gpg_homedir }}/pubring.kbx
+ environment:
+ ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: "+1"
+ register: verify
+ ignore_errors: yes
+
+- assert:
+ that:
+ - verify is failed
+ - verify.rc == 1
+ - '"Signature verification failed for ''namespace1.name1'': no successful signatures" in verify.stdout'
+
+- name: empty installed collections
+ file:
+ path: "{{ galaxy_dir }}/ansible_collections"
+ state: "{{ item }}"
+ loop:
+ - absent
+ - directory