Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c4c216e
digitalocean: Remove the lower filter from the loop
vitabaks Oct 25, 2025
1425a0a
Fix loop and condition handling for droplet results
vitabaks Oct 25, 2025
3b30ecd
Fix server result filtering in Hetzner tasks
vitabaks Oct 25, 2025
8b60388
fix typo
vitabaks Oct 25, 2025
0d4ea99
Fix AWS tasks filtering and condition checks
vitabaks Oct 25, 2025
e4e0e2b
Ensure selectattr results are lists in Azure tasks
vitabaks Oct 25, 2025
d6e671a
Fix GCP task loops for proper list handling
vitabaks Oct 25, 2025
1578872
Update stanza creation conditions in pgbackrest role
vitabaks Oct 25, 2025
962c172
Fix package list handling for PostgreSQL upgrade
vitabaks Oct 25, 2025
0d5c3cf
Refactor pgbackrest delegate host variable
vitabaks Oct 25, 2025
cae83a6
molecule_pg_upgrade: Comment out RHEL distros in CI workflow
vitabaks Oct 25, 2025
9512c20
Run molecule_pg_upgrade test
vitabaks Oct 25, 2025
636abaf
Improve pgbackrest stanza creation task checks
vitabaks Oct 25, 2025
5593d69
Update stanza_create.yml
vitabaks Oct 25, 2025
99606a0
Improve error handling for DigitalOcean LB deletion
vitabaks Oct 25, 2025
f8c56aa
Fix package loop to use regex_replace in post_upgrade.yml
vitabaks Oct 25, 2025
8e38338
Refactor pgBackRest delegate selection logic
vitabaks Oct 25, 2025
670d306
Update pgbackrest_host.yml
vitabaks Oct 25, 2025
ebdcd28
Improve pgbackrest group handling in Ansible tasks
vitabaks Oct 25, 2025
c6f43ee
Update molecule_pg_upgrade.yml
vitabaks Oct 25, 2025
800b787
Simplify GCP instance selfLink formatting
vitabaks Oct 26, 2025
b256f1e
Parse instances_selflink as JSON in GCP task
vitabaks Oct 26, 2025
ac1afb5
Update default Azure VM image to Ubuntu 24.04
vitabaks Oct 26, 2025
e93c2df
Add retries to ssh-keyscan tasks for reliability
vitabaks Oct 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 25 additions & 24 deletions .github/workflows/molecule_pg_upgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,31 @@ jobs:
- distro: ubuntu2204
tag: latest
namespace: geerlingguy
- distro: rockylinux10
tag: latest
namespace: geerlingguy
- distro: rockylinux9
tag: latest
namespace: geerlingguy
- distro: almalinux10
tag: latest
namespace: glillico
- distro: almalinux9
tag: latest
namespace: glillico
- distro: oraclelinux10
tag: latest
namespace: glillico
- distro: oraclelinux9
tag: latest
namespace: glillico
- distro: centosstream10
tag: latest
namespace: glillico
- distro: centosstream9
tag: latest
namespace: glillico
# TODO: error "rsync: connection unexpectedly closed" in GitHub CI environment (need to investigate)
# - distro: rockylinux10
# tag: latest
# namespace: geerlingguy
# - distro: rockylinux9
# tag: latest
# namespace: geerlingguy
# - distro: almalinux10
# tag: latest
# namespace: glillico
# - distro: almalinux9
# tag: latest
# namespace: glillico
# - distro: oraclelinux10
# tag: latest
# namespace: glillico
# - distro: oraclelinux9
# tag: latest
# namespace: glillico
# - distro: centosstream10
# tag: latest
# namespace: glillico
# - distro: centosstream9
# tag: latest
# namespace: glillico

