--- # roles/pfsense_upgrade/tasks/upgrade.yml # Execute the actual upgrade process with dynamic repository switching - name: Display upgrade details ansible.builtin.debug: msg: - "============================================================" - "Starting upgrade process on {{ inventory_hostname }}" - "============================================================" - " Current version : {{ pfsense_current_version }}" - " Current repo : {{ current_repo }}" - " Target repo : {{ upgrade_target_repo }}" - " Target description : {{ upgrade_target_description }}" - "============================================================" when: perform_upgrade | bool # --------------------------------------------------------------------------- # 1. Switch repository in configuration # --------------------------------------------------------------------------- # - name: Switch repository in config.xml # ansible.builtin.raw: | # php -r ' # require_once("/etc/inc/config.inc"); # require_once("/etc/inc/pkg-utils.inc"); # config_set_path("system/pkg_repo_conf_path", "{{ upgrade_target_repo }}"); # write_config("Switched to {{ upgrade_target_repo }} for upgrade");' # register: _repo_switch # timeout: "{{ upgrade_check_timeout | default(120) }}" # changed_when: true # when: perform_upgrade | bool - name: Switch repository and force synchronization (GUI Native) ansible.builtin.raw: | php -r ' require_once("guiconfig.inc"); require_once("pkg-utils.inc"); $target_repo = "{{ upgrade_target_repo }}"; $repos = pkg_list_repos(); $found = false; foreach ($repos as $repo) { if ($repo["name"] == $target_repo || $repo["path"] == $target_repo) { config_set_path("system/pkg_repo_conf_path", $repo["path"]); pkg_switch_repo(g_get("pkg_repos_path"), $repo["name"]); write_config("Branch switched to " . $repo["name"] . " via Ansible"); update_repos(); echo "Successfully switched to " . $repo["name"]; $found = true; break; } } if (!$found) { echo "ERROR: Repository not found"; exit(1); } ' register: _repo_switch timeout: "{{ upgrade_check_timeout | default(120) }}" changed_when: "'Successfully switched' in _repo_switch.stdout" when: perform_upgrade | bool - name: Apply repository configuration via pfSense-repo-setup ansible.builtin.raw: | /usr/local/sbin/pfSense-repo-setup -U register: _repo_apply when: perform_upgrade | bool - name: Verify repository switch took effect ansible.builtin.raw: | php -r ' require_once("/etc/inc/pkg-utils.inc"); foreach(pkg_list_repos() as $r) { if (isset($r["default"])) { echo $r["name"]; } }' register: _verify_repo_switch when: perform_upgrade | bool - name: Display new default repository ansible.builtin.debug: msg: "Repository switched to: {{ _verify_repo_switch.stdout | trim }}" when: - perform_upgrade | bool - _verify_repo_switch.stdout | trim == upgrade_target_repo # --------------------------------------------------------------------------- # 2. Execute the upgrade (with retry for lock error RC=99) # --------------------------------------------------------------------------- - name: Execute pfSense upgrade command ansible.builtin.raw: | /usr/local/sbin/pfSense-upgrade -y -l /conf/upgrade_log.txt -p /tmp/pfSense-upgrade.sock register: _upgrade_exec until: _upgrade_exec.rc != 99 retries: 3 delay: 10 ignore_errors: yes when: perform_upgrade | bool timeout: "{{ upgrade_timeout | default(900) }}" - name: Display upgrade command exit code ansible.builtin.debug: msg: "Upgrade command exit code: {{ _upgrade_exec.rc | default('TIMEOUT - upgrade may still be running') }}" when: perform_upgrade | bool - name: Check upgrade success from log file ansible.builtin.raw: | grep -q "__RC=0" /conf/upgrade_log.txt && echo "SUCCESS" || echo "FAILED" register: _upgrade_verify when: perform_upgrade | bool - name: Check upgrade success from log file ansible.builtin.raw: | grep -q "__RC=0" /conf/upgrade_log.txt && echo "SUCCESS" || echo "FAILED" register: _upgrade_verify when: perform_upgrade | bool - name: Parse upgrade verification result ansible.builtin.set_fact: upgrade_successful: "{{ _upgrade_verify.stdout | trim == 'SUCCESS' }}" upgrade_exit_code: "{{ _upgrade_exec.rc }}" when: perform_upgrade | bool - name: Display upgrade verification result ansible.builtin.debug: msg: - "Upgrade verification: {{ _upgrade_verify.stdout | trim }}" - "Exit code from log: {{ upgrade_exit_code }}" when: perform_upgrade | bool # --------------------------------------------------------------------------- # 3. Extract upgrade log summary for debugging (on failure) # --------------------------------------------------------------------------- - name: Get last 20 lines of upgrade log ansible.builtin.raw: | tail -20 /conf/upgrade_log.txt register: _upgrade_log_tail when: - perform_upgrade | bool - not upgrade_successful - name: Display upgrade log tail (for debugging) ansible.builtin.debug: msg: "Upgrade log tail:\n{{ _upgrade_log_tail.stdout }}" when: - perform_upgrade | bool - not upgrade_successful # --------------------------------------------------------------------------- # 4. Handle reboot if needed # --------------------------------------------------------------------------- - name: Check if reboot is required from upgrade log ansible.builtin.raw: | grep -q "__REBOOT_AFTER" /conf/upgrade_log.txt && echo "REBOOT_NEEDED" || echo "NO_REBOOT" register: _reboot_check when: - perform_upgrade | bool - upgrade_successful - name: Display reboot status ansible.builtin.debug: msg: "Reboot required: {{ _reboot_check.stdout | trim }}" when: - perform_upgrade | bool - upgrade_successful - name: Initiate system reboot ansible.builtin.raw: | /sbin/reboot ignore_unreachable: true ignore_errors: true when: - perform_upgrade | bool - upgrade_successful | bool - _reboot_check.stdout | trim == "REBOOT_NEEDED" # - name: Wait for system to come back online after reboot # ansible.builtin.wait_for_connection: # timeout: "{{ reboot_timeout | default(600) }}" # delay: 15 # when: # - perform_upgrade | bool # - upgrade_successful | bool # - _reboot_check.stdout | trim == "REBOOT_NEEDED" - name: Wait for system to come back online (raw ping loop) ansible.builtin.raw: | for i in 1 2 3 4 5 6 7 8 9 10 11 12; do sleep 10 /sbin/ping -c 1 -t 2 8.8.8.8 > /dev/null 2>&1 && exit 0 done exit 1 register: _wait_result ignore_errors: true when: - perform_upgrade | bool - upgrade_successful | bool - _reboot_check.stdout | trim == "REBOOT_NEEDED" # --------------------------------------------------------------------------- # 5. Final status and failure handling # --------------------------------------------------------------------------- - name: Display upgrade completion message ansible.builtin.debug: msg: - "============================================================" - "✅ Upgrade completed successfully on {{ inventory_hostname }}" - "============================================================" when: - perform_upgrade | bool - upgrade_successful - name: Display upgrade failure message ansible.builtin.debug: msg: - "============================================================" - "❌ Upgrade FAILED on {{ inventory_hostname }}" - " Exit code: {{ upgrade_exit_code }}" - " Check /conf/upgrade_log.txt on the target system" - "============================================================" when: - perform_upgrade | bool - not upgrade_successful - name: Fail playbook if upgrade unsuccessful ansible.builtin.fail: msg: "Upgrade failed on {{ inventory_hostname }}. Manual intervention required." when: - perform_upgrade | bool - not upgrade_successful