Fourth batch of incidental integration tests. (#67873)

* Copy in incidental posix tests.

* Update incidental test aliases.

* Update target names.

* Add support plugins.

* Fix paths.

* Update ignores.

* Update integration-aliases sanity test.

* Add incidental tests to CI.
pull/67878/head
Matt Clay 4 years ago committed by GitHub
parent 04666c9fa1
commit 7c8b046b5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -158,6 +158,22 @@ matrix:
- env: T=linux/ubuntu1604/5
- env: T=linux/ubuntu1804/5
- env: T=i/aix/7.2
- env: T=i/osx/10.11
- env: T=i/rhel/7.6
- env: T=i/rhel/8.1
- env: T=i/freebsd/11.1
- env: T=i/freebsd/12.1
- env: T=i/linux/centos6
- env: T=i/linux/centos7
- env: T=i/linux/centos8
- env: T=i/linux/fedora30
- env: T=i/linux/fedora31
- env: T=i/linux/opensuse15py2
- env: T=i/linux/opensuse15
- env: T=i/linux/ubuntu1604
- env: T=i/linux/ubuntu1804
- env: T=aws/2.7/1
- env: T=aws/3.6/1

@ -0,0 +1,101 @@
# test code for the assemble module
# (c) 2014, James Cammarata <jcammarata@ansible.com>
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
- name: create a new directory for file source
file: dest="{{output_dir}}/src" state=directory
register: result
- name: assert the directory was created
assert:
that:
- "result.state == 'directory'"
- name: copy the files to a new directory
copy: src="./" dest="{{output_dir}}/src"
register: result
- name: create unicode file for test
shell: echo "π" > {{ output_dir }}/src/ßΩ.txt
register: result
- name: assert that the new file was created
assert:
that:
- "result.changed == true"
- name: test assemble with all fragments
assemble: src="{{output_dir}}/src" dest="{{output_dir}}/assembled1"
register: result
- name: assert the fragments were assembled
assert:
that:
- "result.state == 'file'"
- "result.changed == True"
- "result.checksum == '74152e9224f774191bc0bedf460d35de86ad90e6'"
- name: test assemble with all fragments
assemble: src="{{output_dir}}/src" dest="{{output_dir}}/assembled1"
register: result
- name: assert that the same assemble made no changes
assert:
that:
- "result.state == 'file'"
- "result.changed == False"
- "result.checksum == '74152e9224f774191bc0bedf460d35de86ad90e6'"
- name: test assemble with fragments matching a regex
assemble: src="{{output_dir}}/src" dest="{{output_dir}}/assembled2" regexp="^fragment[1-3]$"
register: result
- name: assert the fragments were assembled with a regex
assert:
that:
- "result.state == 'file'"
- "result.checksum == 'edfe2d7487ef8f5ebc0f1c4dc57ba7b70a7b8e2b'"
- name: test assemble with a delimiter
assemble: src="{{output_dir}}/src" dest="{{output_dir}}/assembled3" delimiter="#--- delimiter ---#"
register: result
- name: assert the fragments were assembled with a delimiter
assert:
that:
- "result.state == 'file'"
- "result.checksum == 'd986cefb82e34e4cf14d33a3cda132ff45aa2980'"
- name: test assemble with remote_src=False
assemble: src="./" dest="{{output_dir}}/assembled4" remote_src=no
register: result
- name: assert the fragments were assembled without remote
assert:
that:
- "result.state == 'file'"
- "result.checksum == '048a1bd1951aa5ccc427eeb4ca19aee45e9c68b3'"
- name: test assemble with remote_src=False and a delimiter
assemble: src="./" dest="{{output_dir}}/assembled5" remote_src=no delimiter="#--- delimiter ---#"
register: result
- name: assert the fragments were assembled without remote
assert:
that:
- "result.state == 'file'"
- "result.checksum == '505359f48c65b3904127cf62b912991d4da7ed6d'"

@ -0,0 +1,5 @@
destructive
shippable/posix/incidental
skip/aix
skip/osx
skip/freebsd

@ -0,0 +1,50 @@
---
- name: test cloud-init
# TODO: check for a workaround
# install 'cloud-init'' failed: dpkg-divert: error: `diversion of /etc/init/ureadahead.conf
# to /etc/init/ureadahead.conf.disabled by cloud-init' clashes with `local diversion of
# /etc/init/ureadahead.conf to /etc/init/ureadahead.conf.distrib
# https://bugs.launchpad.net/ubuntu/+source/ureadahead/+bug/997838
# Will also have to skip on OpenSUSE when running on Python 2 on newer Leap versions
# (!= 42 and >= 15) ascloud-init will install the Python 3 package, breaking our build on py2.
when:
- not (ansible_distribution == "Ubuntu" and ansible_distribution_major_version|int == 14)
- not (ansible_os_family == "Suse" and ansible_distribution_major_version|int != 42 and ansible_python.version.major != 3)
block:
- name: setup install cloud-init
package:
name:
- cloud-init
- udev
- name: setup run cloud-init
service:
name: cloud-init-local
state: restarted
- name: test gather cloud-init facts in check mode
cloud_init_data_facts:
check_mode: yes
register: result
- name: verify test gather cloud-init facts in check mode
assert:
that:
- result.cloud_init_data_facts.status.v1 is defined
- result.cloud_init_data_facts.status.v1.stage is defined
- not result.cloud_init_data_facts.status.v1.stage
- cloud_init_data_facts.status.v1 is defined
- cloud_init_data_facts.status.v1.stage is defined
- not cloud_init_data_facts.status.v1.stage
- name: test gather cloud-init facts
cloud_init_data_facts:
register: result
- name: verify test gather cloud-init facts
assert:
that:
- result.cloud_init_data_facts.status.v1 is defined
- result.cloud_init_data_facts.status.v1.stage is defined
- not result.cloud_init_data_facts.status.v1.stage
- cloud_init_data_facts.status.v1 is defined
- cloud_init_data_facts.status.v1.stage is defined
- not cloud_init_data_facts.status.v1.stage

@ -0,0 +1,3 @@
needs/root
shippable/posix/incidental
needs/target/connection

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -eux
# Connection tests for POSIX platforms use this script by linking to it from the appropriate 'connection_' target dir.
# The name of the inventory group to test is extracted from the directory name following the 'connection_' prefix.
group=$(python -c \
"from os import path; print(path.basename(path.abspath(path.dirname('$0'))).replace('incidental_connection_', ''))")
cd ../connection
INVENTORY="../incidental_connection_${group}/test_connection.inventory" ./test.sh \
-e target_hosts="${group}" \
-e action_prefix= \
-e local_tmp=/tmp/ansible-local \
-e remote_tmp=/tmp/ansible-remote \
"$@"

@ -0,0 +1,7 @@
[chroot]
chroot-pipelining ansible_ssh_pipelining=true
chroot-no-pipelining ansible_ssh_pipelining=false
[chroot:vars]
ansible_host=/
ansible_connection=chroot
ansible_python_interpreter="{{ ansible_playbook_python }}"

@ -0,0 +1,3 @@
shippable/posix/incidental
destructive
skip/aix

@ -0,0 +1,3 @@
---
dependencies:
- incidental_setup_openssl

@ -0,0 +1,162 @@
- name: list sessions
consul_session:
state: list
register: result
- assert:
that:
- result is changed
- "'sessions' in result"
- name: create a session
consul_session:
state: present
name: testsession
register: result
- assert:
that:
- result is changed
- result['name'] == 'testsession'
- "'session_id' in result"
- set_fact:
session_id: "{{ result['session_id'] }}"
- name: list sessions after creation
consul_session:
state: list
register: result
- set_fact:
session_count: "{{ result['sessions'] | length }}"
- assert:
that:
- result is changed
# selectattr not available on Jinja 2.2 provided by CentOS 6
# hence the two following tasks (set_fact/assert) are used
# - (result['sessions'] | selectattr('ID', 'match', '^' ~ session_id ~ '$') | first)['Name'] == 'testsession'
- name: search created session
set_fact:
test_session_found: True
loop: "{{ result['sessions'] }}"
when: "item.get('ID') == session_id and item.get('Name') == 'testsession'"
- name: ensure session was created
assert:
that:
- test_session_found|default(False)
- name: fetch info about a session
consul_session:
state: info
id: '{{ session_id }}'
register: result
- assert:
that:
- result is changed
- name: ensure 'id' parameter is required when state=info
consul_session:
state: info
name: test
register: result
ignore_errors: True
- assert:
that:
- result is failed
- name: ensure unknown scheme fails
consul_session:
state: info
id: '{{ session_id }}'
scheme: non_existent
register: result
ignore_errors: True
- assert:
that:
- result is failed
- when: pyopenssl_version.stdout is version('0.15', '>=')
block:
- name: ensure SSL certificate is checked
consul_session:
state: info
id: '{{ session_id }}'
port: 8501
scheme: https
register: result
ignore_errors: True
- name: previous task should fail since certificate is not known
assert:
that:
- result is failed
- "'certificate verify failed' in result.msg"
- name: ensure SSL certificate isn't checked when validate_certs is disabled
consul_session:
state: info
id: '{{ session_id }}'
port: 8501
scheme: https
validate_certs: False
register: result
- name: previous task should succeed since certificate isn't checked
assert:
that:
- result is changed
- name: ensure a secure connection is possible
consul_session:
state: info
id: '{{ session_id }}'
port: 8501
scheme: https
environment:
REQUESTS_CA_BUNDLE: '{{ remote_dir }}/cert.pem'
register: result
- assert:
that:
- result is changed
- name: delete a session
consul_session:
state: absent
id: '{{ session_id }}'
register: result
- assert:
that:
- result is changed
- name: list sessions after deletion
consul_session:
state: list
register: result
- assert:
that:
- result is changed
# selectattr and equalto not available on Jinja 2.2 provided by CentOS 6
# hence the two following tasks (command/assert) are used
# - (result['sessions'] | selectattr('ID', 'equalto', session_id) | list | length) == 0
- name: search deleted session
command: echo 'session found'
loop: "{{ result['sessions'] }}"
when: "item.get('ID') == session_id and item.get('Name') == 'testsession'"
register: search_deleted
- name: ensure session was deleted
assert:
that:
- search_deleted is skipped # each iteration is skipped
- search_deleted is not changed # and then unchanged

@ -0,0 +1,97 @@
---
- name: Install Consul and test
vars:
consul_version: '1.5.0'
consul_uri: https://s3.amazonaws.com/ansible-ci-files/test/integration/targets/consul/consul_{{ consul_version }}_{{ ansible_system | lower }}_{{ consul_arch }}.zip
consul_cmd: '{{ output_dir }}/consul'
block:
- name: register pyOpenSSL version
command: "{{ ansible_python_interpreter }} -c 'import OpenSSL; print(OpenSSL.__version__)'"
register: pyopenssl_version
- name: Install requests<2.20 (CentOS/RHEL 6)
pip:
name: requests<2.20
register: result
until: result is success
when: ansible_distribution_file_variety|default() == 'RedHat' and ansible_distribution_major_version is version('6', '<=')
- name: Install python-consul
pip:
name: python-consul
register: result
until: result is success
- when: pyopenssl_version.stdout is version('0.15', '>=')
block:
- name: Generate privatekey
openssl_privatekey:
path: '{{ output_dir }}/privatekey.pem'
- name: Generate CSR
openssl_csr:
path: '{{ output_dir }}/csr.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
subject:
commonName: localhost
- name: Generate selfsigned certificate
openssl_certificate:
path: '{{ output_dir }}/cert.pem'
csr_path: '{{ output_dir }}/csr.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
provider: selfsigned
selfsigned_digest: sha256
register: selfsigned_certificate
- name: 'Install unzip'
package:
name: unzip
register: result
until: result is success
when: ansible_distribution != "MacOSX" # unzip already installed
- assert:
# Linux: x86_64, FreeBSD: amd64
that: ansible_architecture in ['i386', 'x86_64', 'amd64']
- set_fact:
consul_arch: '386'
when: ansible_architecture == 'i386'
- set_fact:
consul_arch: amd64
when: ansible_architecture in ['x86_64', 'amd64']
- name: 'Download consul binary'
unarchive:
src: '{{ consul_uri }}'
dest: '{{ output_dir }}'
remote_src: true
register: result
until: result is success
- vars:
remote_dir: '{{ echo_output_dir.stdout }}'
block:
- command: 'echo {{ output_dir }}'
register: echo_output_dir
- name: 'Create configuration file'
template:
src: consul_config.hcl.j2
dest: '{{ output_dir }}/consul_config.hcl'
- name: 'Start Consul (dev mode enabled)'
shell: 'nohup {{ consul_cmd }} agent -dev -config-file {{ output_dir }}/consul_config.hcl </dev/null >/dev/null 2>&1 &'
- name: 'Create some data'
command: '{{ consul_cmd }} kv put data/value{{ item }} foo{{ item }}'
loop: [1, 2, 3]
- import_tasks: consul_session.yml
always:
- name: 'Kill consul process'
shell: "kill $(cat {{ output_dir }}/consul.pid)"
ignore_errors: true

@ -0,0 +1,13 @@
# {{ ansible_managed }}
server = true
pid_file = "{{ remote_dir }}/consul.pid"
ports {
http = 8500
{% if pyopenssl_version.stdout is version('0.15', '>=') %}
https = 8501
{% endif %}
}
{% if pyopenssl_version.stdout is version('0.15', '>=') %}
key_file = "{{ remote_dir }}/privatekey.pem"
cert_file = "{{ remote_dir }}/cert.pem"
{% endif %}

@ -0,0 +1,149 @@
---
- name: record the output directory
set_fact: deploy_helper_test_root={{output_dir}}/deploy_helper_test_root
- name: State=query with default parameters
deploy_helper: path={{ deploy_helper_test_root }} state=query
- name: Assert State=query with default parameters
assert:
that:
- "'project_path' in deploy_helper"
- "deploy_helper.current_path == '{{ deploy_helper.project_path }}/current'"
- "deploy_helper.releases_path == '{{ deploy_helper.project_path }}/releases'"
- "deploy_helper.shared_path == '{{ deploy_helper.project_path }}/shared'"
- "deploy_helper.unfinished_filename == 'DEPLOY_UNFINISHED'"
- "'previous_release' in deploy_helper"
- "'previous_release_path' in deploy_helper"
- "'new_release' in deploy_helper"
- "'new_release_path' in deploy_helper"
- "deploy_helper.new_release_path == '{{ deploy_helper.releases_path }}/{{ deploy_helper.new_release }}'"
- name: State=query with relative overridden paths
deploy_helper: path={{ deploy_helper_test_root }} current_path=CURRENT_PATH releases_path=RELEASES_PATH shared_path=SHARED_PATH state=query
- name: Assert State=query with relative overridden paths
assert:
that:
- "deploy_helper.current_path == '{{ deploy_helper.project_path }}/CURRENT_PATH'"
- "deploy_helper.releases_path == '{{ deploy_helper.project_path }}/RELEASES_PATH'"
- "deploy_helper.shared_path == '{{ deploy_helper.project_path }}/SHARED_PATH'"
- "deploy_helper.new_release_path == '{{ deploy_helper.releases_path }}/{{ deploy_helper.new_release}}'"
- name: State=query with absolute overridden paths
deploy_helper: path={{ deploy_helper_test_root }} current_path=/CURRENT_PATH releases_path=/RELEASES_PATH shared_path=/SHARED_PATH state=query
- name: Assert State=query with absolute overridden paths
assert:
that:
- "deploy_helper.current_path == '/CURRENT_PATH'"
- "deploy_helper.releases_path == '/RELEASES_PATH'"
- "deploy_helper.shared_path == '/SHARED_PATH'"
- "deploy_helper.new_release_path == '{{ deploy_helper.releases_path }}/{{ deploy_helper.new_release}}'"
- name: State=query with overridden unfinished_filename
deploy_helper: path={{ deploy_helper_test_root }} unfinished_filename=UNFINISHED_DEPLOY state=query
- name: Assert State=query with overridden unfinished_filename
assert:
that:
- "'UNFINISHED_DEPLOY' == deploy_helper.unfinished_filename"
# Remove the root folder just in case it exists
- file: path={{ deploy_helper_test_root }} state=absent
- name: State=present with default parameters
deploy_helper: path={{ deploy_helper_test_root }} state=present
- stat: path={{ deploy_helper.releases_path }}
register: releases_path
- stat: path={{ deploy_helper.shared_path }}
register: shared_path
- name: Assert State=present with default parameters
assert:
that:
- "releases_path.stat.exists"
- "shared_path.stat.exists"
# Setup older releases for tests
- file: path={{ deploy_helper.releases_path }}/{{ item }} state=directory
with_items: ['first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh']
# Setup the new release
- file: path={{ deploy_helper.new_release_path }} state=directory
# Add a buildfile, just like in a real deploy
- copy: content='' dest={{ deploy_helper.new_release_path }}/{{ deploy_helper.unfinished_filename }}
# Add a buildfile, to an older deploy
- copy: content='' dest={{ deploy_helper.releases_path }}/third/{{ deploy_helper.unfinished_filename }}
- name: State=finalize with default parameters
deploy_helper: path={{ deploy_helper_test_root }} release={{ deploy_helper.new_release }} state=finalize
- stat: path={{ deploy_helper.current_path }}
register: current_path
- stat: path={{ deploy_helper.current_path }}/DEPLOY_UNFINISHED
register: current_path_unfinished_filename
- name: Assert State=finalize with default parameters
assert:
that:
- "current_path.stat.islnk"
- "deploy_helper.new_release_path in current_path.stat.lnk_source"
- "not current_path_unfinished_filename.stat.exists"
- stat: path={{ deploy_helper.releases_path }}/third
register: third_release_path
- shell: "ls {{ deploy_helper.releases_path }} | wc -l"
register: releases_count
- name: Assert State=finalize with default parameters (clean=true checks)
assert:
that:
- "not third_release_path.stat.exists"
- "releases_count.stdout|trim == '6'"
- deploy_helper: path={{ deploy_helper_test_root }} release={{ deploy_helper.new_release }} state=query
- name: Assert State=finalize with default parameters (previous_release checks)
assert:
that:
- "deploy_helper.new_release == deploy_helper.previous_release"
- name: State=absent with default parameters
deploy_helper: path={{ deploy_helper_test_root }} state=absent
- stat: path={{ deploy_helper_test_root }}
register: project_path
- name: Assert State=absent with default parameters
assert:
that:
- "not project_path.stat.exists"
- debug: msg="Clearing all release data and facts ---------"
- name: State=present with shared_path set to False
deploy_helper: path={{ deploy_helper_test_root }} state=present shared_path=''
- stat: path={{ deploy_helper.releases_path }}
register: releases_path
- stat: path={{ deploy_helper.shared_path }}
register: shared_path
- name: Assert State=present with shared_path set to False
assert:
that:
- "releases_path.stat.exists"
- "not shared_path.stat.exists"
# Setup older releases for tests
- file: path={{ deploy_helper.releases_path }}/{{ item }} state=directory
with_items: ['first', 'second', 'third', 'fourth', 'fifth']
# Setup the new release
- file: path={{ deploy_helper.new_release_path }} state=directory
# Add a buildfile, just like in a real deploy
- copy: content='' dest={{ deploy_helper.new_release_path }}/{{ deploy_helper.unfinished_filename }}
# Add a buildfile, to an older deploy
- copy: content='' dest={{ deploy_helper.releases_path }}/third/{{ deploy_helper.unfinished_filename }}
- shell: "ls {{ deploy_helper_test_root }}/releases | wc -l"
register: before_releases_count
- name: State=clean with keep_releases=3
deploy_helper: path={{ deploy_helper_test_root }} release={{ deploy_helper.new_release }} state=clean keep_releases=3
- stat: path={{ deploy_helper.releases_path }}/third
register: third_release_path
- shell: "ls {{ deploy_helper.releases_path }} | wc -l"
register: releases_count
- name: Assert State=finalize with default parameters (clean=true checks)
assert:
that:
- "not third_release_path.stat.exists"
- "before_releases_count.stdout|trim == '6'"
- "releases_count.stdout|trim == '3'"
# Remove the root folder
- file: path={{ deploy_helper_test_root }} state=absent

@ -0,0 +1,7 @@
shippable/posix/incidental
destructive
skip/aix
skip/freebsd
skip/osx
skip/rhel
needs/root

@ -0,0 +1,2 @@
dependencies:
- incidental_setup_flatpak_remote

@ -0,0 +1,101 @@
# - Tests with absent flatpak remote -------------------------------------------
# state=present
- name: Test addition of absent flatpak remote (check mode)
flatpak_remote:
name: flatpak-test
flatpakrepo_url: /tmp/flatpak/repo/dummy-repo.flatpakrepo
state: present
register: addition_result
check_mode: true
- name: Verify addition of absent flatpak remote test result (check mode)
assert:
that:
- "addition_result.changed == true"
msg: "Adding an absent flatpak remote shall mark module execution as changed"
- name: Test non-existent idempotency of addition of absent flatpak remote (check mode)
flatpak_remote:
name: flatpak-test
flatpakrepo_url: /tmp/flatpak/repo/dummy-repo.flatpakrepo
state: present
register: double_addition_result
check_mode: true
- name: >
Verify non-existent idempotency of addition of absent flatpak remote
test result (check mode)
assert:
that:
- "double_addition_result.changed == true"
msg: |
Adding an absent flatpak remote a second time shall still mark module execution
as changed in check mode
# state=absent
- name: Test removal of absent flatpak remote not doing anything in check mode
flatpak_remote:
name: flatpak-test
state: absent
register: removal_result
check_mode: true
- name: Verify removal of absent flatpak remote test result (check mode)
assert:
that:
- "removal_result.changed == false"
msg: "Removing an absent flatpak remote shall mark module execution as not changed"
# - Tests with present flatpak remote -------------------------------------------
# state=present
- name: Test addition of present flatpak remote (check mode)
flatpak_remote:
name: check-mode-test-remote
flatpakrepo_url: /tmp/flatpak/repo/dummy-repo.flatpakrepo
state: present
register: addition_result
check_mode: true
- name: Verify addition of present flatpak remote test result (check mode)
assert:
that:
- "addition_result.changed == false"
msg: "Adding a present flatpak remote shall mark module execution as not changed"
# state=absent
- name: Test removal of present flatpak remote not doing anything in check mode
flatpak_remote:
name: check-mode-test-remote
state: absent
register: removal_result
check_mode: true
- name: Verify removal of present flatpak remote test result (check mode)
assert:
that:
- "removal_result.changed == true"
msg: "Removing a present flatpak remote shall mark module execution as changed"
- name: Test non-existent idempotency of removal of present flatpak remote (check mode)
flatpak_remote:
name: check-mode-test-remote
state: absent
register: double_removal_result
check_mode: true
- name: >
Verify non-existent idempotency of removal of present flatpak remote
test result (check mode)
assert:
that:
- "double_removal_result.changed == true"
msg: |
Removing a present flatpak remote a second time shall still mark module execution
as changed in check mode

@ -0,0 +1,57 @@
# (c) 2018, Alexander Bethke <oolongbrothers@gmx.net>
# (c) 2018, Ansible Project
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
- block:
- import_tasks: setup.yml
become: true
# executable override
- name: Test executable override
flatpak_remote:
name: irrelevant
remote: irrelevant
state: present
executable: nothing-that-exists
ignore_errors: true
register: executable_override_result
- name: Verify executable override test result
assert:
that:
- "executable_override_result.failed == true"
- "executable_override_result.changed == false"
msg: "Specifying non-existing executable shall fail module execution"
- import_tasks: check_mode.yml
become: false
- import_tasks: test.yml
become: false
vars:
method: user
- import_tasks: test.yml
become: true
vars:
method: system
when: |
ansible_distribution == 'Fedora' or
ansible_distribution == 'Ubuntu' and not ansible_distribution_major_version | int < 16

@ -0,0 +1,27 @@
- name: Install flatpak on Fedora
dnf:
name: flatpak
state: present
when: ansible_distribution == 'Fedora'
- block:
- name: Activate flatpak ppa on Ubuntu versions older than 18.04/bionic
apt_repository:
repo: "ppa:alexlarsson/flatpak"
state: present
mode: 0644
when: ansible_lsb.major_release | int < 18
- name: Install flatpak package on Ubuntu
apt:
name: flatpak
state: present
when: ansible_distribution == 'Ubuntu'
- name: Install flatpak remote for testing check mode
flatpak_remote:
name: check-mode-test-remote
flatpakrepo_url: /tmp/flatpak/repo/dummy-repo.flatpakrepo
state: present

@ -0,0 +1,72 @@
# state=present
- name: Test addition - {{ method }}
flatpak_remote:
name: flatpak-test
flatpakrepo_url: /tmp/flatpak/repo/dummy-repo.flatpakrepo
state: present
method: "{{ method }}"
register: addition_result
- name: Verify addition test result - {{ method }}
assert:
that:
- "addition_result.changed == true"
msg: "state=preset shall add flatpak when absent"
- name: Test idempotency of addition - {{ method }}
flatpak_remote:
name: flatpak-test
flatpakrepo_url: /tmp/flatpak/repo/dummy-repo.flatpakrepo
state: present
method: "{{ method }}"
register: double_addition_result
- name: Verify idempotency of addition test result - {{ method }}
assert:
that:
- "double_addition_result.changed == false"
msg: "state=present shall not do anything when flatpak is already present"
- name: Test updating remote url does not do anything - {{ method }}
flatpak_remote:
name: flatpak-test
flatpakrepo_url: https://a.different/repo.flatpakrepo
state: present
method: "{{ method }}"
register: url_update_result
- name: Verify updating remote url does not do anything - {{ method }}
assert:
that:
- "url_update_result.changed == false"
msg: "Trying to update the URL of an existing flatpak remote shall not do anything"
# state=absent
- name: Test removal - {{ method }}
flatpak_remote:
name: flatpak-test
state: absent
method: "{{ method }}"
register: removal_result
- name: Verify removal test result - {{ method }}
assert:
that:
- "removal_result.changed == true"
msg: "state=absent shall remove flatpak when present"
- name: Test idempotency of removal - {{ method }}
flatpak_remote:
name: flatpak-test
state: absent
method: "{{ method }}"
register: double_removal_result
- name: Verify idempotency of removal test result - {{ method }}
assert:
that:
- "double_removal_result.changed == false"
msg: "state=absent shall not do anything when flatpak is not present"

@ -0,0 +1,11 @@
shippable/posix/incidental
skip/aix
skip/osx
skip/freebsd
destructive
skip/docker # The tests sometimes make docker daemon unstable; hence,
# we skip all docker-based CI runs to avoid disrupting
# the whole CI system. On VMs, we restart docker daemon
# after finishing the tests to minimize potential effects
# on other tests.
needs/root

@ -0,0 +1,3 @@
---
plugin: docker_swarm
docker_host: unix://var/run/docker.sock

@ -0,0 +1,5 @@
---
plugin: docker_swarm
docker_host: unix://var/run/docker.sock
verbose_output: no
include_host_uri: yes

@ -0,0 +1,3 @@
---
dependencies:
- incidental_setup_docker

@ -0,0 +1,18 @@
---
- hosts: 127.0.0.1
connection: local
gather_facts: yes
tasks:
- name: Make sure swarm is removed
docker_swarm:
state: absent
force: yes
- name: remove docker pagkages
action: "{{ ansible_facts.pkg_mgr }}"
args:
name:
- docker
- docker-ce
- docker-ce-cli
state: absent

@ -0,0 +1,15 @@
---
- hosts: 127.0.0.1
connection: local
vars:
docker_skip_cleanup: yes
tasks:
- name: Setup docker
import_role:
name: incidental_setup_docker
- name: Create a Swarm cluster
docker_swarm:
state: present
advertise_addr: "{{ansible_default_ipv4.address | default('127.0.0.1')}}"

@ -0,0 +1,58 @@
---
- hosts: 127.0.0.1
connection: local # otherwise Ansible will complain that it cannot connect via ssh to 127.0.0.1:22
gather_facts: no
tasks:
- name: Show all groups
debug:
var: groups
- name: Make sure docker_swarm groups are there
assert:
that:
- groups.all | length > 0
- groups.leader | length == 1
- groups.manager | length > 0
- groups.worker | length >= 0
- groups.nonleaders | length >= 0
- hosts: all
connection: local # otherwise Ansible will complain that it cannot connect via ssh to 127.0.0.1:22
vars:
# for some reason, Ansible can't find the Python interpreter when connecting to the nodes,
# which is in fact just localhost in disguise. That's why we use ansible_playbook_python.
ansible_python_interpreter: "{{ ansible_playbook_python }}"
tasks:
- name: Check for groups
assert:
that:
- "groups.manager | length > 0"
- "groups.worker | length >= 0"
- "groups.leader | length == 1"
run_once: yes
- name: List manager group
debug:
var: groups.manager
run_once: yes
- name: List worker group
debug:
var: groups.worker
run_once: yes
- name: List leader group
debug:
var: groups.leader
run_once: yes
- name: Print ansible_host per host
debug:
var: ansible_host
- name: Make sure docker_swarm_node_attributes is available
assert:
that:
- docker_swarm_node_attributes is not undefined
- name: Print docker_swarm_node_attributes per host
debug:
var: docker_swarm_node_attributes

@ -0,0 +1,35 @@
---
- hosts: 127.0.0.1
connection: local # otherwise Ansible will complain that it cannot connect via ssh to 127.0.0.1:22
gather_facts: no
tasks:
- name: Show all groups
debug:
var: groups
- name: Make sure docker_swarm groups are there
assert:
that:
- groups.all | length > 0
- groups.leader | length == 1
- groups.manager | length > 0
- groups.worker | length >= 0
- groups.nonleaders | length >= 0
- hosts: all
connection: local # otherwise Ansible will complain that it cannot connect via ssh to 127.0.0.1:22
vars:
# for some reason, Ansible can't find the Python interpreter when connecting to the nodes,
# which is in fact just localhost in disguise. That's why we use ansible_playbook_python.
ansible_python_interpreter: "{{ ansible_playbook_python }}"
tasks:
- name: Make sure docker_swarm_node_attributes is not available
assert:
that:
- docker_swarm_node_attributes is undefined
- name: Make sure ansible_host_uri is available
assert:
that:
- ansible_host_uri is defined
- name: Print ansible_host_uri
debug:
var: ansible_host_uri

@ -0,0 +1,23 @@
#!/usr/bin/env bash
[[ -n "$DEBUG" || -n "$ANSIBLE_DEBUG" ]] && set -x
set -euo pipefail
cleanup() {
echo "Cleanup"
ansible-playbook playbooks/swarm_cleanup.yml
echo "Done"
exit 0
}
trap cleanup INT TERM EXIT
echo "Setup"
ANSIBLE_ROLES_PATH=.. ansible-playbook playbooks/swarm_setup.yml
echo "Test docker_swarm inventory 1"
ansible-playbook -i inventory_1.docker_swarm.yml playbooks/test_inventory_1.yml
echo "Test docker_swarm inventory 2"
ansible-playbook -i inventory_2.docker_swarm.yml playbooks/test_inventory_2.yml

@ -0,0 +1,6 @@
shippable/posix/incidental
destructive
needs/target/incidental_setup_openssl
needs/file/test/lib/ansible_test/_data/requirements/constraints.txt
skip/aix
skip/python2.6

@ -0,0 +1,4 @@
---
vault_gen_path: 'gen/testproject'
vault_kv1_path: 'kv1/testproject'
vault_kv2_path: 'kv2/data/testproject'

@ -0,0 +1,21 @@
- name: 'Create an approle policy'
shell: "echo '{{ policy }}' | {{ vault_cmd }} policy write approle-policy -"
vars:
policy: |
path "auth/approle/login" {
capabilities = [ "create", "read" ]
}
- name: 'Enable the AppRole auth method'
command: '{{ vault_cmd }} auth enable approle'
- name: 'Create a named role'
command: '{{ vault_cmd }} write auth/approle/role/test-role policies="test-policy,approle-policy"'
- name: 'Fetch the RoleID of the AppRole'
command: '{{ vault_cmd }} read -field=role_id auth/approle/role/test-role/role-id'
register: role_id_cmd
- name: 'Get a SecretID issued against the AppRole'
command: '{{ vault_cmd }} write -field=secret_id -f auth/approle/role/test-role/secret-id'
register: secret_id_cmd

@ -0,0 +1,45 @@
- vars:
role_id: '{{ role_id_cmd.stdout }}'
secret_id: '{{ secret_id_cmd.stdout }}'
block:
- name: 'Fetch secrets using "hashi_vault" lookup'
set_fact:
secret1: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret1 auth_method=approle secret_id=' ~ secret_id ~ ' role_id=' ~ role_id) }}"
secret2: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret2 auth_method=approle secret_id=' ~ secret_id ~ ' role_id=' ~ role_id) }}"
- name: 'Check secret values'
fail:
msg: 'unexpected secret values'
when: secret1['value'] != 'foo1' or secret2['value'] != 'foo2'
- name: 'Failure expected when erroneous credentials are used'
vars:
secret_wrong_cred: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret2 auth_method=approle secret_id=toto role_id=' ~ role_id) }}"
debug:
msg: 'Failure is expected ({{ secret_wrong_cred }})'
register: test_wrong_cred
ignore_errors: true
- name: 'Failure expected when unauthorized secret is read'
vars:
secret_unauthorized: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret3 auth_method=approle secret_id=' ~ secret_id ~ ' role_id=' ~ role_id) }}"
debug:
msg: 'Failure is expected ({{ secret_unauthorized }})'
register: test_unauthorized
ignore_errors: true
- name: 'Failure expected when inexistent secret is read'
vars:
secret_inexistent: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret4 auth_method=approle secret_id=' ~ secret_id ~ ' role_id=' ~ role_id) }}"
debug:
msg: 'Failure is expected ({{ secret_inexistent }})'
register: test_inexistent
ignore_errors: true
- name: 'Check expected failures'
assert:
msg: "an expected failure didn't occur"
that:
- test_wrong_cred is failed
- test_unauthorized is failed
- test_inexistent is failed

@ -0,0 +1,155 @@
---
- name: Install Hashi Vault on controlled node and test
vars:
vault_version: '0.11.0'
vault_uri: 'https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/lookup_hashi_vault/vault_{{ vault_version }}_{{ ansible_system | lower }}_{{ vault_arch }}.zip'
vault_cmd: '{{ local_temp_dir }}/vault'
block:
- name: Create a local temporary directory
tempfile:
state: directory
register: tempfile_result
- set_fact:
local_temp_dir: '{{ tempfile_result.path }}'
- when: pyopenssl_version.stdout is version('0.15', '>=')
block:
- name: Generate privatekey
openssl_privatekey:
path: '{{ local_temp_dir }}/privatekey.pem'
- name: Generate CSR
openssl_csr:
path: '{{ local_temp_dir }}/csr.csr'
privatekey_path: '{{ local_temp_dir }}/privatekey.pem'
subject:
commonName: localhost
- name: Generate selfsigned certificate
openssl_certificate:
path: '{{ local_temp_dir }}/cert.pem'
csr_path: '{{ local_temp_dir }}/csr.csr'
privatekey_path: '{{ local_temp_dir }}/privatekey.pem'
provider: selfsigned
selfsigned_digest: sha256
register: selfsigned_certificate
- name: 'Install unzip'
package:
name: unzip
when: ansible_distribution != "MacOSX" # unzip already installed
- assert:
# Linux: x86_64, FreeBSD: amd64
that: ansible_architecture in ['i386', 'x86_64', 'amd64']
- set_fact:
vault_arch: '386'
when: ansible_architecture == 'i386'
- set_fact:
vault_arch: amd64
when: ansible_architecture in ['x86_64', 'amd64']
- name: 'Download vault binary'
unarchive:
src: '{{ vault_uri }}'
dest: '{{ local_temp_dir }}'
remote_src: true
- environment:
# used by vault command
VAULT_DEV_ROOT_TOKEN_ID: '47542cbc-6bf8-4fba-8eda-02e0a0d29a0a'
block:
- name: 'Create configuration file'
template:
src: vault_config.hcl.j2
dest: '{{ local_temp_dir }}/vault_config.hcl'
- name: 'Start vault service'
environment:
VAULT_ADDR: 'http://localhost:8200'
block:
- name: 'Start vault server (dev mode enabled)'
shell: 'nohup {{ vault_cmd }} server -dev -config {{ local_temp_dir }}/vault_config.hcl </dev/null >/dev/null 2>&1 &'
- name: 'Create generic secrets engine'
command: '{{ vault_cmd }} secrets enable -path=gen generic'
- name: 'Create KV v1 secrets engine'
command: '{{ vault_cmd }} secrets enable -path=kv1 -version=1 kv'
- name: 'Create KV v2 secrets engine'
command: '{{ vault_cmd }} secrets enable -path=kv2 -version=2 kv'
- name: 'Create a test policy'
shell: "echo '{{ policy }}' | {{ vault_cmd }} policy write test-policy -"
vars:
policy: |
path "{{ vault_gen_path }}/secret1" {
capabilities = ["read"]
}
path "{{ vault_gen_path }}/secret2" {
capabilities = ["read", "update"]
}
path "{{ vault_gen_path }}/secret3" {
capabilities = ["deny"]
}
path "{{ vault_kv1_path }}/secret1" {
capabilities = ["read"]
}
path "{{ vault_kv1_path }}/secret2" {
capabilities = ["read", "update"]
}
path "{{ vault_kv1_path }}/secret3" {
capabilities = ["deny"]
}
path "{{ vault_kv2_path }}/secret1" {
capabilities = ["read"]
}
path "{{ vault_kv2_path }}/secret2" {
capabilities = ["read", "update"]
}
path "{{ vault_kv2_path }}/secret3" {
capabilities = ["deny"]
}
- name: 'Create generic secrets'
command: '{{ vault_cmd }} write {{ vault_gen_path }}/secret{{ item }} value=foo{{ item }}'
loop: [1, 2, 3]
- name: 'Create KV v1 secrets'
command: '{{ vault_cmd }} kv put {{ vault_kv1_path }}/secret{{ item }} value=foo{{ item }}'
loop: [1, 2, 3]
- name: 'Create KV v2 secrets'
command: '{{ vault_cmd }} kv put {{ vault_kv2_path | regex_replace("/data") }}/secret{{ item }} value=foo{{ item }}'
loop: [1, 2, 3]
- name: setup approle auth
import_tasks: approle_setup.yml
when: ansible_distribution != 'RedHat' or ansible_distribution_major_version is version('7', '>')
- name: setup token auth
import_tasks: token_setup.yml
- import_tasks: tests.yml
vars:
auth_type: approle
when: ansible_distribution != 'RedHat' or ansible_distribution_major_version is version('7', '>')
- import_tasks: tests.yml
vars:
auth_type: token
always:
- name: 'Kill vault process'
shell: "kill $(cat {{ local_temp_dir }}/vault.pid)"
ignore_errors: true
always:
- name: 'Delete temp dir'
file:
path: '{{ local_temp_dir }}'
state: absent

@ -0,0 +1,35 @@
- name: 'test {{ auth_type }} auth without SSL (lookup parameters)'
include_tasks: '{{ auth_type }}_test.yml'
vars:
conn_params: 'url=http://localhost:8200 '
- name: 'test {{ auth_type }} auth without SSL (environment variable)'
include_tasks: '{{ auth_type }}_test.yml'
args:
apply:
vars:
conn_params: ''
environment:
VAULT_ADDR: 'http://localhost:8200'
- when: pyopenssl_version.stdout is version('0.15', '>=')
block:
- name: 'test {{ auth_type }} auth with certs (validation enabled, lookup parameters)'
include_tasks: '{{ auth_type }}_test.yml'
vars:
conn_params: 'url=https://localhost:8201 ca_cert={{ local_temp_dir }}/cert.pem validate_certs=True '
- name: 'test {{ auth_type }} auth with certs (validation enabled, environment variables)'
include_tasks: '{{ auth_type }}_test.yml'
args:
apply:
vars:
conn_params: ''
environment:
VAULT_ADDR: 'https://localhost:8201'
VAULT_CACERT: '{{ local_temp_dir }}/cert.pem'
- name: 'test {{ auth_type }} auth with certs (validation disabled, lookup parameters)'
include_tasks: '{{ auth_type }}_test.yml'
vars:
conn_params: 'url=https://localhost:8201 validate_certs=False '

@ -0,0 +1,3 @@
- name: 'Create a test credentials (token)'
command: '{{ vault_cmd }} token create -policy test-policy -field token'
register: user_token_cmd

@ -0,0 +1,58 @@
- vars:
user_token: '{{ user_token_cmd.stdout }}'
block:
- name: 'Fetch secrets using "hashi_vault" lookup'
set_fact:
gen_secret1: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_gen_path ~ '/secret1 auth_method=token token=' ~ user_token) }}"
gen_secret2: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_gen_path ~ '/secret2 token=' ~ user_token) }}"
kv1_secret1: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv1_path ~ '/secret1 auth_method=token token=' ~ user_token) }}"
kv1_secret2: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv1_path ~ '/secret2 token=' ~ user_token) }}"
kv2_secret1: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret1 auth_method=token token=' ~ user_token) }}"
kv2_secret2: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret2 token=' ~ user_token) }}"
- name: 'Check secret generic values'
fail:
msg: 'unexpected secret values'
when: gen_secret1['value'] != 'foo1' or gen_secret2['value'] != 'foo2'
- name: 'Check secret kv1 values'
fail:
msg: 'unexpected secret values'
when: kv1_secret1['value'] != 'foo1' or kv1_secret2['value'] != 'foo2'
- name: 'Check secret kv2 values'
fail:
msg: 'unexpected secret values'
when: kv2_secret1['value'] != 'foo1' or kv2_secret2['value'] != 'foo2'
- name: 'Failure expected when erroneous credentials are used'
vars:
secret_wrong_cred: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret2 auth_method=token token=wrong_token') }}"
debug:
msg: 'Failure is expected ({{ secret_wrong_cred }})'
register: test_wrong_cred
ignore_errors: true
- name: 'Failure expected when unauthorized secret is read'
vars:
secret_unauthorized: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret3 token=' ~ user_token) }}"
debug:
msg: 'Failure is expected ({{ secret_unauthorized }})'
register: test_unauthorized
ignore_errors: true
- name: 'Failure expected when inexistent secret is read'
vars:
secret_inexistent: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret4 token=' ~ user_token) }}"
debug:
msg: 'Failure is expected ({{ secret_inexistent }})'
register: test_inexistent
ignore_errors: true
- name: 'Check expected failures'
assert:
msg: "an expected failure didn't occur"
that:
- test_wrong_cred is failed
- test_unauthorized is failed
- test_inexistent is failed