steps:
- name: Set TERM environment variable
Expand Down
4 changes: 2 additions & 2 deletions automation/roles/cloud_resources/tasks/aws.yml
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@
| selectattr('instances','defined') | map(attribute='instances') | list | flatten
| selectattr('instance_id','defined') | map(attribute='instance_id') | list
}}
loop: "{{ server_result.results | selectattr('instances', 'defined') }}"
loop: "{{ server_result.results | selectattr('instances', 'defined') | list }}"
loop_control:
label: >-
public_ip: {{ item.instances[0].public_ip_address | default('') }},
Expand All @@ -592,7 +592,7 @@
ansible.builtin.import_tasks: inventory.yml
when:
- server_result.results is defined
- server_result.results | selectattr('instances', 'defined')
- (server_result.results | selectattr('instances','defined') | list | length) > 0

# Delete the temporary ssh key from the cloud after creating the EC2 instance
- name: "AWS: Remove temporary SSH key '{{ ssh_key_name | default('') }}' from cloud"
Expand Down
10 changes: 5 additions & 5 deletions automation/roles/cloud_resources/tasks/azure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,9 @@
key_data: "{{ ssh_key_content }}"
ssh_password_enabled: false
image:
offer: "{{ azure_vm_image_offer | default('0001-com-ubuntu-server-jammy') }}"
offer: "{{ azure_vm_image_offer | default('ubuntu-24_04-lts') }}"
publisher: "{{ azure_vm_image_publisher | default('Canonical') }}"
sku: "{{ azure_vm_image_sku | default('22_04-lts-gen2') }}"
sku: "{{ azure_vm_image_sku | default('server') }}"
version: "{{ azure_vm_image_version | default('latest') }}"
os_type: Linux
os_disk_size_gb: "{{ system_volume_size | default('80') }}" # system disk size
Expand Down Expand Up @@ -386,7 +386,7 @@
private_ips | default([]) +
[item.ansible_facts.azure_vm.network_profile.network_interfaces[0].properties.ip_configurations[0].private_ip_address]
}}
loop: "{{ server_result.results | selectattr('ansible_facts.azure_vm', 'defined') }}"
loop: "{{ server_result.results | selectattr('ansible_facts.azure_vm', 'defined') | list }}"
loop_control:
label: "{{ item.ansible_facts.azure_vm.network_profile.network_interfaces[0].properties.ip_configurations[0].private_ip_address }}"

Expand Down Expand Up @@ -530,7 +530,7 @@
| map(attribute='vms') | map('default', []) | list | flatten
| selectattr('id','defined') | map(attribute='id') | list
}}
loop: "{{ server_result.results | selectattr('ansible_facts.azure_vm', 'defined') }}"
loop: "{{ server_result.results | selectattr('ansible_facts.azure_vm', 'defined') | list }}"
loop_control:
label: >-
public_ip: {{ (public_ip_address.results if public_ip_address is defined else []) | selectattr('idx', 'equalto', item.idx) | map(attribute='state.ip_address') | first | default('') }},
Expand All @@ -540,7 +540,7 @@
ansible.builtin.import_tasks: inventory.yml
when:
- server_result.results is defined
- server_result.results | selectattr('ansible_facts.azure_vm', 'defined')
- (server_result.results | selectattr('ansible_facts.azure_vm', 'defined') | list | length) > 0

# Delete (if state is absent)
- block:
Expand Down
28 changes: 15 additions & 13 deletions automation/roles/cloud_resources/tasks/digitalocean.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@
- name: "DigitalOcean: Get fingerprint for SSH key '{{ ssh_key_name | default('') }}'"
ansible.builtin.set_fact:
ssh_key_fingerprint: "{{ [item.fingerprint] }}"
loop: "{{ ssh_keys.data | lower }}"
loop_control: # do not display the public key
label: "{{ item.name }}"
loop: "{{ ssh_keys.data | default([]) }}"
loop_control:
label: "{{ item.name | default('unknown') }}"
when:
- ((ssh_key_name | length > 0 and ssh_key_name != (tmp_ssh_key_name | default(''))) or
(ssh_key_name == (tmp_ssh_key_name | default('')) and ssh_public_keys | default('') | length > 0))
- item.name == ssh_key_name | lower
(ssh_key_name == (tmp_ssh_key_name | default('')) and (ssh_public_keys | default('') | length > 0)))
- (item.name | lower) == (ssh_key_name | lower)

