mirror of
https://gitea.com/mcereda/oam.git
synced 2026-02-09 05:44:23 +00:00
681 lines
25 KiB
YAML
681 lines
25 KiB
YAML
---
|
|
|
|
- name: Debug tasks
|
|
block:
|
|
- ansible.builtin.debug:
|
|
msg: I always display!
|
|
- ansible.builtin.debug:
|
|
msg: I only display with 'ansible-playbook -vvv' or with more 'v's
|
|
verbosity: 3
|
|
- debugger: on_failed
|
|
ansible.builtin.fail:
|
|
msg: Manual, enforced failure
|
|
# print all variables at this point => p task_vars
|
|
# continue => c
|
|
# abort and quit => q
|
|
|
|
- name: Flush handlers
|
|
ansible.builtin.meta: flush_handlers
|
|
|
|
- name: Retry tasks
|
|
ansible.builtin.command: /usr/bin/false
|
|
retries: 3
|
|
delay: 3
|
|
register: command_result
|
|
until: command_result is not failed
|
|
|
|
- name: Run tasks locally
|
|
delegate_to: 127.0.0.1 # 'localhost' works too
|
|
ansible.builtin.command: hostname
|
|
|
|
- name: Assertions
|
|
vars:
|
|
installation_method: package
|
|
url: https://www.google.com/
|
|
ansible.builtin.assert:
|
|
that:
|
|
- installation_method in ['container', 'package']
|
|
- "'https://www.google.com/' is ansible.builtin.url"
|
|
- "'domain.example.com' is community.general.fqdn_valid(min_labels=2)"
|
|
- url is regex('\w\.com/')
|
|
fail_msg: What to say if any of the above conditions fail
|
|
success_msg: What to say if all of the above conditions succeed
|
|
|
|
- name: Test types
|
|
ansible.builtin.assert:
|
|
that:
|
|
# strings are classified as 'string', 'iterable' and 'sequence', but not 'mapping'
|
|
- "'aa' is string"
|
|
- "'aa' is iterable"
|
|
- "'aa' is sequence"
|
|
# numbers are classified as 'numbers', with 'integer' and 'float' being subclasses
|
|
- 42 is number and 5 is integer
|
|
- 21.34 is number and 12.1 is float
|
|
# lists are classified as 'iterable' and 'sequence', but not as 'string' nor 'mapping'
|
|
- "['list'] is iterable"
|
|
- "['list'] is sequence"
|
|
# dictionaries are classified as 'iterable', 'sequence' and 'mapping', but not as 'string'
|
|
- "{'a': 'dict'} is iterable"
|
|
- "{'a': 'dict'} is sequence"
|
|
- "{'a': 'dict'} is mapping"
|
|
# native booleans
|
|
- true is boolean
|
|
- True is boolean
|
|
- false is boolean
|
|
- False is boolean
|
|
|
|
- name: Type conversion
|
|
ansible.builtin.assert:
|
|
that:
|
|
- "'string' | int is integer"
|
|
- "'string' | float is float"
|
|
- 12 | float is float
|
|
- 21.02 | int is integer
|
|
- 43 | string is string
|
|
- 74.93 | string is string
|
|
- 4 | bool is boolean
|
|
|
|
- name: Elvis operator
|
|
# (condition) | bool | ternary(value_for_true_condition, value_for_false_condition, optional_value_for_null_condition)
|
|
ansible.builtin.set_fact:
|
|
acme_directory: >-
|
|
{{
|
|
this_is_a_test_run
|
|
| default(true)
|
|
| bool
|
|
| ternary(
|
|
'https://acme-staging-v02.api.letsencrypt.org/directory',
|
|
'https://acme-v02.api.letsencrypt.org/directory'
|
|
)
|
|
}}
|
|
|
|
- name: Create directories recursively
|
|
ansible.builtin.file:
|
|
path: /tmp/path/to/final/dir
|
|
state: directory
|
|
|
|
- name: Define files content in tasks
|
|
ansible.builtin.copy:
|
|
dest: "{{ ansible_user_dir }}/.tmux.conf"
|
|
mode: u=rw,go=r
|
|
content: |
|
|
…
|
|
|
|
- name: Show input data type
|
|
ansible.builtin.set_fact:
|
|
should_be_string: "{{ 'this' | type_debug }}"
|
|
|
|
- name: Pretty print information
|
|
ansible.builtin.debug:
|
|
msg: >-
|
|
{{
|
|
dict([
|
|
[ 'install_method', install_method ],
|
|
[ 'install_method in supported_install_methods', install_method in supported_install_methods ],
|
|
])
|
|
}}
|
|
|
|
- name: Use filters
|
|
tags: filter
|
|
ansible.builtin.set_fact:
|
|
path_list_of_all_txt_files_in_dir: "{{ lookup('ansible.builtin.fileglob', '/my/path/*.txt') }}"
|
|
|
|
- name: Import tasks
|
|
block:
|
|
- name: By using absolute paths and special variables (preferred)
|
|
ansible.builtin.import_tasks:
|
|
file: "{{ role_path }}/tasks/install/{{ install_method }}.yml"
|
|
- name: By using paths relative to the including file
|
|
ansible.builtin.import_tasks:
|
|
file: pre-flight.yml
|
|
|
|
- name: Conditionally include tasks
|
|
block:
|
|
- name: by leveraging the 'with_fileglob' loop filter (preferred)
|
|
ansible.builtin.include_tasks:
|
|
file: "{{ item }}"
|
|
with_fileglob: "{{ install_method }}.yml"
|
|
- name: by checking the files' existence
|
|
vars:
|
|
filename: "{{ install_method }}.yml"
|
|
when: lookup('ansible.builtin.fileglob', filename) != []
|
|
ansible.builtin.import_tasks:
|
|
file: "{{ filename }}"
|
|
|
|
- name: Generate passwords
|
|
block:
|
|
- name: Randomly
|
|
ansible.builtin.debug:
|
|
msg: "{{ lookup('ansible.builtin.password', '/dev/null') }}"
|
|
- name: Specifying requirements
|
|
ansible.builtin.debug:
|
|
msg: "{{ lookup('ansible.builtin.password', '/dev/null length=32 chars=ascii_letters,digits,punctuation') }}"
|
|
- name: Random but idempotent, so it will not change at every execution
|
|
ansible.builtin.debug:
|
|
msg: "{{ lookup('ansible.builtin.password', '/dev/null', seed=inventory_hostname) }}"
|
|
|
|
- name: Add repositories
|
|
block:
|
|
- name: DNF/YUM
|
|
ansible.builtin.yum_repository:
|
|
name: epel
|
|
description: EPEL YUM repo
|
|
baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
|
|
|
|
- name: Install packages
|
|
block:
|
|
- name: Generic module
|
|
ansible.builtin.package:
|
|
name:
|
|
- tmux
|
|
- screen
|
|
- name: Via PIP
|
|
ansible.builtin.pip:
|
|
name:
|
|
- bottle
|
|
- django>1.11.0,<1.12.0
|
|
- svn+http://myrepo/svn/MyApp#egg=MyApp
|
|
- git+http://myrepo/app/MyApp
|
|
- file:///path/to/MyApp.tar.gz
|
|
|
|
- name: Run containers
|
|
block:
|
|
- name: Directly
|
|
community.docker.docker_container:
|
|
name: gitlab
|
|
image: gitlab/gitlab-ce:16.11.2-ce.0
|
|
hostname: gitlab.lan
|
|
published_ports:
|
|
- "8022:22"
|
|
- "8080:80"
|
|
- "8443:443"
|
|
env:
|
|
GITLAB_OMNIBUS_CONFIG: >-
|
|
external_url 'http://gitlab.lan';
|
|
shm_size: 256m
|
|
volumes:
|
|
- ./config:/etc/gitlab:Z
|
|
- ./logs:/var/log/gitlab:Z
|
|
- ./data:/var/opt/gitlab:Z
|
|
auto_remove: true
|
|
- name: With Compose
|
|
community.docker.docker_compose_v2:
|
|
project_src: /home/user/flask
|
|
|
|
- name: Manipulate strings
|
|
ansible.builtin.set_fact:
|
|
string_with_first_letter_to_uppercase: "{{ 'all_lowercase' | capitalize }}"
|
|
string_with_something_replaced: "{{ 'dots.to.dashes' | replace('.','-') }}"
|
|
split_string: "{{ 'testMe@example.com' | split('@') | first }}"
|
|
string_with_pattern_replaced: >-
|
|
{{ '*.domain.com...' | regex_replace('*' | regex_escape, 'star') | regex_replace('\.+$', '') }}
|
|
|
|
- name: Manipulate lists
|
|
block:
|
|
- name: Add elements to lists
|
|
vars:
|
|
programming_languages:
|
|
- C
|
|
- Python
|
|
ansible.builtin.set_fact:
|
|
programming_languages: "{{ programming_languages + ['Ruby'] }}"
|
|
- name: Remove elements from lists
|
|
vars:
|
|
dbs_list: ['primary', 'sales']
|
|
ansible.builtin.set_fact:
|
|
list_without_items: "{{ dbs_list | difference(['template0','template1','postgres','rdsadmin']) }}"
|
|
- name: Get a random element
|
|
ansible.builtin.set_fact:
|
|
random_item: "{{ ['a','b','c'] | random }}"
|
|
- name: Sort dict elements in list by attribute
|
|
tags: order_by
|
|
vars:
|
|
snapshots:
|
|
- name: sales
|
|
create_time: '2024-06-25T00:52:55.127000+00:00'
|
|
- name: test
|
|
create_time: '2024-05-17T01:53:12.103220+00:00'
|
|
ansible.builtin.set_fact:
|
|
snapshot_latest: "{{ snapshots | sort(attribute='create_time') | last }}"
|
|
- name: Give back the first not null value (coalesce-like)
|
|
vars:
|
|
list_with_null_values:
|
|
- null
|
|
- null
|
|
- something
|
|
- something else
|
|
ansible.builtin.set_fact:
|
|
first_non_null_value: "{{ list_with_null_values | select | first }}"
|
|
- name: Get values for a specific attribute in a list of dictionaries
|
|
ansible.builtin.set_fact:
|
|
vpc_security_group_ids: >-
|
|
{{ instance_information.vpc_security_groups | map(attribute='vpc_security_group_id') }}
|
|
volume_ids: "{{ instances_information.instances[0].block_device_mappings | map(attribute='ebs.volume_id') }}"
|
|
- name: Return only elements with specific attributes matching a filter
|
|
ansible.builtin.set_fact:
|
|
available_rds_snapshots: "{{ snapshots_list | selectattr('status', 'equalto', 'available') }}"
|
|
mounts_with_path: "{{ ansible_facts.mounts | selectattr('mount', 'in', path) }}"
|
|
- name: Return all elements *but* the ones with specific attributes matching a filter
|
|
ansible.builtin.set_fact:
|
|
available_rds_snapshots: "{{ snapshots_list | rejectattr('status', 'equalto', 'creating') }}"
|
|
mounts_without_path: "{{ ansible_facts.mounts | rejectattr('mount', 'in', path) }}"
|
|
- name: Remove lines about RDS protected users and permissions from a dump file
|
|
# remove empty lines
|
|
# remove comments
|
|
# remove creation of the master user
|
|
# remove anything involving 'rdsadmin'
|
|
# remove changes to protected RDS users
|
|
# remove protected 'superuser' and 'replication' assignments
|
|
vars:
|
|
# **Hack notice**: Ansible has issues with splitting on new lines if this template is quoted differently
|
|
permissions_dump_content_as_lines: "{{ dump_file.content | ansible.builtin.b64decode | split('\n') }}"
|
|
master_username: postgresql
|
|
ansible.builtin.set_fact:
|
|
permissions_commands: >-
|
|
{{
|
|
permissions_dump_content_as_lines
|
|
| reject('match', '^$')
|
|
| reject('match', '^--')
|
|
| reject('match', '^CREATE ROLE ' + master_username)
|
|
| reject('match', '.*rdsadmin.*')
|
|
| reject('match', '^(CREATE|ALTER) ROLE rds_')
|
|
| map('regex_replace', '(NO)(SUPERUSER|REPLICATION)\s?', '')
|
|
}}
|
|
|
|
- name: Manipulate dictionaries
|
|
vars:
|
|
organization:
|
|
address: 123 common lane
|
|
id: 123abc
|
|
block:
|
|
- name: Add keys to dictionaries
|
|
ansible.builtin.set_fact:
|
|
organization: "{{ organization | combine({ 'name': 'ExampleOrg' }) }}"
|
|
- name: Sort keys in dictionaries
|
|
ansible.builtin.set_fact:
|
|
organization: "{{ organization | dictsort }}"
|
|
- name: Pretty print dictionaries
|
|
ansible.builtin.set_fact:
|
|
organization: "{{ organization | to_nice_json }}"
|
|
- name: Merge dictionaries
|
|
vars:
|
|
dict_1:
|
|
a: 43
|
|
b: some string
|
|
dict_2:
|
|
y: true
|
|
z:
|
|
- 4
|
|
- test
|
|
ansible.builtin.set_fact:
|
|
merged_dict: "{{ dict1 | ansible.builtin.combine(dict_2, {'z':'new_value','w':[44]}) }}"
|
|
recursively_merged_dict: >-
|
|
{{ {'rest':'test'} | ansible.builtin.combine({'z':'new_value','w':[44]}, dict_1, dict_2, recursive=true) }}
|
|
- name: Register the list of extensions per DB
|
|
vars:
|
|
db_extensions: {}
|
|
ansible.builtin.set_fact:
|
|
db_extensions: >-
|
|
{{
|
|
db_extensions
|
|
| combine({
|
|
item.item: item.query_result | map(attribute='extname')
|
|
})
|
|
}}
|
|
with_items: "{{ db_extensions_query.results }}"
|
|
- name: Register the list of extensions per DB as 'db:extensions[]' pairs
|
|
vars:
|
|
db_extensions:
|
|
sales:
|
|
- pgaudit
|
|
- plpgsql
|
|
countries:
|
|
- pgcrypto
|
|
- postgis
|
|
- pg_stat_statements
|
|
ansible.builtin.set_fact:
|
|
db_extension_pairs:
|
|
# Refer https://jinja.palletsprojects.com/en/3.0.x/templates/#assignments for the namespace object's reason
|
|
>-
|
|
{%- set ns = namespace(output = []) -%}
|
|
{%- for db in db_extensions.keys() -%}
|
|
{%- for extension in db_extensions[db] -%}
|
|
{{- ns.output.append({'db':db, 'extension': extension}) -}}
|
|
{%- endfor -%}
|
|
{%- endfor -%}
|
|
{{- ns.output -}}
|
|
- name: Get the device name and last snapshot id for all block devices in an EC2 instance
|
|
# Useful to create AMIs from instance snapshots
|
|
tags:
|
|
- aws
|
|
- ec2
|
|
- snapshot
|
|
- ami
|
|
ansible.builtin.set_fact:
|
|
last_snap_for_device:
|
|
# Refer https://jinja.palletsprojects.com/en/3.0.x/templates/#assignments for the namespace object's reason
|
|
>-
|
|
{%- set ns = namespace(devices_list = []) -%}
|
|
{%- for result in current_instance_snapshots.results -%}
|
|
{%- for device in current_instance_information.instances[0].block_device_mappings
|
|
| selectattr('ebs.volume_id', 'equalto', result.volume_id) -%}
|
|
{{-
|
|
ns.devices_list.append({
|
|
'device_name': device.device_name,
|
|
'snapshot_id': result.snapshots | sort(attribute='start_time') | last | json_query('snapshot_id'),
|
|
})
|
|
-}}
|
|
{%- endfor -%}
|
|
{%- endfor -%}
|
|
{{ ns.devices_list }}
|
|
|
|
- name: Use the users' home directory for something
|
|
block:
|
|
- name: Executing commands from specified users
|
|
block:
|
|
- name: Get users' homedir back
|
|
become: true
|
|
become_user: "{{ item }}"
|
|
become_flags: -iH
|
|
check_mode: false
|
|
ansible.builtin.command: >-
|
|
echo "{{ item }}: $HOME"
|
|
changed_when: false
|
|
with_items:
|
|
- root
|
|
- ec2-user
|
|
register: users_homedir_retrieve
|
|
- name: Compute and register the results
|
|
tags: AnsibleUnsafeText_to_Dict
|
|
ansible.builtin.set_fact:
|
|
users_homedir: >-
|
|
{{
|
|
users_homedir_retrieve
|
|
| community.general.json_query('results[].stdout')
|
|
| map('from_yaml')
|
|
| combine
|
|
}}
|
|
- name: Do your thing!
|
|
become: true
|
|
become_user: "{{ item.key }}"
|
|
ansible.builtin.file:
|
|
path: "{{ item.value }}/placeholder"
|
|
state: touch
|
|
with_dict: "{{ users_homedir }}"
|
|
- name: From the system's entries
|
|
block:
|
|
- name: Get raw information from the system's entries
|
|
ansible.builtin.getent:
|
|
database: passwd
|
|
key: "{{ item }}"
|
|
split: ':'
|
|
with_items:
|
|
- root
|
|
- ec2-user
|
|
register: users_entries
|
|
- name: Compute and register the results
|
|
ansible.builtin.set_fact:
|
|
users_info: >-
|
|
{{
|
|
users_entries
|
|
| community.general.json_query('results[].ansible_facts.getent_passwd[]')
|
|
| combine
|
|
}}
|
|
- name: Do your thing!
|
|
ansible.builtin.file:
|
|
path: "{{ item.value[4] }}/placeholder"
|
|
owner: "{{ item.key }}"
|
|
state: touch
|
|
with_dict: "{{ users_info }}"
|
|
|
|
- name: Cronjobs
|
|
block:
|
|
- name: At specific times
|
|
become: true
|
|
ansible.builtin.cron:
|
|
name: Prometheus manual data backup
|
|
cron_file: prometheus-manual-data-backup
|
|
|
|
# Mind this is based on the hosts' time.
|
|
hour: 4
|
|
minute: 0
|
|
|
|
user: root
|
|
job:
|
|
# - Keep '%' characters escaped or they'll be treated as newlines.
|
|
# - Archive creation returns 1 if it detects changes to read files.
|
|
# Using ';' instead of '&&' to ignore.
|
|
>
|
|
FILENAME="/tmp/prometheus-data-$(date +'\%s-\%F-\%H-\%m-\%S').tar.gz"
|
|
&& tar -czf "$FILENAME" '/var/lib/prometheus/data'
|
|
; tar -tf "$FILENAME" > '/dev/null'
|
|
&& aws s3 cp "$FILENAME" 's3://backups/prometheus/'
|
|
&& rm "$FILENAME"
|
|
|
|
- name: Error handling in blocks
|
|
block:
|
|
- name: This executes normally
|
|
ansible.builtin.debug:
|
|
msg: I execute normally
|
|
- name: This errors out
|
|
ansible.builtin.command: /bin/false
|
|
- name: This never executes
|
|
ansible.builtin.debug:
|
|
msg: I never execute due to the above task failing
|
|
rescue:
|
|
- name: This executes if any errors arose in the block
|
|
ansible.builtin.debug:
|
|
msg: I caught an error and can do stuff here to fix it
|
|
always:
|
|
- name: This always executes
|
|
ansible.builtin.debug:
|
|
msg: I always execute
|
|
|
|
- name: Integrate Ansible Vault
|
|
tags: ansible_vault
|
|
block:
|
|
- name: Use encrypted values
|
|
ansible.builtin.set_fact:
|
|
var_from_encrypted_value:
|
|
# password: '1q2w3e4r', plaintext value: 'very secret string'
|
|
!vault |
|
|
$ANSIBLE_VAULT;1.1;AES256
|
|
34646464653830386631363430386432666530356364313532313336373665613038633464376335
|
|
3539363530613130623638313063363165386230646566640a313438386133366137383939336637
|
|
33333365393337326239336264623462373064383663363234353635316538356461353061646563
|
|
3037306464363439340a663430313739393439363936613862316361353330363638323065383063
|
|
39613935613035343637336537643266313737666635313730353034373736353736
|
|
- name: Use encrypted files
|
|
# The 'unvault' filter requires files to exist beforehand, but it is fine for them to be plaintext. \_(-_-)_/
|
|
tags: tls_certificate
|
|
ansible.builtin.copy:
|
|
dest: /etc/haproxy/certificate.pem
|
|
content: |
|
|
{{ lookup('ansible.builtin.unvault', 'path/to/cert/key.pem') | string | trim }}
|
|
{{ lookup('ansible.builtin.unvault', 'path/to/cert/full_chain.pem') | string | trim }}
|
|
- name: Save data to encrypted files
|
|
# Of fu*king course the 'vault' filter would use the 'filter_default' vault ID by default to encrypt content.
|
|
# Set that parameter to '' to *not* specify a vault ID.
|
|
vars:
|
|
ansible_vault_password: >-
|
|
{{ lookup('ansible.builtin.file', [playbook_dir, 'ansible_vault_password_file.txt'] | path_join) }}
|
|
ansible.builtin.copy:
|
|
dest: path/to/file
|
|
decrypt: false # necessary if the file does not exist beforehand
|
|
content: "{{ 'some string' | ansible.builtin.vault(ansible_vault_password, vault_id='') }}"
|
|
|
|
- name: AWS
|
|
tags: aws
|
|
block:
|
|
- name: Get current IP ranges
|
|
# too many to be put into security group rules
|
|
ansible.builtin.set_fact:
|
|
ip_ranges: >-
|
|
lookup('url', 'https://ip-ranges.amazonaws.com/ip-ranges.json', split_lines=False)
|
|
| from_json
|
|
| json_query('prefixes')
|
|
| selectattr('region', 'equalto', 'eu-west-1')
|
|
| selectattr('service', 'equalto', 'AMAZON')
|
|
| map(attribute='ip_prefix')
|
|
- name: Assume roles
|
|
block:
|
|
- name: Get session tokens
|
|
amazon.aws.sts_assume_role:
|
|
access_key: AKIA1EXAMPLE1EXAMPLE # optional if defined as environment variable
|
|
secret_key: 123456789abcdefghijklmnopqrstuvwxyzABCDE # optional if defined as environment variable
|
|
profile: someProfile # optional if defined as environment variable
|
|
role_arn: "arn:aws:iam::123456789012:role/someRole"
|
|
role_session_name: someRoleSession
|
|
register: assumed_role
|
|
- name: Use the assumed role to take action
|
|
amazon.aws.ec2_tag:
|
|
access_key: "{{ assumed_role.sts_creds.access_key }}"
|
|
secret_key: "{{ assumed_role.sts_creds.secret_key }}"
|
|
profile: null # required to use the assumed role's token, if profile is specified via environment variable
|
|
session_token: "{{ assumed_role.sts_creds.session_token }}"
|
|
resource: i-xyzxyz01
|
|
tags:
|
|
MyNewTag: value
|
|
- name: EC2
|
|
block:
|
|
- name: Get running instances with 'K8S' as the 'Application' tag
|
|
amazon.aws.ec2_instance_info:
|
|
filters:
|
|
"tag:Application": K8S
|
|
instance-state-name: ["running"]
|
|
- name: Clone EC2 instances
|
|
vars:
|
|
source_instance_id: i-0123456789abcdef0
|
|
block:
|
|
- name: Get instance information from the original instance
|
|
amazon.aws.ec2_instance_info:
|
|
instance_ids:
|
|
- "{{ source_instance_id }}"
|
|
register: source_instance_info
|
|
- name: Create an AMI of the original instance
|
|
amazon.aws.ec2_ami:
|
|
instance_id: "{{ source_instance_id }}"
|
|
no_reboot: true # remove if the instance rebooting upon AMI creation is no biggie
|
|
wait: true
|
|
wait_timeout: 3600 # big volumes call for bit wait times (a 200GiB volume took )
|
|
name: ami-source
|
|
register: source_ami
|
|
- name: Use the AMI to launch clones identical to the original
|
|
when: source_ami.image_id is defined
|
|
amazon.aws.ec2_instance:
|
|
name: clone
|
|
vpc_subnet_id: "{{ source_instance_info.instances[0].subnet_id }}"
|
|
instance_type: "{{ source_instance_info.instances[0].instance_type }}"
|
|
image:
|
|
id: "{{ source_ami.image_id }}"
|
|
- name: RDS
|
|
block:
|
|
- name: Create an instance's snapshot
|
|
block:
|
|
- name: Create the snapshot
|
|
amazon.aws.rds_instance_snapshot:
|
|
db_instance_identifier: identifier-for-db-instance
|
|
db_snapshot_identifier: identifier-for-db-snapshot
|
|
register: snapshot_creation
|
|
- name: Wait for the snapshot to be in the 'available' state
|
|
when: snapshot_creation.snapshot_create_time is defined
|
|
amazon.aws.rds_snapshot_info:
|
|
db_snapshot_identifier: "{{ snapshot_creation.db_snapshot_identifier }}"
|
|
register: snapshot_check
|
|
retries: 3
|
|
delay: 120
|
|
until: snapshot_check.snapshots | selectattr('status', 'equalto', 'available') | length > 0
|
|
- name: Dump roles' privileges
|
|
block:
|
|
- name: Dump to file
|
|
environment:
|
|
PGPASSWORD: someRandomString
|
|
vars:
|
|
out_file: /tmp/instance-id_roles.sql
|
|
ansible.builtin.command: >-
|
|
pg_dumpall
|
|
--host 'instance-id.0123456789ab.eu-west-1.rds.amazonaws.com' --port '5432'
|
|
--user 'postgres' --database 'postgres' --no-password
|
|
--roles-only --no-role-passwords
|
|
--file '{{ out_file }}'
|
|
changed_when: false
|
|
- name: Dump to variable for later use through 'dump_execution.stdout_lines'
|
|
environment:
|
|
PGPASSWORD: someRandomString
|
|
ansible.builtin.command: >-
|
|
pg_dumpall
|
|
-h 'instance-id.0123456789ab.eu-west-1.rds.amazonaws.com' -p '5432'
|
|
-U 'postgres' -l 'postgres' -w
|
|
-r --no-role-passwords
|
|
changed_when: false
|
|
register: dump_execution
|
|
- name: Wait for pending changes to be applied
|
|
amazon.aws.rds_instance_info:
|
|
db_instance_identifier: identifier-for-db-instance
|
|
register: instance_check
|
|
retries: 12
|
|
delay: 15
|
|
until: instance_check.instances[0].pending_modified_values.keys() | length == 0
|
|
- name: Wait for AWS to realize some requests have been made
|
|
ansible.builtin.pause:
|
|
seconds: 60
|
|
|
|
- name: Send messages to Slack channels
|
|
vars:
|
|
slack_notification_hook_url: https://hooks.slack.com/services/AB01CD23EF4/ABCD0123E/aBcDefGh0123456789iJKLmn
|
|
block:
|
|
- name: Send plain messages
|
|
ansible.builtin.uri:
|
|
url: "{{ slack_notification_hook_url }}"
|
|
method: POST
|
|
body_format: json
|
|
body:
|
|
text: (╥╯ᗝ╰╥) task XYZ failed
|
|
- name: Send mrkdwn (Slack-specific markdown) text
|
|
# FIXME: still to be tested
|
|
ansible.builtin.uri:
|
|
url: "{{ slack_notification_hook_url }}"
|
|
method: POST
|
|
body_format: json
|
|
body:
|
|
blocks:
|
|
- type: section
|
|
text:
|
|
type: mrkdwn
|
|
text: This is a *_fancy_* message
|
|
|
|
- name: AWX
|
|
environment:
|
|
CONTROLLER_HOST: https://awx.example.org/
|
|
CONTROLLER_VERIFY_SSL: false
|
|
CONTROLLER_USERNAME: admin
|
|
CONTROLLER_PASSWORD: somethingSecret
|
|
block:
|
|
- name: Export all data from existing instances
|
|
# At the time of writing: applications, credential_types, credentials, execution_environments, inventory,
|
|
# inventory_sources, job_templates, notification_templates, organizations, projects, schedules, teams, and users.
|
|
awx.awx.export:
|
|
all: true
|
|
register: awx_export_output
|
|
|
|
- name: Let's Encrypt
|
|
# The 'acme_certificate' module takes in file paths for the certificate's files; those need either to *not* exist
|
|
# beforehand, or their content to be in specific formats.
|
|
block:
|
|
- name: Revoke test certificates with account key
|
|
community.crypto.acme_certificate_revoke:
|
|
acme_directory: https://acme-staging-v02.api.letsencrypt.org/directory
|
|
acme_version: 2
|
|
account_key_src: path/to/acme_account.key.pem
|
|
certificate: path/to/certificate.crt.pem
|
|
|
|
- name: GitLab
|
|
block:
|
|
- name: Install configured fleeting plugins
|
|
when: runner_executor in [ "docker-autoscaler", "instance" ]
|
|
become: true
|
|
ansible.builtin.command:
|
|
chdir: /root
|
|
cmd: gitlab-runner fleeting install
|
|
creates: /root/.config/fleeting/plugins
|