@ -0,0 +1,10 @@
# {{ ansible_managed }}
pid_file = "{{ local_temp_dir }}/vault.pid"
{% if pyopenssl_version.stdout is version('0.15', '>=') %}
listener "tcp" {
tls_key_file = "{{ local_temp_dir }}/privatekey.pem"
tls_cert_file = "{{ local_temp_dir }}/cert.pem"
tls_disable = false
address = "localhost:8201"
}
{% endif %}

@ -0,0 +1,19 @@
- hosts: localhost
tasks:
- name: Install openssl
import_role:
name: incidental_setup_openssl
- name: "RedHat <= 7, select last version compatible with request 2.6.0 (this version doesn't support approle auth)"
set_fact:
hvac_package: 'hvac==0.2.5'
when: ansible_distribution == 'RedHat' and ansible_distribution_major_version is version('7', '<=')
- name: 'CentOS < 7, select last version compatible with Python 2.6'
set_fact:
hvac_package: 'hvac==0.5.0'
when: ansible_distribution == 'CentOS' and ansible_distribution_major_version is version('7', '<')
- name: 'Install hvac Python package'
pip:
name: "{{ hvac_package|default('hvac') }}"

@ -0,0 +1,9 @@
- hosts: localhost
tasks:
- name: register pyOpenSSL version
command: "{{ ansible_python.executable }} -c 'import OpenSSL; print(OpenSSL.__version__)'"
register: pyopenssl_version
- name: Test lookup hashi_vault
import_role:
name: incidental_lookup_hashi_vault/lookup_hashi_vault