# Stop, if the ssh key is not found
- name: "DigitalOcean: Fail if SSH key '{{ ssh_key_name | default('') }}' is not found"
Expand All @@ -122,13 +122,13 @@
# get the fingerprint of all ssh keys
- name: "DigitalOcean: Get fingerprint for all SSH keys"
ansible.builtin.set_fact:
ssh_key_fingerprint: "{{ ssh_key_fingerprint | default([]) + [item.fingerprint] }}"
loop: "{{ ssh_keys.data | lower }}"
loop_control: # do not display the public key
label: "{{ item.name }}"
ssh_key_fingerprint: "{{ (ssh_key_fingerprint | default([])) + [item.fingerprint] }}"
loop: "{{ ssh_keys.data | default([]) }}"
loop_control:
label: "{{ item.name | default('unknown') }}"
when:
- (ssh_key_name | length < 1 or ssh_key_name == (tmp_ssh_key_name | default('')))
- (ssh_public_keys is not defined or ssh_public_keys | length < 1)
- (ssh_key_name | length < 1) or (ssh_key_name == (tmp_ssh_key_name | default('')))
- (ssh_public_keys is not defined) or ((ssh_public_keys | length) < 1)
when: state == 'present'

# Create (if state is present)
Expand Down Expand Up @@ -687,7 +687,7 @@
| map(attribute='data') | map('default', []) | list | flatten
| selectattr('id','defined') | map(attribute='id') | list
}}
loop: "{{ droplet_result.results | selectattr('data', 'defined') }}"
loop: "{{ droplet_result.results | selectattr('data','defined') | list }}"

Check warning on line 690 in automation/roles/cloud_resources/tasks/digitalocean.yml

View workflow job for this annotation

GitHub Actions / build

jinja[spacing]

Jinja2 spacing could be improved: {{ droplet_result.results | selectattr('data','defined') | list }} -> {{ droplet_result.results | selectattr('data', 'defined') | list }}
loop_control:
label: >-
public_ip: {{ (item.data.droplet.networks.v4 | selectattr('type', 'equalto', 'public')).0.ip_address | default('') }},
Expand All @@ -697,7 +697,7 @@
ansible.builtin.import_tasks: inventory.yml
when:
- droplet_result.results is defined
- droplet_result.results | selectattr('data', 'defined')
- (droplet_result.results | selectattr('data','defined') | list | length) > 0

# Delete the temporary SSH key from the cloud after creating the droplet
- name: "DigitalOcean: Remove temporary SSH key '{{ ssh_key_name | default('') }}' from cloud"
Expand Down Expand Up @@ -757,6 +757,8 @@
- sync
loop_control:
label: "{{ patroni_cluster_name }}-{{ item }}"
register: do_lb_del_result
failed_when: do_lb_del_result is failed and ('not found' not in (do_lb_del_result.msg | default('') | lower))
when: cloud_load_balancer | bool and
(item == 'primary' or
(item == 'replica' and server_count | int > 1) or
Expand Down
10 changes: 4 additions & 6 deletions automation/roles/cloud_resources/tasks/gcp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@
port: "{{ pgbouncer_listen_port | default('6432') }}"
network:
selfLink: "global/networks/{{ gcp_network_name }}"
instances: "{{ instances_selflink }}"
instances: "{{ instances_selflink | from_json }}"
state: present
vars:
region: "{{ server_location[:-2] if server_location[-2:] | regex_search('-[a-z]$') else server_location }}"
Expand All @@ -348,9 +348,7 @@
instances_selflink: >- # TODO: use "{{ server_result.results | map(attribute='selfLink') | map('community.general.dict_kv', 'selfLink') | list }}"
[
{% for i in range(1, (server_count | int) + 1) %}
{
"selfLink": "zones/{{ zone }}/instances/{{ server_name }}{{ '%02d' % i }}"
}{% if not loop.last %},{% endif %}
{ "selfLink": "zones/{{ zone }}/instances/{{ server_name }}{{ '%02d' % i }}" }{% if not loop.last %},{% endif %}
{% endfor %}
]
register: instance_group
Expand Down Expand Up @@ -558,7 +556,7 @@
| map(attribute='resources') | map('default', []) | list | flatten
| selectattr('id','defined') | map(attribute='id') | list
}}
loop: "{{ server_result.results | selectattr('networkInterfaces', 'defined') }}"
loop: "{{ server_result.results | selectattr('networkInterfaces', 'defined') | list }}"
loop_control:
label: >-
public_ip: {{ item.networkInterfaces[0].accessConfigs[0].natIP | default('') }},
Expand All @@ -568,7 +566,7 @@
ansible.builtin.import_tasks: inventory.yml
when:
- server_result.results is defined
- server_result.results | selectattr('networkInterfaces', 'defined')
- (server_result.results | selectattr('networkInterfaces', 'defined') | list | length) > 0

