Author SHA1 Message Date
jakub 00b56a7c06 Update mikrotikbackup_clean.yml 2026-09-24 17:55:18 +00:00
jakub 87150f8cd9 Update inv_linuxes 2026-09-07 18:08:46 +00:00
jakub 6c9c003a30 Update inv_linuxes 2026-09-03 16:06:18 +00:00
jakub 0b298372c9 Update inv_linuxes 2026-09-03 14:30:58 +00:00
jakub 07ddce73fb Update inv_linuxes 2026-09-03 14:04:10 +00:00
jakub 600f9ec292 Update inv_linuxes 2026-09-03 13:51:33 +00:00
jakub 64b50f7501 support Arch Linux system updates 2026-09-03 14:58:24 +02:00
jakub b3d706721c Update update.yml 2026-09-02 21:55:23 +00:00
jakub 334fdaec8c Update update.yml 2026-09-02 21:45:22 +00:00
jakub e3def666c8 Update initial_install/roles/freeipa_client/tasks/main.yml 2026-09-02 20:03:52 +00:00
jakub 668e853cba Update initial_install/roles/freeipa_client/tasks/main.yml 2026-09-02 20:01:27 +00:00
jakub 84b0a463c3 Track Portainer STS releases 2026-08-30 01:58:38 +02:00
jakub 928c429568 Fix Portainer updater command 2026-08-30 01:51:47 +02:00
jakub a997469d6e Use official Portainer updater 2026-08-30 01:49:04 +02:00
jakub 075353d90c Update Portainer across release channels 2026-08-30 01:43:10 +02:00
jakub c22e580d3d Add tagged Portainer update role 2026-08-30 01:01:28 +02:00
jakub e66941b147 Update mikrotikbackup_clean.yml 2026-08-24 20:03:30 +00:00
jakub 82ad37e7ae Update initial_install/roles/freeipa_client/tasks/main.yml 2026-07-24 14:18:01 +00:00
jakub 905e3f597c Update initial_install/roles/freeipa_client/tasks/main.yml 2026-07-24 10:54:33 +00:00
jakub 704eff293a Update inv_linuxes 2026-07-24 10:49:14 +00:00
jakub 04cbc15b8e Update inv_linuxes 2026-07-24 10:41:40 +00:00
jakub d91c30c509 Update inv_linuxes 2026-07-24 10:38:38 +00:00
jakub 4e762abd6f Update inv_linuxes 2026-07-24 10:21:18 +00:00
jakub 40d7560e44 Merge pull request 'Manage own borgmatic systemd service and timer' (#1) from backup-systemd-units into main
Reviewed-on: #1
2026-05-30 18:55:15 +00:00
9 changed files with 411 additions and 163 deletions
@@ -11,13 +11,18 @@
- name: Set hostname FQDN - name: Set hostname FQDN
ansible.builtin.hostname: ansible.builtin.hostname:
name: "{{ inventory_hostname }}.im.lab" name: "{{ inventory_hostname }}"
- name: Check if FreeIPA client is already configured - name: Check if FreeIPA client is already configured
ansible.builtin.stat: ansible.builtin.stat:
path: /etc/ipa/default.conf path: /etc/ipa/default.conf
register: ipa_client_conf register: ipa_client_conf
- name: Check if Kerberos host keytab exists
ansible.builtin.stat:
path: /etc/krb5.keytab
register: ipa_keytab
- name: Enroll to FreeIPA - name: Enroll to FreeIPA
ansible.builtin.command: ansible.builtin.command:
argv: argv:
@@ -25,14 +30,36 @@
- --domain=im.lab - --domain=im.lab
- --realm=IM.LAB - --realm=IM.LAB
- --server=ipa.im.lab - --server=ipa.im.lab
- "--hostname={{ inventory_hostname }}.im.lab" - "--hostname={{ inventory_hostname }}"
- --mkhomedir - --mkhomedir
- --principal=admin - --principal=admin
- --password={{ ipa_admin_password }} - "--password={{ ipa_admin_password }}"
- --unattended - --unattended
- --force-join - --force-join
no_log: false no_log: true
when: not ipa_client_conf.stat.exists when:
- not ipa_client_conf.stat.exists or not ipa_keytab.stat.exists
- name: Check current sudo alternative
ansible.builtin.command:
cmd: update-alternatives --query sudo
register: sudo_alternative
changed_when: false
failed_when: false
when: ansible_facts['distribution'] == "Ubuntu"
- name: Switch to classic sudo
ansible.builtin.command:
argv:
- update-alternatives
- --set
- sudo
- /usr/bin/sudo.ws
when:
- ansible_facts['distribution'] == "Ubuntu"
- sudo_alternative.rc == 0
- "'/usr/bin/sudo.ws' in sudo_alternative.stdout"
- "'Value: /usr/bin/sudo.ws' not in sudo_alternative.stdout"
- name: Prioritize SSS over local accounts in NSS - name: Prioritize SSS over local accounts in NSS
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
@@ -44,7 +71,14 @@
- group - group
notify: Restart SSSD notify: Restart SSSD
- name: Enable mkhomedir - name: Check if authselect is available
ansible.builtin.command:
cmd: command -v authselect
register: authselect_available
changed_when: false
failed_when: false
- name: Enable mkhomedir with authselect
ansible.builtin.command: ansible.builtin.command:
argv: argv:
- authselect - authselect
@@ -53,6 +87,7 @@
register: authselect_mkhomedir register: authselect_mkhomedir
changed_when: "'already enabled' not in authselect_mkhomedir.stdout" changed_when: "'already enabled' not in authselect_mkhomedir.stdout"
failed_when: false failed_when: false
when: authselect_available.rc == 0
- name: Enable and start oddjobd - name: Enable and start oddjobd
ansible.builtin.service: ansible.builtin.service:
+10 -6
View File
@@ -1,20 +1,24 @@
[linux_servers_jim] [linux_servers_jim]
jimbuntu ansible_host=192.168.19.4 jimbuntu ansible_host=192.168.19.4
portainernode2_jim ansible_host=192.168.19.8 portainer2-jim.im.lab ansible_host=192.168.19.8
galera3 ansible_host=192.168.19.92 #galera3 ansible_host=192.168.19.92
galera2 ansible_host=192.168.19.91 #galera2 ansible_host=192.168.19.91
testipaclient ansible_host=192.168.19.98 testipaclient ansible_host=192.168.19.98
testclient ansible_host=192.168.19.115 #testclient ansible_host=192.168.19.115
portainer1-jim.im.lab ansible_host=192.168.19.7 portainer1-jim.im.lab ansible_host=192.168.19.7
[linux_servers_hellsos] [linux_servers_hellsos]
portainer2_hellsos ansible_host=192.168.52.9 portainer2-hellsos.im.lab ansible_host=192.168.52.9
portainernode_hellsos ansible_host=192.168.52.21 portainer1-hellsos.im.lab ansible_host=192.168.52.21
amp-hellsos.im.lab ansible_host=192.168.52.4
[linux_servers:children] [linux_servers:children]
linux_servers_jim linux_servers_jim
linux_servers_hellsos linux_servers_hellsos
[linux_servers_poli]
portainer1-poli.im.lab ansible_host=192.168.6.3
[local] [local]
localhost ansible_connection=local localhost ansible_connection=local
+154 -105
View File
@@ -1,146 +1,195 @@
---
- name: Backup and/or Upgrade MikroTik - name: Backup and/or Upgrade MikroTik
hosts: mikrotik_routers hosts: mikrotik_routers
gather_facts: no gather_facts: false
vars: vars:
backup_dir: /opt/mikrotik_backups/ backup_dir: /opt/mikrotik_backups/
ansible_connection: ansible.netcommon.network_cli
ansible_network_os: community.routeros.routeros
ansible_connect_timeout: 60
ansible_command_timeout: 60
upgrade_command_timeout: 600
upgrade_reconnect_timeout: 600
upgrade_verify_retries: 40
upgrade_verify_delay: 15
tasks: tasks:
# ----------------------------
# Always: identity + timestamp
# ----------------------------
- name: Get router identity - name: Get router identity
community.routeros.command: community.routeros.command:
commands: /system identity print commands: /system identity print
register: identity_raw register: identity_raw
changed_when: false
tags: always tags: always
- name: Parse router name - name: Parse router name
set_fact: ansible.builtin.set_fact:
router_name: "{{ identity_raw.stdout[0].split(': ')[1] | trim }}" router_name: "{{ identity_raw.stdout[0].split(': ', 1)[1] | trim }}"
tags: always tags: always
- name: Get timestamp - name: Get timestamp
ansible.builtin.command: date +%Y-%m-%d_%H-%M-%S ansible.builtin.command: date +%Y-%m-%d_%H-%M-%S
register: date_out register: date_out
delegate_to: localhost delegate_to: localhost
vars:
ansible_connection: local
changed_when: false
tags: always tags: always
- name: Set timestamp fact - name: Set timestamp fact
set_fact: ansible.builtin.set_fact:
ts: "{{ date_out.stdout }}" ts: "{{ date_out.stdout }}"
tags: always tags: always
# ---------------------------- - name: Back up router configuration
# Backup (tag: backup)
# ----------------------------
- name: Ensure local backup directory exists
ansible.builtin.file:
path: "{{ backup_dir }}"
state: directory
mode: "0755"
delegate_to: localhost
tags: [backup, never] tags: [backup, never]
block:
- name: Ensure local backup directory exists
ansible.builtin.file:
path: "{{ backup_dir }}"
state: directory
mode: "0755"
delegate_to: localhost
vars:
ansible_connection: local
- name: Export router config - name: Export router config
community.routeros.command: community.routeros.command:
commands: /export terse show-sensitive commands: /export terse show-sensitive
register: export_cfg register: export_cfg
tags: [backup, never] changed_when: false
no_log: true
- name: Save export locally - name: Save export locally
ansible.builtin.copy: ansible.builtin.copy:
content: "{{ export_cfg.stdout[0] }}" content: "{{ export_cfg.stdout[0] }}"
dest: "{{ backup_dir }}/{{ router_name }}-{{ ts }}.rsc" dest: "{{ backup_dir }}/{{ router_name }}-{{ ts }}.rsc"
delegate_to: localhost mode: "0600"
tags: [backup, never] delegate_to: localhost
vars:
ansible_connection: local
no_log: true
# ---------------------------- - name: Check and upgrade RouterOS packages
# Upgrade (tag: upgrade)
# ----------------------------
- name: Check current and latest available package versions
community.routeros.command:
commands: /system package update check-for-updates
register: update_check
tags: [upgrade, never] tags: [upgrade, never]
when: not ansible_check_mode
block:
- name: Check current and latest available package versions
community.routeros.command:
commands: /system package update check-for-updates
register: update_check
changed_when: false
- name: Normalize update output - name: Normalize update output
set_fact: ansible.builtin.set_fact:
_update_text: "{{ update_check.stdout[0] | replace('\r', '') }}" _update_text: "{{ update_check.stdout[0] | replace('\r', '') }}"
tags: [upgrade, never]
# ⬇️ Add this to see exactly what RouterOS returns before parsing - name: Parse installed and latest versions
- name: Debug raw update output ansible.builtin.set_fact:
ansible.builtin.debug: installed_version: >-
msg: "{{ _update_text }}" {{ (_update_text | regex_findall('(?:installed|current)-version:[ \t]*([0-9][0-9A-Za-z.-]*)')
tags: [upgrade, never] | first) | default('unknown') }}
latest_version: >-
{{ (_update_text | regex_findall('(?:latest|newest)-version:[ \t]*([0-9][0-9A-Za-z.-]*)')
| first) | default('unknown') }}
- name: Parse installed and latest versions - name: Require valid versions before attempting an upgrade
set_fact: ansible.builtin.assert:
installed_version: >- that:
{{ - installed_version != 'unknown'
(_update_text | regex_findall('(?:installed|current)-version:[ ]*([0-9A-Za-z.]+)'))[0] - latest_version != 'unknown'
if (_update_text | regex_findall('(?:installed|current)-version:[ ]*([0-9A-Za-z.]+)')) fail_msg: "Could not parse versions from update output: {{ _update_text }}"
else 'unknown'
}}
latest_version: >-
{{
(_update_text | regex_findall('(?:latest|newest)-version:[ ]*([0-9A-Za-z.]+)'))[0]
if (_update_text | regex_findall('(?:latest|newest)-version:[ ]*([0-9A-Za-z.]+)'))
else 'unknown'
}}
tags: [upgrade, never]
- name: Fail if versions could not be parsed - name: Show installed and available versions
ansible.builtin.fail: ansible.builtin.debug:
msg: > msg: "{{ router_name }}: installed={{ installed_version }}, available={{ latest_version }}"
Could not parse versions from update output.
Raw text was: {{ _update_text }}
when: installed_version == 'unknown' or latest_version == 'unknown'
tags: [upgrade, never]
- name: Debug parsed versions - name: Skip upgrade if already on latest
ansible.builtin.debug: ansible.builtin.debug:
msg: msg: "{{ router_name }} is already on {{ installed_version }}. Skipping upgrade."
- "Installed: {{ installed_version }}" when: installed_version == latest_version
- "Latest: {{ latest_version }}"
tags: [upgrade, never]
- name: Skip upgrade if already on latest - name: Install and verify the available version
ansible.builtin.debug: when: installed_version != latest_version
msg: "Router {{ router_name }} is already on latest version {{ installed_version }}. Skipping upgrade." block:
when: installed_version == latest_version - name: Reset persistent connection before installation
tags: [upgrade, never] ansible.builtin.meta: reset_connection
- name: Trigger package download and install - name: Request package installation
community.routeros.command: block:
commands: /system package update install - name: Trigger package download and install
register: upgrade_result community.routeros.command:
when: installed_version != latest_version commands: /system package update install
tags: [upgrade, never] vars:
ansible_command_timeout: "{{ upgrade_command_timeout }}"
register: install_result
- name: Wait for router to come back online after reboot rescue:
community.routeros.command: # A reboot can interrupt the command response. This is NOT
commands: /system resource print # success: the mandatory version check below decides the result.
register: reboot_wait - name: Record installation error for final verification
until: reboot_wait is not failed ansible.builtin.debug:
retries: 30 msg: >-
delay: 15 Installation returned an error: {{ install_result.msg | default('Unknown error') }}.
when: The command may or may not have reached the router.
- installed_version != latest_version Continuing only to verify the actual installed version.
- upgrade_result is not failed
tags: [upgrade, never]
- name: Confirm upgraded version always:
community.routeros.command: - name: Discard the installation connection
commands: /system resource print ansible.builtin.meta: reset_connection
register: post_upgrade_info
when: installed_version != latest_version
tags: [upgrade, never]
- name: Show post-upgrade RouterOS version # This readiness check does not claim that a reboot occurred.
ansible.builtin.debug: # The exact version comparison below is the success criterion.
msg: "{{ post_upgrade_info.stdout[0] | regex_search('version: .+') }}" - name: Wait for SSH availability from Semaphore
when: installed_version != latest_version ansible.builtin.wait_for:
tags: [upgrade, never] host: >-
{{ hostvars[inventory_hostname].ansible_host
| default(hostvars[inventory_hostname].ansible_ssh_host)
| default(inventory_hostname) }}
port: >-
{{ hostvars[inventory_hostname].ansible_port
| default(hostvars[inventory_hostname].ansible_ssh_port)
| default(22) }}
state: started
search_regex: SSH-
delay: 30
sleep: 5
connect_timeout: 5
timeout: "{{ upgrade_reconnect_timeout }}"
delegate_to: localhost
vars:
ansible_connection: local
changed_when: false
- name: Reset persistent connection before verification
ansible.builtin.meta: reset_connection
- name: Verify the installed version
block:
- name: Wait until the router reports the expected version
community.routeros.command:
commands: /system resource print
register: post_upgrade_info
changed_when: false
until:
- post_upgrade_info is succeeded
- >-
((post_upgrade_info.stdout | default(['']) | first
| regex_findall('(?m)^\s*version:[ \t]*([0-9][0-9A-Za-z.-]*)')
| first) | default('unknown')) == latest_version
retries: "{{ upgrade_verify_retries }}"
delay: "{{ upgrade_verify_delay }}"
rescue:
- name: Fail if the expected RouterOS version could not be verified
ansible.builtin.fail:
msg: >-
Upgrade NOT verified for {{ router_name }}.
Previous={{ installed_version }}; expected={{ latest_version }}.
Last router response={{ post_upgrade_info.stdout | default([]) }}.
Verification error={{ post_upgrade_info.msg | default('Version mismatch') }}.
Install error={{ install_result.msg | default('No module error reported') }}.
- name: Report verified upgrade
ansible.builtin.debug:
msg: "{{ router_name }}: verified RouterOS {{ installed_version }} -> {{ latest_version }}."
+2 -1
View File
@@ -1,2 +1,3 @@
collections: collections:
- name: community.routeros - name: community.routeros
- name: community.general
+23
View File
@@ -0,0 +1,23 @@
---
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
lock_timeout: 300
- name: Perform full upgrade
ansible.builtin.apt:
upgrade: full
autoremove: true
autoclean: true
lock_timeout: 300
register: apt_upgrade
retries: 3
delay: 10
until: apt_upgrade is succeeded
- name: Fix broken packages
ansible.builtin.command:
cmd: apt-get -f install -y
register: fix_result
failed_when: false
changed_when: "'Setting up' in fix_result.stdout"
+9
View File
@@ -0,0 +1,9 @@
---
- name: Update pacman cache and upgrade all packages
community.general.pacman:
update_cache: true
upgrade: true
register: pacman_upgrade
retries: 3
delay: 10
until: pacman_upgrade is succeeded
+5
View File
@@ -0,0 +1,5 @@
---
# Portainer's official updater recreates the server container while preserving
# its existing Docker configuration and persistent data.
portainer_updater_image: portainer/portainer-updater:latest
portainer_target_tag: sts
+72
View File
@@ -0,0 +1,72 @@
---
- name: Check whether Docker is available
ansible.builtin.command:
argv:
- docker
- info
register: portainer_docker_info
changed_when: false
failed_when: false
- name: Find and update Portainer
when: portainer_docker_info.rc == 0
block:
- name: List all container IDs
ansible.builtin.command:
argv:
- docker
- container
- ls
- --all
- --quiet
register: portainer_all_containers
changed_when: false
- name: Inspect all container images
ansible.builtin.command:
argv: >-
{{ ['docker', 'container', 'inspect']
+ portainer_all_containers.stdout_lines }}
register: portainer_container_inspection
changed_when: false
when: portainer_all_containers.stdout_lines | length > 0
- name: Select installed Portainer editions
ansible.builtin.set_fact:
portainer_installed_images: >-
{{ (portainer_container_inspection.stdout | default('[]') | from_json)
| map(attribute='Config.Image')
| select('match',
'^(?:[^/]+/)?portainer/(?:portainer|portainer-(?:ce|ee))(?::|@|$)')
| unique
| list }}
- name: Update Portainer to the newest release
ansible.builtin.command:
argv:
- docker
- run
- --rm
- --pull
- always
- --volume
- /var/run/docker.sock:/var/run/docker.sock
- "{{ portainer_updater_image }}"
- portainer
- >-
--image={{ 'portainer/portainer-ee:' ~ portainer_target_tag
if 'portainer-ee' in item
else 'portainer/portainer-ce:' ~ portainer_target_tag }}
loop: "{{ portainer_installed_images }}"
loop_control:
label: "{{ item }}"
register: portainer_update
changed_when: true
when:
- portainer_installed_images | length > 0
- not ansible_check_mode
- name: Report when no Portainer server is installed
ansible.builtin.debug:
msg: No Portainer CE or Business Edition server container found; skipping.
when: portainer_installed_images | length == 0
+95 -45
View File
@@ -1,91 +1,141 @@
--- ---
- name: Update system (APT + Flatpak) - name: Update Linux system
hosts: all hosts: all:!localhost:!portainer2-jim.im.lab
become: yes become: true
gather_facts: yes gather_facts: false
serial: 5 serial: 5
tasks: tasks:
# ---------------------------------------------------------
# Connectivity
# ---------------------------------------------------------
- name: Ensure SSH is reachable (skip host if not) - name: Ensure SSH is reachable (skip host if not)
delegate_to: localhost ansible.builtin.wait_for:
wait_for:
host: "{{ ansible_host | default(inventory_hostname) }}" host: "{{ ansible_host | default(inventory_hostname) }}"
port: 22 port: 22
timeout: 5 timeout: 5
delegate_to: localhost
register: ssh_check register: ssh_check
ignore_errors: yes ignore_errors: true
become: false
- meta: end_host - name: Skip host if SSH is unreachable
ansible.builtin.meta: end_host
when: ssh_check is failed when: ssh_check is failed
- name: Gather facts
ansible.builtin.setup:
- name: Ping with retries (handle intermittent flaps) - name: Ping with retries (handle intermittent flaps)
ping: ansible.builtin.ping:
register: ping_result register: ping_result
retries: 5 retries: 5
delay: 5 delay: 5
until: ping_result is success until: ping_result is success
- name: Wait for apt lock to be released # ---------------------------------------------------------
shell: | # Distribution packages
while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do # ---------------------------------------------------------
echo "Waiting for apt lock..."
sleep 5
done
changed_when: false
- name: Update apt cache - name: Update Debian-family packages
apt: ansible.builtin.include_role:
update_cache: yes name: update_apt
when: ansible_facts.os_family == 'Debian'
- name: Perform full upgrade - name: Update Arch Linux packages
apt: ansible.builtin.include_role:
upgrade: full name: update_arch
autoremove: yes when: ansible_facts.os_family == 'Archlinux'
autoclean: yes
register: apt_upgrade
retries: 3
delay: 10
until: apt_upgrade is succeeded
- name: Fix broken packages - name: Skip unsupported Linux distribution
command: apt-get -f install -y ansible.builtin.debug:
register: fix_result msg: >-
failed_when: false Package updates are not configured for
changed_when: "'Setting up' in fix_result.stdout" {{ ansible_facts.distribution }} ({{ ansible_facts.os_family }}).
when: ansible_facts.os_family not in ['Debian', 'Archlinux']
# ---------------------------------------------------------
# Flatpak
# ---------------------------------------------------------
- name: Check if Flatpak is installed - name: Check if Flatpak is installed
command: which flatpak ansible.builtin.command:
cmd: which flatpak
register: flatpak_check register: flatpak_check
changed_when: false changed_when: false
failed_when: false failed_when: false
- name: Update system Flatpaks - name: Update system Flatpaks
command: flatpak update -y --noninteractive --system ansible.builtin.command:
when: flatpak_check.rc == 0 cmd: flatpak update -y --noninteractive --system
register: flatpak_system_update
changed_when: "'Nothing to do' not in flatpak_system_update.stdout"
failed_when: false failed_when: false
when: flatpak_check.rc == 0
- name: Update user Flatpaks - name: Update user Flatpaks
command: flatpak update -y --noninteractive --user ansible.builtin.command:
cmd: flatpak update -y --noninteractive --user
become: false become: false
when: flatpak_check.rc == 0 register: flatpak_user_update
changed_when: "'Nothing to do' not in flatpak_user_update.stdout"
failed_when: false failed_when: false
when: flatpak_check.rc == 0
- name: Remove unused Flatpaks - name: Remove unused Flatpaks
command: flatpak uninstall -y --noninteractive --unused ansible.builtin.command:
cmd: flatpak uninstall -y --noninteractive --unused
register: flatpak_unused
changed_when: "'Nothing unused to uninstall' not in flatpak_unused.stdout"
failed_when: false
when: flatpak_check.rc == 0 when: flatpak_check.rc == 0
# ---------------------------------------------------------
# Snap
# ---------------------------------------------------------
- name: Check if Snap is installed
ansible.builtin.command:
cmd: which snap
register: snap_check
changed_when: false
failed_when: false failed_when: false
- name: Update snap packages - name: Update snap packages
command: snap refresh ansible.builtin.command:
cmd: snap refresh
register: snap_refresh
changed_when: "'All snaps up to date' not in snap_refresh.stdout"
failed_when: false failed_when: false
when: snap_check.rc == 0
# ---------------------------------------------------------
# Reboot check
# ---------------------------------------------------------
- name: Check if reboot is required - name: Check if reboot is required
stat: ansible.builtin.stat:
path: /var/run/reboot-required path: /var/run/reboot-required
register: reboot_required register: reboot_required
- name: Notify if reboot required - name: Notify if reboot required
debug: ansible.builtin.debug:
msg: "Reboot required on {{ inventory_hostname }}" msg: "Reboot required on {{ inventory_hostname }}"
when: reboot_required.stat.exists when: reboot_required.stat.exists
# ---------------------------------------------------------
# Portainer
# Only runs when --tags portainer is specified
# ---------------------------------------------------------
- name: Update Portainer containers
ansible.builtin.include_role:
name: update_portainer
apply:
tags:
- portainer
tags:
- never
- portainer