@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -eux
# First install pyOpenSSL, then test lookup in a second playbook in order to
# workaround this error which occurs on OS X 10.11 only:
#
# TASK [lookup_hashi_vault : test token auth with certs (validation enabled, lookup parameters)] ***
# included: lookup_hashi_vault/tasks/token_test.yml for testhost
#
# TASK [lookup_hashi_vault : Fetch secrets using "hashi_vault" lookup] ***
# From cffi callback <function _verify_callback at 0x106f995f0>:
# Traceback (most recent call last):
# File "/usr/local/lib/python2.7/site-packages/OpenSSL/SSL.py", line 309, in wrapper
# _lib.X509_up_ref(x509)
# AttributeError: 'module' object has no attribute 'X509_up_ref'
# fatal: [testhost]: FAILED! => { "msg": "An unhandled exception occurred while running the lookup plugin 'hashi_vault'. Error was a <class 'requests.exceptions.SSLError'>, original message: HTTPSConnectionPool(host='localhost', port=8201): Max retries exceeded with url: /v1/auth/token/lookup-self (Caused by SSLError(SSLError(\"bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)\",),))"}
ANSIBLE_ROLES_PATH=../ \
ansible-playbook playbooks/install_dependencies.yml -v "$@"
ANSIBLE_ROLES_PATH=../ \
ansible-playbook playbooks/test_lookup_hashi_vault.yml -v "$@"