# Delete (if state is absent)
- block:
Expand Down
4 changes: 2 additions & 2 deletions automation/roles/cloud_resources/tasks/hetzner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@
| map(attribute='hcloud_server_info') | map('default', []) | list | flatten
| selectattr('id','defined') | map(attribute='id') | list
}}
loop: "{{ server_result.results | selectattr('hcloud_server', 'defined') }}"
loop: "{{ server_result.results | selectattr('hcloud_server', 'defined') | list }}"
loop_control:
label: >-
public_ip: {{ item.hcloud_server.ipv4_address | default('') }},
Expand All @@ -733,7 +733,7 @@
ansible.builtin.import_tasks: inventory.yml
when:
- server_result.results is defined
- server_result.results | selectattr('hcloud_server', 'defined')
- (server_result.results | selectattr('hcloud_server','defined') | list | length) > 0

# Delete the temporary ssh key from the cloud after creating the server
- name: "Hetzner Cloud: Remove temporary SSH key {{ ssh_key_name | default('') }} from cloud"
Expand Down
3 changes: 3 additions & 0 deletions automation/roles/pgbackrest/tasks/ssh_keys.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@
target_host: "{{ hostvars[item].get('bind_address') if (item in (groups['postgres_cluster'])) else pgbackrest_repo_host }}"
target_port: "{{ hostvars[item].get('ansible_ssh_port') or hostvars[item].get('ansible_port') or 22 }}"
register: ssh_known_host_keyscan
until: ssh_known_host_keyscan is succeeded
retries: 3
delay: 5
changed_when: false

- name: known_hosts | Add ssh host keys in "~postgres/.ssh/known_hosts" on database servers
Expand Down
13 changes: 8 additions & 5 deletions automation/roles/pgbackrest/tasks/stanza_create.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@
# The delegate_to parameter is used to execute the task on a different host than the one specified in the play's hosts parameter.
# In this case, the task is delegated to the first host in the pgbackrest group in the invetory.
- name: Get repo1-path value
delegate_to: "{{ groups['pgbackrest'][0] }}"
delegate_to: "{{ pgbackrest_delegate }}"
run_once: true
ansible.builtin.set_fact:
repo1_path: "{{ pgbackrest_server_conf['global'] | selectattr('option', 'equalto', 'repo1-path') | map(attribute='value') | list | first }}"
when: pgbackrest_repo_type | lower == 'posix'
when: (pgbackrest_repo_type | default('posix')) | lower == 'posix'

