Technology Tales

Adventures in consumer and enterprise technology

Ansible automation for Linux Mint updates with repository failover handling

Published on 7th November 2025 Estimated Reading Time: 4 minutes

Recently, I had a Microsoft PPA output disrupt an Ansible playbook mediated upgrade process for my main Linux workstation. Thus, I ended up creating a failover for this situation, and the first step in the playbook was to define the affected repo:

  vars:
    microsoft_repo_url: "https://packages.microsoft.com/repos/code/dists/stable/InRelease"

The next move was to start defining tasks, with the first testing the repo to pick up any lack of responsiveness and flag that for subsequent operations.

  tasks:
  - name: Check Microsoft repository availability
    uri:
      url: "{{ microsoft_repo_url }}"
      method: HEAD
      return_content: no
      timeout: 10
    register: microsoft_repo_check
    failed_when: false

  - name: Set flag to skip Microsoft updates if unreachable
    set_fact:
      skip_microsoft_repos: "{{ microsoft_repo_check.status is not defined or microsoft_repo_check.status != 200 }}"

In the event of a failure, the next task was to disable the repo to allow other processing to take place. This was accomplished by temporarily renaming the relevant files under /etc/apt/sources.list.d/.

    - name: Temporarily disable Microsoft repositories
    become: true
    shell: |
      for file in /etc/apt/sources.list.d/microsoft*.list; do
        [ -f "$file" ] && mv "$file" "${file}.disabled"
      done
      for file in /etc/apt/sources.list.d/vscode*.list; do
        [ -f "$file" ] && mv "$file" "${file}.disabled"
      done
    when: skip_microsoft_repos | default(false)
    changed_when: false

With that completed, the rest of the update actions could be performed near enough as usual.

  - name: Update APT cache (retry up to 5 times)
    apt:
      update_cache: yes
    register: apt_update_result
    retries: 5
    delay: 10
    until: apt_update_result is succeeded

  - name: Perform normal upgrade
    apt:
      upgrade: yes
    register: apt_upgrade_result
    retries: 3
    delay: 10
    until: apt_upgrade_result is succeeded

  - name: Perform dist-upgrade with autoremove and autoclean
    apt:
      upgrade: dist
      autoremove: yes
      autoclean: yes
    register: apt_dist_result
    retries: 3
    delay: 10
    until: apt_dist_result is succeeded

After those, another renaming operation restores the earlier filenames to what they were.

  - name: Re-enable Microsoft repositories
    become: true
    shell: |
      for file in /etc/apt/sources.list.d/*.disabled; do
        base="$(basename "$file" .disabled)"
        if [[ "$base" == microsoft* || "$base" == vscode* || "$base" == edge* ]]; then
          mv "$file" "/etc/apt/sources.list.d/$base"
        fi
      done
    when: skip_microsoft_repos | default(false)
    changed_when: false

Needless to say, this disabling only happens in the event of there being a system failure. Otherwise, the steps are skipped and everything else is completed as it should be. While there is some cause for extended the repository disabling actions to other third repos as well, that is something that I will leave aside for now. Even this shows just how much can be done using Ansible playbooks and how much automation can be achieved. As it happens, I even get Flatpaks updated in much the same way:

    -   name: Ensure Flatpak is installed
      apt:
        name: flatpak
        state: present
        update_cache: yes
        cache_valid_time: 3600

  -   name: Update Flatpak remotes
      command: flatpak update --appstream -y
      register: flatpak_appstream
      changed_when: "'Now at' in flatpak_appstream.stdout"
      failed_when: flatpak_appstream.rc != 0

  -   name: Update all Flatpak applications
      command: flatpak update -y
      register: flatpak_result
      changed_when: "'Now at' in flatpak_result.stdout"
      failed_when: flatpak_result.rc != 0

  -   name: Install unused Flatpak applications
      command: flatpak uninstall --unused
      register: flatpak_cleanup
      changed_when: "'Nothing' not in flatpak_cleanup.stdout"
      failed_when: flatpak_cleanup.rc != 0

  -   name: Repair Flatpak installations
      command: flatpak repair
      register: flatpak_repair
      changed_when: flatpak_repair.stdout is search('Repaired|Fixing')
      failed_when: flatpak_repair.rc != 0

The ability to call system commands as you see in the above sequence is an added bonus, though getting the response detection completely sorted remains an outstanding task. All this has only scratched the surface of what is possible.

Add a Comment

Your email address will not be published. Required fields are marked *

Please be aware that comment moderation is enabled and may delay the appearance of your contribution.

  • The content, images, and materials on this website are protected by copyright law and may not be reproduced, distributed, transmitted, displayed, or published in any form without the prior written permission of the copyright holder. All trademarks, logos, and brand names mentioned on this website are the property of their respective owners. Unauthorised use or duplication of these materials may violate copyright, trademark and other applicable laws, and could result in criminal or civil penalties.

  • All comments on this website are moderated and should contribute meaningfully to the discussion. We welcome diverse viewpoints expressed respectfully, but reserve the right to remove any comments containing hate speech, profanity, personal attacks, spam, promotional content or other inappropriate material without notice. Please note that comment moderation may take up to 24 hours, and that repeatedly violating these guidelines may result in being banned from future participation.

  • By submitting a comment, you grant us the right to publish and edit it as needed, whilst retaining your ownership of the content. Your email address will never be published or shared, though it is required for moderation purposes.