@ -0,0 +1,6 @@
destructive
shippable/posix/incidental
skip/aix
skip/osx
skip/freebsd
skip/rhel

@ -0,0 +1,2 @@
dependencies:
- incidental_setup_rabbitmq

@ -0,0 +1,5 @@
# Rabbitmq lookup
- include: ubuntu.yml
when:
- ansible_distribution == 'Ubuntu'
- ansible_distribution_release != 'trusty'

@ -0,0 +1,138 @@
- name: Test failure without pika installed
set_fact:
rabbit_missing_pika: "{{ lookup('rabbitmq', url='amqp://guest:guest@192.168.250.1:5672/%2F', queue='hello', count=3) }}"
ignore_errors: yes
register: rabbitmq_missing_pika_error
- assert:
that:
- "'pika python package is required' in rabbitmq_missing_pika_error.msg"
- name: Install pika and requests
pip:
name: pika<1.0.0,requests
state: latest
- name: Test that giving an incorrect amqp protocol in URL will error
set_fact:
rabbitmq_test_protocol: "{{ lookup('rabbitmq', url='zzzamqp://guest:guest@192.168.250.1:5672/%2F', queue='hello', count=3) }}"
ignore_errors: yes
register: rabbitmq_protocol_error
- assert:
that:
- "rabbitmq_protocol_error is failed"
- "'URL malformed' in rabbitmq_protocol_error.msg"
- name: Test that giving an incorrect IP address in URL will error
set_fact:
rabbitmq_test_protocol: "{{ lookup('rabbitmq', url='amqp://guest:guest@xxxxx192.112312368.250.1:5672/%2F', queue='hello', count=3) }}"
ignore_errors: yes
register: rabbitmq_ip_error
- assert:
that:
- "rabbitmq_ip_error is failed"
- "'Connection issue' in rabbitmq_ip_error.msg"
- name: Test missing parameters will error
set_fact:
rabbitmq_test_protocol: "{{ lookup('rabbitmq') }}"
ignore_errors: yes
register: rabbitmq_params_error
- assert:
that:
- "rabbitmq_params_error is failed"
- "'URL is required for rabbitmq lookup.' in rabbitmq_params_error.msg"
- name: Test missing queue will error
set_fact:
rabbitmq_queue_protocol: "{{ lookup('rabbitmq', url='amqp://guest:guest@192.168.250.1:5672/%2F') }}"
ignore_errors: yes
register: rabbitmq_queue_error
- assert:
that:
- "rabbitmq_queue_error is failed"
- "'Queue is required for rabbitmq lookup' in rabbitmq_queue_error.msg"
- name: Enables the rabbitmq_management plugin
rabbitmq_plugin:
names: rabbitmq_management
state: enabled
- name: Setup test queue
rabbitmq_queue:
name: hello
- name: Post test message to the exchange (string)
uri:
url: http://localhost:15672/api/exchanges/%2f/amq.default/publish
method: POST
body: '{"properties":{},"routing_key":"hello","payload":"ansible-test","payload_encoding":"string"}'
user: guest
password: guest
force_basic_auth: yes
return_content: yes
headers:
Content-Type: "application/json"
register: post_data
- name: Post test message to the exchange (json)
uri:
url: http://localhost:15672/api/exchanges/%2f/amq.default/publish
method: POST
body: '{"properties":{"content_type": "application/json"},"routing_key":"hello","payload":"{\"key\": \"value\" }","payload_encoding":"string"}'
user: guest
password: guest
force_basic_auth: yes
return_content: yes
headers:
Content-Type: "application/json"
register: post_data_json
- name: Test retrieve messages
set_fact:
rabbitmq_msg: "{{ lookup('rabbitmq', url='amqp://guest:guest@localhost:5672/%2f/hello', queue='hello') }}"
ignore_errors: yes
register: rabbitmq_msg_error
- name: Ensure two messages received
assert:
that:
- "rabbitmq_msg_error is not failed"
- rabbitmq_msg | length == 2
- name: Ensure first message is a string
assert:
that:
- rabbitmq_msg[0].msg == "ansible-test"
- name: Ensure second message is json
assert:
that:
- rabbitmq_msg[1].json.key == "value"
- name: Test missing vhost
set_fact:
rabbitmq_msg: "{{ lookup('rabbitmq', url='amqp://guest:guest@localhost:5672/missing/', queue='hello') }}"
ignore_errors: yes
register: rabbitmq_vhost_error
- assert:
that:
- "rabbitmq_vhost_error is failed"
- "'NOT_ALLOWED' in rabbitmq_vhost_error.msg"
# Tidy up
- name: Uninstall pika and requests
pip:
name: pika,requests
state: absent
- name: Disable the rabbitmq_management plugin
rabbitmq_plugin:
names: rabbitmq_management
state: disabled

@ -0,0 +1,6 @@
destructive
needs/privileged
shippable/posix/incidental
skip/aix
skip/freebsd
skip/osx

@ -0,0 +1,2 @@
dependencies:
- setup_remote_tmp_dir

@ -0,0 +1,15 @@
- name: Install required packages (Linux)
package:
name: lvm2
state: present
when: ansible_system == 'Linux'
- name: Test lvg module
block:
- import_tasks: setup.yml
- import_tasks: test_indempotency.yml
- import_tasks: test_grow_reduce.yml
always:
- import_tasks: teardown.yml

@ -0,0 +1,13 @@
- name: "Create files to use as a disk devices"
command: "dd if=/dev/zero of={{ remote_tmp_dir }}/img{{ item }} bs=1M count=10"
with_sequence: 'count=2'
- name: "Create loop device for file"
command: "losetup --show -f {{ remote_tmp_dir }}/img{{ item }}"
with_sequence: 'count=2'
register: loop_devices
- name: "Affect name on disk to work on"
set_fact:
loop_device1: "{{ loop_devices.results[0] }}"
loop_device2: "{{ loop_devices.results[1] }}"

@ -0,0 +1,17 @@
- name: Remove test volume group
lvg:
vg: testvg
state: absent
- name: Detach loop device
command: "losetup -d {{ item.stdout }}"
loop: "{{ loop_devices.results|default([]) }}"
when:
- item.stdout is defined
- item.stdout is match("/dev/.*")
- name: Remove device files
file:
path: "{{ remote_tmp_dir }}/img{{ item }}"
state: absent
with_sequence: 'count={{ loop_devices.results|length }}'

@ -0,0 +1,33 @@
- name: "Create volume group on first disk"
lvg:
vg: testvg
pvs: "{{ loop_device1.stdout }}"
- name: "get lvm facts"
setup:
- debug: var=ansible_lvm
- name: "Assert the testvg span only on first disk"
assert:
that:
- ansible_lvm.pvs[loop_device1.stdout].vg == "testvg"
- 'loop_device2.stdout not in ansible_lvm.pvs or
ansible_lvm.pvs[loop_device2.stdout].vg == ""'
- name: "Extend to second disk AND reduce from the first disk"
lvg:
vg: testvg
pvs: "{{ loop_device2.stdout }}"
- name: "get lvm facts"
setup:
- debug: var=ansible_lvm
- name: "Assert the testvg span only on first disk"
assert:
that:
- 'loop_device1.stdout not in ansible_lvm.pvs or
ansible_lvm.pvs[loop_device1.stdout].vg == ""'
- ansible_lvm.pvs[loop_device2.stdout].vg == "testvg"

@ -0,0 +1,15 @@
- name: Create volume group on disk device
lvg:
vg: testvg
pvs: "{{ loop_device1.stdout }}"
- name: Create the volume group again to verify idempotence
lvg:
vg: testvg
pvs: "{{ loop_device1.stdout }}"
register: repeat_vg_create
- name: Do all assertions to verify expected results
assert:
that:
- repeat_vg_create is not changed

@ -0,0 +1,7 @@
destructive
shippable/posix/incidental
skip/aix
skip/osx
skip/freebsd
skip/rhel
needs/root

@ -0,0 +1,21 @@
---
# defaults file for test_mongodb_user
mongodb_admin_user: test_root
mongodb_admin_password: saE_Rr9!gE6gh#e~R#nZ
mongod_auth: false
kill_signal: SIGTERM
# Should be one of
# --storageEngine wiredTiger --wiredTigerEngineConfigString="cache_size=200M"
# --storageEngine mmapv1 --nojournal
mongod_storage_engine_opts: "--storageEngine wiredTiger --wiredTigerEngineConfigString='cache_size=200M'"
mongodb_user: mongodb
mongodb_user_list:
- { "name": "user1", "password": "password1", "roles": "read", "database": "test" }
- { "name": "user2", "password": "password2", "roles": "readWrite", "database": "test" }
- { "name": "user3", "password": "password3", "roles": "dbAdmin", "database": "test" }
- { "name": "user4", "password": "password4", "roles": "userAdmin", "database": "test" }
- { "name": "user5", "password": "password5", "roles": "clusterAdmin", "database": "admin" }
- { "name": "user6", "password": "password6", "roles": "readAnyDatabase", "database": "admin" }
- { "name": "user7", "password": "password7", "roles": "readWriteAnyDatabase", "database": "admin" }
- { "name": "user8", "password": "password8", "roles": "userAdminAnyDatabase", "database": "admin" }
- { "name": "user9", "password": "password9", "roles": "dbAdminAnyDatabase", "database": "admin" }