- name: "Make sure the {{ repo1_path | default('') }} directory exists"
delegate_to: "{{ groups['pgbackrest'][0] }}"
delegate_to: "{{ pgbackrest_delegate }}"
run_once: true
ansible.builtin.file:
path: "{{ repo1_path }}"
Expand All @@ -56,13 +56,16 @@
- name: Create stanza "{{ pgbackrest_stanza | default('') }}"
become: true
become_user: "{{ pgbackrest_repo_user }}"
delegate_to: "{{ groups['pgbackrest'][0] }}"
delegate_to: "{{ pgbackrest_delegate }}"
run_once: true
ansible.builtin.command: "pgbackrest --stanza={{ pgbackrest_stanza }} --no-online stanza-create"
register: stanza_create_result
changed_when:
- stanza_create_result.rc == 0
- stanza_create_result.stdout is not search("already exists")
vars:
pgbackrest_delegate: "{{ (groups.get('pgbackrest') | default([], true) | list | first) | default(inventory_hostname, true) }}"
when:
- pgbackrest_repo_host | length > 0
- (pgbackrest_repo_host | default('')) | length > 0
- (groups.get('pgbackrest') | default([], true) | length) > 0
tags: pgbackrest, pgbackrest_stanza_create
3 changes: 3 additions & 0 deletions automation/roles/ssh_keys/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
ansible.builtin.command: "ssh-keyscan -trsa -p {{ ansible_ssh_port | default(22) }} {{ hostvars[item]['bind_address'] }}"
loop: "{{ ssh_known_hosts }}"
register: ssh_known_host_results
until: ssh_known_host_results is succeeded
retries: 3
delay: 5
changed_when: false

- name: known_hosts | for each host, add/update the public key in the "~{{ ssh_key_user | default('') }}/.ssh/known_hosts"
Expand Down
14 changes: 8 additions & 6 deletions automation/roles/update/tasks/pgbackrest_host.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
- block:
- name: Gather facts from pgbackrest server
ansible.builtin.setup:
delegate_to: "{{ groups['pgbackrest'][0] }}"
delegate_to: "{{ pgbackrest_delegate }}"
run_once: true

- name: Update dnf cache
delegate_to: "{{ groups['pgbackrest'][0] }}"
delegate_to: "{{ pgbackrest_delegate }}"
run_once: true
ansible.builtin.shell: dnf clean all && dnf -y makecache
args:
executable: /bin/bash
when: ansible_os_family == "RedHat" and not (skip_dnf_makecache | default(false) | bool)

- name: Update apt cache
delegate_to: "{{ groups['pgbackrest'][0] }}"
delegate_to: "{{ pgbackrest_delegate }}"
run_once: true
ansible.builtin.apt:
update_cache: true
Expand All @@ -28,7 +28,7 @@
when: ansible_os_family == "Debian"

- name: Install the latest version of pgbackrest package
delegate_to: "{{ groups['pgbackrest'][0] }}"
delegate_to: "{{ pgbackrest_delegate }}"
run_once: true
ansible.builtin.package:
name: pgbackrest
Expand All @@ -39,7 +39,9 @@
retries: 3
become: true
become_user: root
vars:
pgbackrest_delegate: "{{ (groups.get('pgbackrest') | default([], true) | list | first) | default(inventory_hostname, true) }}"
when:
- pgbackrest_install | bool
- pgbackrest_repo_host | default('') | length > 0
- groups['pgbackrest'] | default([]) | length > 0
- (pgbackrest_repo_host | default('')) | length > 0
- (groups.get('pgbackrest') | default([], true) | length) > 0
2 changes: 1 addition & 1 deletion automation/roles/upgrade/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pg_upper_datadir: "{{ pg_new_datadir | regex_replace('/$', '') | dirname | dirna

# List of package names for the new PostgreSQL version to be installed.
# automatically detects the list of packages based on the 'postgresql_packages' variable
pg_new_packages: "{{ postgresql_packages | replace(postgresql_version | string, pg_new_version | string) }}"
pg_new_packages: "{{ postgresql_packages | map('regex_replace', postgresql_version | string, pg_new_version | string) | list }}"

# Alternatively, you can explicitly specify the list of new packages to install.
# This gives you more control and should be used if the automatic update does not meet your needs.
Expand Down
2 changes: 1 addition & 1 deletion automation/roles/upgrade/tasks/packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
ansible.builtin.package:
name: "{{ item }}"
state: latest
loop: "{{ pg_new_packages }}"
loop: "{{ pg_new_packages | list }}"
register: package_status
until: package_status is success
delay: 5
Expand Down
Loading
Loading