@ -0,0 +1,3 @@
dependencies:
- incidental_setup_mongodb
- setup_remote_tmp_dir

@ -0,0 +1,143 @@
# test code for the mongodb_parameter module
# (c) 2019, Rhys Campbell <rhys.james.campbell@googlemail.com>
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# ============================================================
- name: Ensure tests home exists
file:
path: "{{ remote_tmp_dir }}/tests"
state: directory
- include_tasks: mongod_teardown.yml
- include_tasks: mongod_singlenode.yml
- name: Set syncdelay to 99
mongodb_parameter:
login_port: 3001
param: syncdelay
value: 99
param_type: int
register: sd_change
- assert:
that:
- sd_change.before | int == 60
- sd_change.after | int == 99
- sd_change.changed == True
- name: Set syncdelay to 99 (again)
mongodb_parameter:
login_port: 3001
param: syncdelay
value: 99
param_type: int
register: sd_change
- assert:
that:
- sd_change.before | int == 99
- sd_change.after | int == 99
- sd_change.changed == False
- name: Create admin user with module
mongodb_user:
login_port: 3001
database: admin
name: "{{ mongodb_admin_user }}"
password: "{{ mongodb_admin_password }}"
roles: root
state: present
register: mongodb_admin_user_created
- assert:
that:
- mongodb_admin_user_created.changed == True
- name: Kill all mongod processes
command: pkill -{{ kill_signal }} mongod
ignore_errors: true
- name: Getting pids for mongod
pids:
name: mongod
register: pids_of_mongod
- name: Wait for all mongod processes to exit
wait_for:
path: "/proc/{{ item }}/status"
state: absent
delay: 3
with_items: "{{ pids_of_mongod }}"
- set_fact:
mongod_auth: true
- include_tasks: mongod_singlenode.yml
# Tests with auth enabled
- name: Set syncdelay to 59 with auth
mongodb_parameter:
login_port: 3001
login_user: "{{ mongodb_admin_user }}"
login_password: "{{ mongodb_admin_password }}"
param: syncdelay
value: 59
param_type: int
register: sd_change
- assert:
that:
- sd_change.before | int == 60
- sd_change.after | int == 59
- sd_change.changed == True
- name: Set syncdelay to 59 (again) with auth
mongodb_parameter:
login_port: 3001
login_user: "{{ mongodb_admin_user }}"
login_password: "{{ mongodb_admin_password }}"
param: syncdelay
value: 59
param_type: int
register: sd_change
- assert:
that:
- sd_change.before | int == 59
- sd_change.after | int == 59
- sd_change.changed == False
- name: Set authenticationMechanisms to MONGODB-X509 with auth (will fail)
mongodb_parameter:
login_port: 3001
login_user: "{{ mongodb_admin_user }}"
login_password: "{{ mongodb_admin_password }}"
param: authenticationMechanisms
value: "MONGODB-X509"
param_type: str
register: diag_change
ignore_errors: yes
- assert:
that:
- '"unable to change parameter" in diag_change.msg'
- diag_change.failed == True
# Clean up
- include_tasks: mongod_teardown.yml

@ -0,0 +1,55 @@
- name: Set mongodb_user user for redhat
set_fact:
mongodb_user: "mongod"
when: ansible_os_family == "RedHat"
- set_fact:
mongodb_nodes:
- 3001
- name: Create directories for mongod processes
file:
path: "{{ remote_tmp_dir }}/mongod{{ item }}"
state: directory
owner: "{{ mongodb_user }}"
group: "{{ mongodb_user }}"
mode: 0755
recurse: yes
with_items: "{{ mongodb_nodes }}"
- name: Ensure {{ remote_tmp_dir }}/config dir exists
file:
path: "{{ remote_tmp_dir }}/config"
state: directory
owner: "{{ mongodb_user }}"
group: "{{ mongodb_user }}"
mode: 0755
- name: Create keyfile
copy:
dest: "{{ remote_tmp_dir }}/my.key"
content: |
fd2CUrbXBJpB4rt74A6F
owner: "{{ mongodb_user }}"
group: "{{ mongodb_user }}"
mode: 0600
when: mongod_auth == True
- name: Spawn mongod process without auth
command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --logpath mongod{{ item }}/log.log --fork
args:
chdir: "{{ remote_tmp_dir }}"
with_items: "{{ mongodb_nodes | sort }}"
when: mongod_auth == False
- name: Spawn mongod process with auth
command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --logpath mongod{{ item }}/log.log --fork --auth --keyFile my.key
args:
chdir: "{{ remote_tmp_dir }}"
with_items: "{{ mongodb_nodes | sort }}"
when: mongod_auth == True
- name: Wait for mongod to start responding
wait_for:
port: "{{ item }}"
with_items: "{{ mongodb_nodes }}"

@ -0,0 +1,25 @@
- name: Kill all mongod processes
command: pkill -{{ kill_signal }} mongod
ignore_errors: true
- name: Getting pids for mongod
pids:
name: mongod
register: pids_of_mongod
- name: Wait for all mongod processes to exit
wait_for:
path: "/proc/{{ item }}/status"
state: absent
delay: 1
with_items: "{{ pids_of_mongod }}"
- name: Remove all mongod folders
file:
path: "{{ remote_tmp_dir }}/{{ item }}"
state: absent
with_items:
- mongod3001
- name: Remove all mongod sock files
shell: rm -Rf /tmp/mongodb*.sock

@ -0,0 +1,4 @@
destructive
shippable/posix/incidental
skip/aix
skip/osx

@ -0,0 +1,3 @@
db_name: 'ansible_db'
db_user1: 'ansible_db_user1'
db_user2: 'ansible_db_user2'

@ -0,0 +1,2 @@
dependencies:
- incidental_setup_postgresql_db

@ -0,0 +1,7 @@
# Initial CI tests of postgresql_user module
- import_tasks: postgresql_user_initial.yml
when: postgres_version_resp.stdout is version('9.4', '>=')
# General tests:
- import_tasks: postgresql_user_general.yml
when: postgres_version_resp.stdout is version('9.4', '>=')

@ -0,0 +1,741 @@
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Integration tests for postgresql_user module.
- vars:
test_user: hello.user.with.dots
test_user2: hello
test_group1: group1
test_group2: group2
test_table: test
test_comment1: 'comment1'
test_comment2: 'comment2'
task_parameters: &task_parameters
become_user: '{{ pg_user }}'
become: yes
register: result
pg_parameters: &pg_parameters
login_user: '{{ pg_user }}'
login_db: postgres
block:
#
# Common tests
#
- name: Create role in check_mode
<<: *task_parameters
check_mode: yes
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: check that the user doesn't exist
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_user }}'"
- assert:
that:
- result.rowcount == 0
- name: Create role in actual mode
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: check that the user exists
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_user }}'"
- assert:
that:
- result.rowcount == 1
- name: Add a comment on the user
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
comment: '{{ test_comment1 }}'
- assert:
that:
- result is changed
- result.queries == ["COMMENT ON ROLE \"{{ test_user }}\" IS '{{ test_comment1 }}'"]
- name: check the comment
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: >
SELECT pg_catalog.shobj_description(r.oid, 'pg_authid') AS comment
FROM pg_catalog.pg_roles r WHERE r.rolname = '{{ test_user }}'
- assert:
that:
- result.rowcount == 1
- result.query_result[0].comment == '{{ test_comment1 }}'
- name: Try to add the same comment on the user
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
comment: '{{ test_comment1 }}'
- assert:
that:
- result is not changed
- name: Try to add another comment on the user
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
comment: '{{ test_comment2 }}'
- assert:
that:
- result is changed
- result.queries == ["COMMENT ON ROLE \"{{ test_user }}\" IS '{{ test_comment2 }}'"]
- name: check the comment
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: >
SELECT pg_catalog.shobj_description(r.oid, 'pg_authid') AS comment
FROM pg_catalog.pg_roles r WHERE r.rolname = '{{ test_user }}'
- assert:
that:
- result.rowcount == 1
- result.query_result[0].comment == '{{ test_comment2 }}'
- name: Try to create role again in check_mode
<<: *task_parameters
check_mode: yes
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
- assert:
that:
- result is not changed
- result.user == '{{ test_user }}'
- name: check that the user exists
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_user }}'"
- assert:
that:
- result.rowcount == 1
- name: Try to create role again
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
- assert:
that:
- result is not changed
- result.user == '{{ test_user }}'
- name: check that the user exists
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_user }}'"
- assert:
that:
- result.rowcount == 1
- name: Drop role in check_mode
<<: *task_parameters
check_mode: yes
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
state: absent
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: check that the user actually exists
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_user }}'"
- assert:
that:
- result.rowcount == 1
- name: Drop role in actual mode
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
state: absent
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: check that the user doesn't exist
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_user }}'"
- assert:
that:
- result.rowcount == 0
- name: Try to drop role in check mode again
<<: *task_parameters
check_mode: yes
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
state: absent
- assert:
that:
- result is not changed
- result.user == '{{ test_user }}'
- name: Try to drop role in actual mode again
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
state: absent
- assert:
that:
- result is not changed
- result.user == '{{ test_user }}'
#
# password, no_password_changes, encrypted, expires parameters
#
- name: Create role with password, passed as hashed md5
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
password: md59543f1d82624df2b31672ec0f7050460
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: Check that the user exist with a proper password
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}' and rolpassword = 'md59543f1d82624df2b31672ec0f7050460'"
- assert:
that:
- result.rowcount == 1
- name: Test no_password_changes
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
password: u123
no_password_changes: yes
- assert:
that:
- result is not changed
- result.user == '{{ test_user }}'
- name: Check that nothing changed
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}' and rolpassword = 'md59543f1d82624df2b31672ec0f7050460'"
- assert:
that:
- result.rowcount == 1
# Storing unencrypted passwords is not available from PostgreSQL 10
- name: Change password, passed as unencrypted
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
password: myunencryptedpass
encrypted: no
when: postgres_version_resp.stdout is version('10', '<')
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
when: postgres_version_resp.stdout is version('10', '<')
- name: Check that the user exist with the unencrypted password
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}' and rolpassword = 'myunencryptedpass'"
when: postgres_version_resp.stdout is version('10', '<')
- assert:
that:
- result.rowcount == 1
when: postgres_version_resp.stdout is version('10', '<')
- name: Change password, explicit encrypted=yes
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
password: myunencryptedpass
encrypted: yes
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: Check that the user exist with encrypted password
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}' and rolpassword != 'myunencryptedpass'"
- assert:
that:
- result.rowcount == 1
- name: Change rolvaliduntil attribute
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
expires: 'Jan 31 2020'
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: Check the prev step
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: >
SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}'
AND rolvaliduntil::text like '2020-01-31%'
- assert:
that:
- result.rowcount == 1
- name: Try to set the same rolvaliduntil value again
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
expires: 'Jan 31 2020'
- assert:
that:
- result is not changed
- result.user == '{{ test_user }}'
- name: Check that nothing changed
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: >
SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}'
AND rolvaliduntil::text like '2020-01-31%'
- assert:
that:
- result.rowcount == 1
#
# role_attr_flags
#
- name: Set role attributes
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
role_attr_flags: CREATEROLE,CREATEDB
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: Check the prev step
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: >
SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}'
AND rolcreaterole = 't' and rolcreatedb = 't'
- assert:
that:
- result.rowcount == 1
- name: Set the same role attributes again
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
role_attr_flags: CREATEROLE,CREATEDB
- assert:
that:
- result is not changed
- result.user == '{{ test_user }}'
- name: Check the prev step
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: >
SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}'
AND rolcreaterole = 't' and rolcreatedb = 't'
- name: Set role attributes
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
role_attr_flags: NOCREATEROLE,NOCREATEDB
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- name: Check the prev step
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: >
SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}'
AND rolcreaterole = 'f' and rolcreatedb = 'f'
- assert:
that:
- result.rowcount == 1
- name: Set role attributes
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
role_attr_flags: NOCREATEROLE,NOCREATEDB
- assert:
that:
- result is not changed
- result.user == '{{ test_user }}'
- name: Check the prev step
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: >
SELECT rolname FROM pg_authid WHERE rolname = '{{ test_user }}'
AND rolcreaterole = 'f' and rolcreatedb = 'f'
#
# priv
#
- name: Create test table
<<: *task_parameters
postgresql_table:
<<: *pg_parameters
name: '{{ test_table }}'
columns:
- id int
- name: Insert data to test table
<<: *task_parameters
postgresql_query:
query: "INSERT INTO {{ test_table }} (id) VALUES ('1')"
<<: *pg_parameters
- name: Check that test_user is not allowed to read the data
<<: *task_parameters
postgresql_query:
db: postgres
login_user: '{{ pg_user }}'
session_role: '{{ test_user }}'
query: 'SELECT * FROM {{ test_table }}'
ignore_errors: yes
- assert:
that:
- result is failed
- "'permission denied' in result.msg"
- name: Grant privileges
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
priv: '{{ test_table }}:SELECT'
- assert:
that:
- result is changed
- name: Check that test_user is allowed to read the data
<<: *task_parameters
postgresql_query:
db: postgres
login_user: '{{ pg_user }}'
session_role: '{{ test_user }}'
query: 'SELECT * FROM {{ test_table }}'
- assert:
that:
- result.rowcount == 1
- name: Grant the same privileges again
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
priv: '{{ test_table }}:SELECT'
- assert:
that:
- result is not changed
- name: Remove test table
<<: *task_parameters
postgresql_table:
<<: *pg_parameters
name: '{{ test_table }}'
state: absent
#
# fail_on_user
#
- name: Create role for test
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user2 }}'
- name: Create test table, set owner as test_user
<<: *task_parameters
postgresql_table:
<<: *pg_parameters
name: '{{ test_table }}'
owner: '{{ test_user2 }}'
- name: Test fail_on_user
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user2 }}'
state: absent
ignore_errors: yes
- assert:
that:
- result is failed
- result.msg == 'Unable to remove user'
- name: Test fail_on_user
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
fail_on_user: no
- assert:
that:
- result is not changed
#
# Test groups parameter
#
- name: Create test group
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_group2 }}'
role_attr_flags: NOLOGIN
- name: Create role test_group1 and grant test_group2 to test_group1 in check_mode
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_group1 }}'
groups: '{{ test_group2 }}'
role_attr_flags: NOLOGIN
check_mode: yes
- assert:
that:
- result is changed
- result.user == '{{ test_group1 }}'
- result.queries == ['CREATE USER "{{ test_group1 }}" NOLOGIN', 'GRANT "{{ test_group2 }}" TO "{{ test_group1 }}"']
- name: check that the user doesn't exist
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_group1 }}'"
- assert:
that:
- result.rowcount == 0
- name: check membership
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT grolist FROM pg_group WHERE groname = '{{ test_group2 }}' AND grolist != '{}'"
- assert:
that:
- result.rowcount == 0
- name: Create role test_group1 and grant test_group2 to test_group1
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_group1 }}'
groups: '{{ test_group2 }}'
role_attr_flags: NOLOGIN
- assert:
that:
- result is changed
- result.user == '{{ test_group1 }}'
- result.queries == ['CREATE USER "{{ test_group1 }}" NOLOGIN', 'GRANT "{{ test_group2 }}" TO "{{ test_group1 }}"']
- name: check that the user exists
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_group1 }}'"
- assert:
that:
- result.rowcount == 1
- name: check membership
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT grolist FROM pg_group WHERE groname = '{{ test_group2 }}' AND grolist != '{}'"
- assert:
that:
- result.rowcount == 1
- name: Grant test_group2 to test_group1 again
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_group1 }}'
groups: '{{ test_group2 }}'
- assert:
that:
- result is not changed
- result.user == '{{ test_group1 }}'
- name: check membership
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT grolist FROM pg_group WHERE groname = '{{ test_group2 }}' AND grolist != '{}'"
- assert:
that:
- result.rowcount == 1
- name: Grant groups to existent role
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ test_user }}'
groups:
- '{{ test_group1 }}'
- '{{ test_group2 }}'
- assert:
that:
- result is changed
- result.user == '{{ test_user }}'
- result.queries == ['GRANT "{{ test_group1 }}" TO "{{ test_user }}"', 'GRANT "{{ test_group2 }}" TO "{{ test_user }}"']
- name: check membership
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
query: "SELECT * FROM pg_group WHERE groname in ('{{ test_group1 }}', '{{ test_group2 }}') AND grolist != '{}'"
- assert:
that:
- result.rowcount == 2
always:
#
# Clean up
#
- name: Drop test table
<<: *task_parameters
postgresql_table:
<<: *pg_parameters
name: '{{ test_table }}'
state: absent
- name: Drop test user
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
name: '{{ item }}'
state: absent
loop:
- '{{ test_user }}'
- '{{ test_user2 }}'
- '{{ test_group1 }}'
- '{{ test_group2 }}'

@ -0,0 +1,153 @@
#
# Create and destroy user, test 'password' and 'encrypted' parameters
#
# unencrypted values are not supported on newer versions
# do not run the encrypted: no tests if on 10+
- set_fact:
encryption_values:
- 'yes'
- set_fact:
encryption_values: '{{ encryption_values + ["no"]}}'
when: postgres_version_resp.stdout is version('10', '<=')
- include_tasks: test_password.yml
vars:
encrypted: '{{ loop_item }}'
db_password1: 'secretù' # use UTF-8
loop: '{{ encryption_values }}'
loop_control:
loop_var: loop_item
# BYPASSRLS role attribute was introduced in PostgreSQL 9.5, so
# we want to test attribute management differently depending
# on the version.
- set_fact:
bypassrls_supported: "{{ postgres_version_resp.stdout is version('9.5.0', '>=') }}"
# test 'no_password_change' and 'role_attr_flags' parameters
- include_tasks: test_no_password_change.yml
vars:
no_password_changes: '{{ loop_item }}'
loop:
- 'yes'
- 'no'
loop_control:
loop_var: loop_item
### TODO: fail_on_user
#
# Test login_user functionality
#
- name: Create a user to test login module parameters
become: yes
become_user: "{{ pg_user }}"
postgresql_user:
name: "{{ db_user1 }}"
state: "present"
encrypted: 'yes'
password: "password"
role_attr_flags: "CREATEDB,LOGIN,CREATEROLE"
login_user: "{{ pg_user }}"
db: postgres
- name: Create db
postgresql_db:
name: "{{ db_name }}"
state: "present"
login_user: "{{ db_user1 }}"
login_password: "password"
login_host: "localhost"
- name: Check that database created
become: yes
become_user: "{{ pg_user }}"
shell: echo "select datname from pg_database where datname = '{{ db_name }}';" | psql -d postgres
register: result
- assert:
that:
- "result.stdout_lines[-1] == '(1 row)'"
- name: Create a user
postgresql_user:
name: "{{ db_user2 }}"
state: "present"
encrypted: 'yes'
password: "md55c8ccfd9d6711fc69a7eae647fc54f51"
db: "{{ db_name }}"
login_user: "{{ db_user1 }}"
login_password: "password"
login_host: "localhost"
- name: Check that it was created
become: yes
become_user: "{{ pg_user }}"
shell: echo "select * from pg_user where usename='{{ db_user2 }}';" | psql -d postgres
register: result
- assert:
that:
- "result.stdout_lines[-1] == '(1 row)'"
- name: Grant database privileges
postgresql_privs:
type: "database"
state: "present"
roles: "{{ db_user2 }}"
privs: "CREATE,connect"
objs: "{{ db_name }}"
db: "{{ db_name }}"
login: "{{ db_user1 }}"
password: "password"
host: "localhost"
- name: Check that the user has the requested permissions (database)
become: yes
become_user: "{{ pg_user }}"
shell: echo "select datacl from pg_database where datname='{{ db_name }}';" | psql {{ db_name }}
register: result_database
- assert:
that:
- "result_database.stdout_lines[-1] == '(1 row)'"
- "db_user2 ~ '=Cc' in result_database.stdout"
- name: Remove user
postgresql_user:
name: "{{ db_user2 }}"
state: 'absent'
priv: "ALL"
db: "{{ db_name }}"
login_user: "{{ db_user1 }}"
login_password: "password"
login_host: "localhost"
- name: Check that they were removed
become: yes
become_user: "{{ pg_user }}"
shell: echo "select * from pg_user where usename='{{ db_user2 }}';" | psql -d postgres
register: result
- assert:
that:
- "result.stdout_lines[-1] == '(0 rows)'"
- name: Destroy DB
postgresql_db:
state: absent
name: "{{ db_name }}"
login_user: "{{ db_user1 }}"
login_password: "password"
login_host: "localhost"
- name: Check that database was destroyed
become: yes
become_user: "{{ pg_user }}"
shell: echo "select datname from pg_database where datname = '{{ db_name }}';" | psql -d postgres
register: result
- assert:
that:
- "result.stdout_lines[-1] == '(0 rows)'"

@ -0,0 +1,167 @@
- vars:
task_parameters: &task_parameters
become_user: "{{ pg_user }}"
become: yes
register: result
postgresql_parameters: &parameters
db: postgres
name: "{{ db_user1 }}"
login_user: "{{ pg_user }}"
block:
- name: Create a user with all role attributes
<<: *task_parameters
postgresql_user:
<<: *parameters
state: "present"
role_attr_flags: "SUPERUSER,CREATEROLE,CREATEDB,INHERIT,LOGIN{{ bypassrls_supported | ternary(',BYPASSRLS', '') }}"
no_password_changes: '{{ no_password_changes }}' # no_password_changes is ignored when user doesn't already exist
- name: Check that the user has the requested role attributes
<<: *task_parameters
shell: "echo \"select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin {{ bypassrls_supported | ternary(\", 'bypassrls:'||rolbypassrls\", '') }} from pg_roles where rolname='{{ db_user1 }}';\" | psql -d postgres"
- assert:
that:
- "result.stdout_lines[-1] == '(1 row)'"
- "'super:t' in result.stdout_lines[-2]"
- "'createrole:t' in result.stdout_lines[-2]"
- "'create:t' in result.stdout_lines[-2]"
- "'inherit:t' in result.stdout_lines[-2]"
- "'login:t' in result.stdout_lines[-2]"
- block:
- name: Check that the user has the requested role attribute BYPASSRLS
<<: *task_parameters
shell: "echo \"select 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';\" | psql -d postgres"
- assert:
that:
- "not bypassrls_supported or 'bypassrls:t' in result.stdout_lines[-2]"
when: bypassrls_supported
- name: Modify a user to have no role attributes
<<: *task_parameters
postgresql_user:
<<: *parameters
state: "present"
role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit,NOLOGIN{{ bypassrls_supported | ternary(',NOBYPASSRLS', '') }}"
no_password_changes: '{{ no_password_changes }}'
- name: Check that ansible reports it modified the role
assert:
that:
- result is changed
- name: "Check that the user doesn't have any attribute"
<<: *task_parameters
shell: "echo \"select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';\" | psql -d postgres"
- assert:
that:
- "result.stdout_lines[-1] == '(1 row)'"
- "'super:f' in result.stdout_lines[-2]"
- "'createrole:f' in result.stdout_lines[-2]"
- "'create:f' in result.stdout_lines[-2]"
- "'inherit:f' in result.stdout_lines[-2]"
- "'login:f' in result.stdout_lines[-2]"
- block:
- name: Check that the user has the requested role attribute BYPASSRLS
<<: *task_parameters
shell: "echo \"select 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';\" | psql -d postgres"
- assert:
that:
- "not bypassrls_supported or 'bypassrls:f' in result.stdout_lines[-2]"
when: bypassrls_supported
- name: Try to add an invalid attribute
<<: *task_parameters
postgresql_user:
<<: *parameters
state: "present"
role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit,NOLOGIN{{ bypassrls_supported | ternary(',NOBYPASSRLS', '') }},INVALID"
no_password_changes: '{{ no_password_changes }}'
ignore_errors: yes
- name: Check that ansible reports failure
assert:
that:
- result is not changed
- result is failed
- "result.msg == 'Invalid role_attr_flags specified: INVALID'"
- name: Modify a single role attribute on a user
<<: *task_parameters
postgresql_user:
<<: *parameters
state: "present"
role_attr_flags: "LOGIN"
no_password_changes: '{{ no_password_changes }}'
- name: Check that ansible reports it modified the role
assert:
that:
- result is changed
- name: Check the role attributes
<<: *task_parameters
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
- assert:
that:
- "result.stdout_lines[-1] == '(1 row)'"
- "'super:f' in result.stdout_lines[-2]"
- "'createrole:f' in result.stdout_lines[-2]"
- "'create:f' in result.stdout_lines[-2]"
- "'inherit:f' in result.stdout_lines[-2]"
- "'login:t' in result.stdout_lines[-2]"
- block:
- name: Check the role attribute BYPASSRLS
<<: *task_parameters
shell: echo "select 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
- assert:
that:
- "( postgres_version_resp.stdout is version('9.5.0', '<')) or 'bypassrls:f' in result.stdout_lines[-2]"
when: bypassrls_supported
- name: Check that using same attribute a second time does nothing
<<: *task_parameters
postgresql_user:
<<: *parameters
state: "present"
role_attr_flags: "LOGIN"
no_password_changes: '{{ no_password_changes }}'
environment:
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- name: Check there isn't any update reported
assert:
that:
- result is not changed
- name: Cleanup the user
<<: *task_parameters
postgresql_user:
<<: *parameters
state: 'absent'
no_password_changes: '{{ no_password_changes }}' # user deletion: no_password_changes is ignored
- name: Check that user was removed
<<: *task_parameters
shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql -d postgres
- assert:
that:
- "result.stdout_lines[-1] == '(0 rows)'"
always:
- name: Cleanup the user
<<: *task_parameters
postgresql_user:
<<: *parameters
state: 'absent'

@ -0,0 +1,336 @@
- vars:
task_parameters: &task_parameters
become_user: "{{ pg_user }}"
become: yes
register: result
postgresql_parameters: &parameters
db: postgres
name: "{{ db_user1 }}"
login_user: "{{ pg_user }}"
block:
- name: 'Check that PGOPTIONS environment variable is effective (1/2)'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: '{{ db_password1 }}'
ignore_errors: true
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- name: 'Check that PGOPTIONS environment variable is effective (2/2)'
assert:
that:
- "{{ result is failed }}"
- name: 'Create a user (password encrypted: {{ encrypted }})'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: '{{ db_password1 }}'
encrypted: '{{ encrypted }}'
environment:
PGCLIENTENCODING: 'UTF8'
- block: &changed # block is only used here in order to be able to define YAML anchor
- name: Check that ansible reports it was created
assert:
that:
- "{{ result is changed }}"
- name: Check that it was created
<<: *task_parameters
shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql -d postgres
- assert:
that:
- "result.stdout_lines[-1] == '(1 row)'"
- name: Check that creating user a second time does nothing
<<: *task_parameters
postgresql_user:
<<: *parameters
password: '{{ db_password1 }}'
encrypted: '{{ encrypted }}'
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- block: &not_changed # block is only used here in order to be able to define YAML anchor
- name: Check that ansible reports no change
assert:
that:
- "{{ result is not changed }}"
- name: 'Define an expiration time'
<<: *task_parameters
postgresql_user:
<<: *parameters
expires: '2025-01-01'
environment:
PGCLIENTENCODING: 'UTF8'
- <<: *changed
- name: 'Redefine the same expiration time'
<<: *task_parameters
postgresql_user:
expires: '2025-01-01'
<<: *parameters
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- block:
- name: 'Using MD5-hashed password: check that password not changed when using cleartext password'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: '{{ db_password1 }}'
encrypted: 'yes'
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: "Using MD5-hashed password: check that password not changed when using md5 hash with 'ENCRYPTED'"
<<: *task_parameters
postgresql_user:
<<: *parameters
password: "md5{{ (db_password1 ~ db_user1) | hash('md5')}}"
encrypted: 'yes'
environment:
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: "Using MD5-hashed password: check that password not changed when using md5 hash with 'UNENCRYPTED'"
<<: *task_parameters
postgresql_user:
<<: *parameters
password: "md5{{ (db_password1 ~ db_user1) | hash('md5')}}"
encrypted: 'no'
environment:
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: 'Redefine the same expiration time and password (encrypted)'
<<: *task_parameters
postgresql_user:
<<: *parameters
encrypted: 'yes'
password: "md5{{ (db_password1 ~ db_user1) | hash('md5')}}"
expires: '2025-01-01'
environment:
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: 'Using MD5-hashed password: check that password changed when using another cleartext password'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: 'prefix{{ db_password1 }}'
encrypted: 'yes'
environment:
PGCLIENTENCODING: 'UTF8'
- <<: *changed
- name: "Using MD5-hashed password: check that password changed when using another md5 hash with 'ENCRYPTED'"
<<: *task_parameters
postgresql_user:
<<: *parameters
password: "md5{{ ('prefix1' ~ db_password1 ~ db_user1) | hash('md5')}}"
encrypted: 'yes'
- <<: *changed
- name: "Using MD5-hashed password: check that password changed when using md5 hash with 'UNENCRYPTED'"
<<: *task_parameters
postgresql_user:
<<: *parameters
password: "md5{{ ('prefix2' ~ db_password1 ~ db_user1) | hash('md5')}}"
encrypted: 'no'
register: change_pass_unencrypted
failed_when:
- change_pass_unencrypted is failed
# newer version of psycopg2 no longer supported unencrypted password, we ignore the error
- '"UNENCRYPTED PASSWORD is no longer supported" not in change_pass_unencrypted.msg'
- <<: *changed
- name: 'Using MD5-hashed password: check that password changed when clearing the password'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: ''
encrypted: 'yes'
environment:
PGCLIENTENCODING: 'UTF8'
- <<: *changed
- name: 'Using MD5-hashed password: check that password not changed when clearing the password again'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: ''
encrypted: 'yes'
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: 'Using cleartext password: check that password not changed when clearing the password again'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: ''
encrypted: 'no'
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: 'Using MD5-hashed password: check that password changed when using a cleartext password'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: '{{ db_password1 }}'
encrypted: 'yes'
environment:
PGCLIENTENCODING: 'UTF8'
- <<: *changed
when: encrypted == 'yes'
- block:
- name: 'Using cleartext password: check that password not changed when using cleartext password'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: "{{ db_password1 }}"
encrypted: 'no'
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: 'Redefine the same expiration time and password (not encrypted)'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: "{{ db_password1 }}"
encrypted: 'no'
expires: '2025-01-01'
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: 'Using cleartext password: check that password changed when using another cleartext password'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: "changed{{ db_password1 }}"
encrypted: 'no'
environment:
PGCLIENTENCODING: 'UTF8'
- <<: *changed
- name: 'Using cleartext password: check that password changed when clearing the password'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: ''
encrypted: 'no'
environment:
PGCLIENTENCODING: 'UTF8'
- <<: *changed
- name: 'Using cleartext password: check that password not changed when clearing the password again'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: ''
encrypted: 'no'
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: 'Using MD5-hashed password: check that password not changed when clearing the password again'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: ''
encrypted: 'yes'
environment:
PGCLIENTENCODING: 'UTF8'
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
- name: 'Using cleartext password: check that password changed when using cleartext password'
<<: *task_parameters
postgresql_user:
<<: *parameters
password: "{{ db_password1 }}"
encrypted: 'no'
environment:
PGCLIENTENCODING: 'UTF8'
- <<: *changed
when: encrypted == 'no'
- name: Remove user
<<: *task_parameters
postgresql_user:
state: 'absent'
<<: *parameters
- <<: *changed
- name: Check that they were removed
<<: *task_parameters
shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql -d postgres
environment:
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- assert:
that:
- "result.stdout_lines[-1] == '(0 rows)'"
- name: Check that removing user a second time does nothing
<<: *task_parameters
postgresql_user:
state: 'absent'
<<: *parameters
environment:
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
- <<: *not_changed
always:
- name: Remove user
<<: *task_parameters
postgresql_user:
state: 'absent'
<<: *parameters

@ -0,0 +1,3 @@
needs/root
shippable/posix/incidental
skip/aix

@ -0,0 +1,36 @@
# (c) 2017, Sam Doran <sdoran@redhat.com>
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
- debug:
msg: SELinux is disabled
when: ansible_selinux is defined and ansible_selinux == False
- debug:
msg: SELinux is {{ ansible_selinux.status }}
when: ansible_selinux is defined and ansible_selinux != False
- include: selinux.yml
when:
- ansible_selinux is defined
- ansible_selinux != False
- ansible_selinux.status == 'enabled'
- include: selogin.yml
when:
- ansible_selinux is defined
- ansible_selinux != False
- ansible_selinux.status == 'enabled'

@ -0,0 +1,364 @@
# (c) 2017, Sam Doran <sdoran@redhat.com>
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# First Test
# ##############################################################################
# Test changing the state, which requires a reboot
- name: TEST 1 | Get current SELinux config file contents
set_fact:
selinux_config_original: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}"
before_test_sestatus: "{{ ansible_selinux }}"
- debug:
var: "{{ item }}"
verbosity: 1
with_items:
- selinux_config_original
- before_test_sestatus
- ansible_selinux
- name: TEST 1 | Setup SELinux configuration for tests
selinux:
state: enforcing
policy: targeted
- name: TEST 1 | Disable SELinux
selinux:
state: disabled
policy: targeted
register: _disable_test1
- debug:
var: _disable_test1
verbosity: 1
- name: TEST 1 | Re-gather facts
setup:
- name: TEST 1 | Assert that status was changed, reboot_required is True, a warning was displayed, and SELinux is configured properly
assert:
that:
- _disable_test1 is changed
- _disable_test1.reboot_required
- (_disable_test1.warnings | length ) >= 1
- ansible_selinux.config_mode == 'disabled'
- ansible_selinux.type == 'targeted'
- debug:
var: ansible_selinux
verbosity: 1
- name: TEST 1 | Disable SELinux again
selinux:
state: disabled
policy: targeted
register: _disable_test2
- debug:
var: _disable_test2
verbosity: 1
- name: TEST 1 | Assert that no change is reported, a warnking was dispalyed, and reboot_required is True
assert:
that:
- _disable_test2 is not changed
- (_disable_test1.warnings | length ) >= 1
- _disable_test2.reboot_required
- name: TEST 1 | Get modified config file
set_fact:
selinux_config_after: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}"
- debug:
var: selinux_config_after
verbosity: 1
- name: TEST 1 | Ensure SELinux config file is properly formatted
assert:
that:
- selinux_config_original | length == selinux_config_after | length
- selinux_config_after[selinux_config_after.index('SELINUX=disabled')] is search("^SELINUX=\w+$")
- selinux_config_after[selinux_config_after.index('SELINUXTYPE=targeted')] is search("^SELINUXTYPE=\w+$")
- name: TEST 1 | Reset SELinux configuration for next test
selinux:
state: enforcing
policy: targeted
# Second Test
# ##############################################################################
# Test changing only the policy, which does not require a reboot
- name: TEST 2 | Make sure the policy is present
package:
name: selinux-policy-mls
state: present
- name: TEST 2 | Set SELinux policy
selinux:
state: enforcing
policy: mls
register: _state_test1
- debug:
var: _state_test1
verbosity: 1
- name: TEST 2 | Re-gather facts
setup:
- debug:
var: ansible_selinux
tags: debug
- name: TEST 2 | Assert that status was changed, reboot_required is False, no warnings were displayed, and SELinux is configured properly
assert:
that:
- _state_test1 is changed
- not _state_test1.reboot_required
- _state_test1.warnings is not defined
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'mls'
- name: TEST 2 | Set SELinux policy again
selinux:
state: enforcing
policy: mls
register: _state_test2
- debug:
var: _state_test2
verbosity: 1
- name: TEST 2 | Assert that no change was reported, no warnings were dispalyed, and reboot_required is False
assert:
that:
- _state_test2 is not changed
- _state_test2.warnings is not defined
- not _state_test2.reboot_required
- name: TEST 2 | Get modified config file
set_fact:
selinux_config_after: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}"
- debug:
var: selinux_config_after
verbosity: 1
- name: TEST 2 | Ensure SELinux config file is properly formatted
assert:
that:
- selinux_config_original | length == selinux_config_after | length
- selinux_config_after[selinux_config_after.index('SELINUX=enforcing')] is search("^SELINUX=\w+$")
- selinux_config_after[selinux_config_after.index('SELINUXTYPE=mls')] is search("^SELINUXTYPE=\w+$")
- name: TEST 2 | Reset SELinux configuration for next test
selinux:
state: enforcing
policy: targeted
# Third Test
# ##############################################################################
# Test changing non-existing policy
- name: TEST 3 | Set SELinux policy
selinux:
state: enforcing
policy: non-existing-selinux-policy
register: _state_test1
ignore_errors: yes
- debug:
var: _state_test1
verbosity: 1
- name: TEST 3 | Re-gather facts
setup:
- debug:
var: ansible_selinux
tags: debug
- name: TEST 3 | Assert that status was not changed, the task failed, the msg contains proper information and SELinux was not changed
assert:
that:
- _state_test1 is not changed
- _state_test1 is failed
- _state_test1.msg == 'Policy non-existing-selinux-policy does not exist in /etc/selinux/'
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'targeted'
# Fourth Test
# ##############################################################################
# Test if check mode returns correct changed values and
# doesn't make any changes
- name: TEST 4 | Set SELinux to enforcing
selinux:
state: enforcing
policy: targeted
register: _check_mode_test1
- debug:
var: _check_mode_test1
verbosity: 1
- name: TEST 4 | Set SELinux to enforcing in check mode
selinux:
state: enforcing
policy: targeted
register: _check_mode_test1
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that check mode is idempotent
assert:
that:
- _check_mode_test1 is success
- not _check_mode_test1.reboot_required
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'targeted'
- name: TEST 4 | Set SELinux to permissive in check mode
selinux:
state: permissive
policy: targeted
register: _check_mode_test2
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that check mode doesn't set state permissive and returns changed
assert:
that:
- _check_mode_test2 is changed
- not _check_mode_test2.reboot_required
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'targeted'
- name: TEST 4 | Disable SELinux in check mode
selinux:
state: disabled
register: _check_mode_test3
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that check mode didn't change anything, status is changed, reboot_required is True, a warning was displayed
assert:
that:
- _check_mode_test3 is changed
- _check_mode_test3.reboot_required
- (_check_mode_test3.warnings | length ) >= 1
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'targeted'
- name: TEST 4 | Set SELinux to permissive
selinux:
state: permissive
policy: targeted
register: _check_mode_test4
- debug:
var: _check_mode_test4
verbosity: 1
- name: TEST 4 | Disable SELinux in check mode
selinux:
state: disabled
register: _check_mode_test4
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that check mode didn't change anything, status is changed, reboot_required is True, a warning was displayed
assert:
that:
- _check_mode_test4 is changed
- _check_mode_test4.reboot_required
- (_check_mode_test3.warnings | length ) >= 1
- ansible_selinux.config_mode == 'permissive'
- ansible_selinux.type == 'targeted'
- name: TEST 4 | Set SELinux to enforcing
selinux:
state: enforcing
policy: targeted
register: _check_mode_test5
- debug:
var: _check_mode_test5
verbosity: 1
- name: TEST 4 | Disable SELinux
selinux:
state: disabled
register: _check_mode_test5
- name: TEST 4 | Disable SELinux in check mode
selinux:
state: disabled
register: _check_mode_test5
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that in check mode status was not changed, reboot_required is True, a warning was displayed, and SELinux is configured properly
assert:
that:
- _check_mode_test5 is success
- _check_mode_test5.reboot_required
- (_check_mode_test5.warnings | length ) >= 1
- ansible_selinux.config_mode == 'disabled'
- ansible_selinux.type == 'targeted'

@ -0,0 +1,81 @@
---
- name: create user for testing
user:
name: seuser
- name: attempt to add mapping without 'seuser'
selogin:
login: seuser
register: selogin_error
ignore_errors: yes
- name: verify failure
assert:
that:
- selogin_error is failed
- name: map login to SELinux user
selogin:
login: seuser
seuser: staff_u
register: selogin_new_mapping
check_mode: "{{ item }}"
with_items:
- yes
- no
- yes
- no
- name: new mapping- verify functionality and check_mode
assert:
that:
- selogin_new_mapping.results[0] is changed
- selogin_new_mapping.results[1] is changed
- selogin_new_mapping.results[2] is not changed
- selogin_new_mapping.results[3] is not changed
- name: change SELinux user login mapping
selogin:
login: seuser
seuser: user_u
register: selogin_mod_mapping
check_mode: "{{ item }}"
with_items:
- yes
- no
- yes
- no
- name: changed mapping- verify functionality and check_mode
assert:
that:
- selogin_mod_mapping.results[0] is changed
- selogin_mod_mapping.results[1] is changed
- selogin_mod_mapping.results[2] is not changed
- selogin_mod_mapping.results[3] is not changed
- name: remove SELinux user mapping
selogin:
login: seuser
state: absent
register: selogin_del_mapping
check_mode: "{{ item }}"
with_items:
- yes
- no
- yes
- no
- name: delete mapping- verify functionality and check_mode
assert:
that:
- selogin_del_mapping.results[0] is changed
- selogin_del_mapping.results[1] is changed
- selogin_del_mapping.results[2] is not changed
- selogin_del_mapping.results[3] is not changed
- name: remove test user
user:
name: seuser
state: absent

@ -0,0 +1,16 @@
docker_cli_version: '0.0'
docker_api_version: '0.0'
docker_py_version: '0.0'
docker_skip_cleanup: no
docker_prereq_packages: []
docker_packages:
- docker-ce
docker_pip_extra_packages: []
docker_pip_packages:
- docker
docker_cleanup_packages:
- docker
- docker-ce
- docker-ce-cli

@ -0,0 +1,14 @@
- name: remove pip packages
pip:
state: present
name: "{{ docker_pip_packages | union(docker_pip_extra_packages) }}"
listen: cleanup docker
when: not docker_skip_cleanup | bool
- name: remove docker pagkages
action: "{{ ansible_facts.pkg_mgr }}"
args:
name: "{{ docker_cleanup_packages }}"
state: absent
listen: cleanup docker
when: not docker_skip_cleanup | bool

@ -0,0 +1,2 @@
dependencies:
- setup_remote_constraints

@ -0,0 +1,43 @@
- name: Get OS version
shell: uname -r
register: os_version
- name: Install pre-reqs
apt:
name: "{{ docker_prereq_packages }}"
state: present
update_cache: yes
notify: cleanup docker
- name: Add gpg key
shell: curl -fsSL https://download.docker.com/linux/ubuntu/gpg >key && apt-key add key
- name: Add Docker repo
shell: add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- block:
- name: Prevent service restart
copy:
content: exit 101
dest: /usr/sbin/policy-rc.d
backup: yes
mode: 0755
register: policy_rc_d
- name: Install Docker CE
apt:
name: "{{ docker_packages }}"
state: present
update_cache: yes
always:
- name: Restore /usr/sbin/policy-rc.d (if needed)
command: mv {{ policy_rc_d.backup_file }} /usr/sbin/policy-rc.d
when:
- "'backup_file' in policy_rc_d"
- name: Remove /usr/sbin/policy-rc.d (if needed)
file:
path: /usr/sbin/policy-rc.d
state: absent
when:
- "'backup_file' not in policy_rc_d"

@ -0,0 +1,21 @@
- name: Add repository
yum_repository:
file: docker-ce
name: docker-ce-stable
description: Docker CE Stable - $basearch
baseurl: https://download.docker.com/linux/fedora/$releasever/$basearch/stable
enabled: yes
gpgcheck: yes
gpgkey: https://download.docker.com/linux/fedora/gpg
- name: Update cache
command: dnf makecache
args:
warn: no
- name: Install docker
dnf:
name: "{{ docker_packages }}"
state: present
enablerepo: docker-ce-test
notify: cleanup docker

@ -0,0 +1,39 @@
# The RHEL extras repository must be enabled to provide the container-selinux package.
# See: https://docs.docker.com/engine/installation/linux/docker-ee/rhel/#install-using-the-repository
- name: Install Docker pre-reqs
yum:
name: "{{ docker_prereq_packages }}"
state: present
notify: cleanup docker
- name: Install epel repo which is missing on rhel-7 and is needed for pigz (needed for docker-ce 18)
include_role:
name: setup_epel
- name: Enable extras repository for RHEL on AWS
command: yum-config-manager --enable rhui-REGION-rhel-server-extras
args:
warn: no
- name: Add repository
command: yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
args:
warn: no
- name: Update cache
command: yum -y makecache fast
args:
warn: no
- name: Install docker
yum:
name: "{{ docker_packages }}"
state: present
notify: cleanup docker
- name: Make sure the docker daemon is running (failure expected inside docker container)
service:
name: docker
state: started
ignore_errors: "{{ ansible_virtualization_type == 'docker' }}"

@ -0,0 +1,29 @@
# The RHEL extras repository must be enabled to provide the container-selinux package.
# See: https://docs.docker.com/engine/installation/linux/docker-ee/rhel/#install-using-the-repository
- name: Install Docker pre-reqs
dnf:
name: "{{ docker_prereq_packages }}"
state: present
notify: cleanup docker
register: result
until: result is success
retries: 10
delay: 2
- name: Set-up repository
command: dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
args:
warn: no
- name: Install docker
dnf:
name: "{{ docker_packages }}"
state: present
notify: cleanup docker
- name: Make sure the docker daemon is running (failure expected inside docker container)
service:
name: docker
state: started
ignore_errors: "{{ ansible_virtualization_type == 'docker' }}"

@ -0,0 +1,7 @@
- name: Install docker 17
zypper:
name: "{{ docker_packages }}"
force: yes
disable_gpg_check: yes
update_cache: yes
notify: cleanup docker

@ -0,0 +1,113 @@
- name: Setup Docker
when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
block:
- name: Include distribution specific variables
include_vars: "{{ lookup('first_found', params) }}"
vars:
params:
files:
- "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.distribution }}.yml"
- "{{ ansible_facts.os_family }}.yml"
- default.yml
paths:
- "{{ role_path }}/vars"
- name: Include distribution specific tasks
include_tasks: "{{ lookup('first_found', params) }}"
vars:
params:
files:
- "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.distribution }}.yml"
- "{{ ansible_facts.os_family }}.yml"
paths:
- "{{ role_path }}/tasks"
- name: Install Python requirements
pip:
state: present
name: "{{ docker_pip_packages | union(docker_pip_extra_packages) }}"
extra_args: "-c {{ remote_constraints }}"
notify: cleanup docker
# Detect docker CLI, API and docker-py versions
- name: Check Docker CLI version
command: "docker version -f {% raw %}'{{.Client.Version}}'{% endraw %}"
register: docker_cli_version_stdout
ignore_errors: yes
- name: Check Docker API version
command: "{{ ansible_python.executable }} -c 'import docker; print(docker.from_env().version()[\"ApiVersion\"])'"
register: docker_api_version_stdout
ignore_errors: yes
- name: Check docker-py API version
command: "{{ ansible_python.executable }} -c 'import docker; print(docker.__version__)'"
register: docker_py_version_stdout
ignore_errors: yes
- set_fact:
docker_cli_version: "{{ docker_cli_version_stdout.stdout | default('0.0') }}"
docker_api_version: "{{ docker_api_version_stdout.stdout | default('0.0') }}"
docker_py_version: "{{ docker_py_version_stdout.stdout | default('0.0') }}"
- debug:
msg: "Docker CLI version: {{ docker_cli_version }}; Docker API version: {{ docker_api_version }}; docker-py library version: {{ docker_py_version }}"
- block:
# Cleanup docker daemon
- name: "Remove all ansible-test-* docker containers"
shell: 'docker ps --no-trunc --format {% raw %}"{{.Names}}"{% endraw %} | grep "^ansible-test-" | xargs -r docker rm -f'
register: docker_containers
retries: 3
delay: 3
until: docker_containers is success
- name: "Remove all ansible-test-* docker volumes"
shell: 'docker volume ls --format {% raw %}"{{.Name}}"{% endraw %} | grep "^ansible-test-" | xargs -r docker volume rm -f'
register: docker_volumes
- name: "Remove all ansible-test-* docker networks"
shell: 'docker network ls --no-trunc --format {% raw %}"{{.Name}}"{% endraw %} | grep "^ansible-test-" | xargs -r docker network rm'
register: docker_networks
- name: Cleaned docker resources
debug:
var: docker_resources
vars:
docker_resources:
containers: "{{ docker_containers.stdout_lines }}"
volumes: "{{ docker_volumes.stdout_lines }}"
networks: "{{ docker_networks.stdout_lines }}"
# List all existing docker resources
- name: List all docker containers
command: docker ps --no-trunc -a
register: docker_containers
- name: List all docker volumes
command: docker volume ls
register: docker_volumes
- name: List all docker networks
command: docker network ls --no-trunc
register: docker_networks
- name: List all docker images
command: docker images --no-trunc -a
register: docker_images
- name: Still existing docker resources
debug:
var: docker_resources
vars:
docker_resources:
containers: "{{ docker_containers.stdout_lines }}"
volumes: "{{ docker_volumes.stdout_lines }}"
networks: "{{ docker_networks.stdout_lines }}"
images: "{{ docker_images.stdout_lines }}"
when: docker_cli_version is version('0.0', '>')

@ -0,0 +1,5 @@
docker_prereq_packages:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common

@ -0,0 +1,4 @@
docker_prereq_packages: []
docker_packages:
- docker-ce

@ -0,0 +1,8 @@
docker_prereq_packages:
- yum-utils
- device-mapper-persistent-data
- lvm2
- libseccomp
docker_pip_extra_packages:
- requests==2.6.0

@ -0,0 +1,9 @@
docker_prereq_packages:
- yum-utils
- device-mapper-persistent-data
- lvm2
- libseccomp
# Docker CE > 3:18.09.1 requires containerd.io >= 1.2.2-3 which is unavaible at this time
docker_packages:
- docker-ce-3:18.09.1

@ -0,0 +1,5 @@
docker_pip_extra_packages:
# Installing requests >=2.12.0 on Ubuntu 14.04 breaks certificate validation. We restrict to an older version
# to ensure out get_url tests work out fine. This is only an issue if pyOpenSSL is also installed.
# Not sure why RHEL7 needs this specific version
- requests==2.6.0

@ -0,0 +1,138 @@
# Create a dummy flatpak repository remote
This document describes how to create a local flatpak dummy repo. Just like the one contained in the `files/repo.tar.gxz` archive.
## Create a hello world app
Prerequisites:
- flathub
Prepare the environment:
```
flatpak install --system flathub org.freedesktop.Platform//1.6 org.freedesktop.Sdk//1.6
```
Create a hello world executable:
```
echo $'#!/bin/sh\necho hello world' > hello.sh
```
To create dummy flatpaks, run this (defining a unique NUM for every flatpak to add):
```
export NUM=1
flatpak build-init appdir$NUM com.dummy.App$NUM org.freedesktop.Sdk org.freedesktop.Platform 1.6;
flatpak build appdir$NUM mkdir /app/bin;
flatpak build appdir$NUM install --mode=750 hello.sh /app/bin;
flatpak build-finish --command=hello.sh appdir$NUM
```
## Create a repo and/or add the app to it
Create a repo and add the file to it in one command:
```
flatpak build-export repo appdir$NUM stable
```
## Create flatpak*-files
Put a flatpakref file under the repo folder (`repo/com.dummy.App1.flatpakref`):
```
[Flatpak Ref]
Title=Dummy App$NUM
Name=com.dummy.App$NUM
Branch=stable
Url=file:///tmp/flatpak/repo
GPGKey={{ base64-encoded public KEY }}
IsRuntime=false
RuntimeRepo=https://flathub.org/repo/flathub.flatpakrepo
```
Add a `.flatpakrepo` file to the `repo` folder (`repo/dummy-repo.flatpakrepo`):
```
[Flatpak Repo]
Title=Dummy Repo
Url=file:///tmp/flatpak/repo
Comment=Dummy repo for ansible module integration testing
Description=Dummy repo for ansible module integration testing
GPGKey={{ base64-encoded public KEY }}
```
## Sign the repo
Create a new key in a new gpg home folder (On RedHat systems, the executable needs to addressed as gpg2):
```
mkdir gpg
gpg --homedir gpg --quick-gen-key test@dummy.com
```
Sign the repo and summary file, you need to redo this when you update the repository:
```
flatpak build-sign repo --gpg-sign=KEY_ID --gpg-homedir=gpg
flatpak build-update-repo repo --gpg-sign=KEY_ID --gpg-homedir=gpg
```
Export the public key as a file:
```
gpg --homedir=gpg --export KEY_ID > dummy-repo.gpg
```
Create base64-encoded string from gpg-file for `GPGKey=` property in flatpak*-files:
```
base64 dummy-repo.gpg | tr -d '\n'
```
## How to use the repo
Now you can add the `repo` folder as a local repo:
```
flatpak --system remote-add --gpg-import=/tmp/flatpak/repo/dummy-repo.gpg dummy-repo /tmp/flatpak/repo
```
Or, via `.flatpakrepo` file:
```
flatpak --system remote-add dummy-repo /tmp/flatpak/repo/dummy-repo.flatpakrepo
```
And install the hello world flatpaks like this:
```
flatpak --system install dummy-repo com.dummy.App$NUM
```
Or from flatpakref:
```
flatpak --system install --from /tmp/flatpak/repo/com.dummy.App$NUM.flatpakref
```
Run the app:
```
flatpak run com.dummy.App$NUM
```
To install an app without any runtime dependencies (the app will be broken, but it is enough to test flatpak installation):
```
flatpak --system install --no-deps dummy-repo com.dummy.App$NUM
```
## Sources:
* https://blogs.gnome.org/alexl/2017/02/10/maintaining-a-flatpak-repository/
* http://docs.flatpak.org/en/latest/first-build.html

@ -0,0 +1,4 @@
- name: remove temporary flatpak link
file:
state: absent
path: /tmp/flatpak

@ -0,0 +1,22 @@
- name: Set up dummy flatpak repository remote
block:
- name: Copy repo into place
unarchive:
src: repo.tar.xz
dest: "{{ remote_tmp_dir }}"
owner: root
group: root
mode: 0644
- name: Create deterministic link to temp directory
file:
state: link
src: "{{ remote_tmp_dir }}/"
path: "/tmp/flatpak"
owner: root
group: root
mode: 0644
notify: remove temporary flatpak link
become: true

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save