Skip to content

Commit

Permalink
Merge pull request #114 from cdot65/108-add-support-for-activeactive-…
Browse files Browse the repository at this point in the history
…ha-upgrades-in-pan-os-upgrade

108 add support for activeactive ha upgrades in pan os upgrade
  • Loading branch information
cdot65 authored Mar 18, 2024
2 parents 3db799b + b4d660e commit 9488df7
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 74 deletions.
4 changes: 2 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ WORKDIR /app
COPY settings.yaml /app

# Install any needed packages specified in requirements.txt
# Note: The requirements.txt should contain pan-os-upgrade==1.3.6
RUN pip install --no-cache-dir pan-os-upgrade==1.3.6
# Note: The requirements.txt should contain pan-os-upgrade==1.3.7
RUN pip install --no-cache-dir pan-os-upgrade==1.3.7

# Set the locale to avoid issues with emoji rendering
ENV LANG C.UTF-8
Expand Down
12 changes: 11 additions & 1 deletion docs/about/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@

Welcome to the release notes for the `pan-os-upgrade` tool. This document provides a detailed record of changes, enhancements, and fixes in each version of the tool.

## Version 1.3.6
## Version 1.3.7

**Release Date:** *<20240317>*

### What's New in version 1.3.7

- Added support for active/active firewall pairs.
- Corrected an issue where parsing HA suspended state wasn't converting ElementTree object before conditional matching
- Corrected an issue where suspending of peer HA was not being triggered in certain scenarios

## Version 1.3.6

**Release Date:** *<20240317>*

### What's New in version 1.3.6

- Added compatibility check for devices that are in HA to ensure that two minor or major releases aren't being skipped, which will result in a `suspended` state on the firewall that's upgraded first, and then resulting in a broken HA after the second firewall completes its upgrade.

## Version 1.3.5
Expand Down
2 changes: 1 addition & 1 deletion pan_os_upgrade/components/assurance.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class AssuranceOptions:
"enabled_by_default": True,
},
"free_disk_space": {
"description": "Check if a there is enough space on the `/opt/panrepo` volume for downloading an PanOS image.",
"description": "Check if a there is enough space on the `/opt/panrepo` volume for PAN-OS image.",
"log_level": "warning",
"exit_on_failure": False,
"enabled_by_default": True,
Expand Down
65 changes: 51 additions & 14 deletions pan_os_upgrade/components/ha.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from pan_os_upgrade.components.device import get_ha_status
from pan_os_upgrade.components.utilities import (
compare_versions,
flatten_xml_to_dict,
get_emoji,
)

Expand Down Expand Up @@ -272,7 +273,7 @@ def handle_firewall_ha(
local_version = ha_details["result"]["group"]["local-info"]["build-rel"]
peer_version = ha_details["result"]["group"]["peer-info"]["build-rel"]

if peer_version != local_version:
if ha_details["result"]["group"]["running-sync"] == "synchronized":
logging.info(
f"HA synchronization complete on {hostname}. Proceeding with upgrade."
)
Expand All @@ -290,22 +291,44 @@ def handle_firewall_ha(
f"{get_emoji(action='report')} {hostname}: Version comparison: {version_comparison}"
)

# If the active and passive target devices are running the same version
# If the firewall and its peer devices are running the same version
if version_comparison == "equal":
if local_state == "active":
# Add the active target device to the list and exit the upgrade process

# if the current device is active or active-primary
if local_state == "active" or local_state == "active-primary":

# Add the target device to the revisit list and exit the upgrade process
with target_devices_to_revisit_lock:
target_devices_to_revisit.append(target_device)

# log message to console
logging.info(
f"{get_emoji(action='search')} {hostname}: Detected active target device in HA pair running the same version as its peer. Added target device to revisit list."
)

# Exit the upgrade process for the target device at this time, to be revisited later
return False, None

elif local_state == "passive":
# if the current device is passive or active-secondary
elif local_state == "passive" or local_state == "active-secondary":

# suspend HA state of the target device
if not dry_run:
logging.info(
f"{get_emoji(action='report')} {hostname}: Suspending HA state of passive or active-secondary"
)
suspend_ha_passive(
target_device,
hostname,
)

# log message to console
else:
logging.info(
f"{get_emoji(action='report')} {hostname}: Target device is passive, but we are in dry-run mode. Skipping HA state suspension.",
)

# Continue with upgrade process on the passive target device
logging.info(
f"{get_emoji(action='report')} {hostname}: Target device is passive",
)
return True, None

elif local_state == "initial":
Expand All @@ -320,9 +343,9 @@ def handle_firewall_ha(
f"{get_emoji(action='report')} {hostname}: Target device is on an older version"
)
# Suspend HA state of active if the passive is on a later release
if local_state == "active" and not dry_run:
if local_state == "active" or local_state == "active-primary" and not dry_run:
logging.info(
f"{get_emoji(action='report')} {hostname}: Suspending HA state of active"
f"{get_emoji(action='report')} {hostname}: Suspending HA state of active or active-primary"
)
suspend_ha_active(
target_device,
Expand All @@ -335,9 +358,13 @@ def handle_firewall_ha(
f"{get_emoji(action='report')} {hostname}: Target device is on a newer version"
)
# Suspend HA state of passive if the active is on a later release
if local_state == "passive" and not dry_run:
if (
local_state == "passive"
or local_state == "active-secondary"
and not dry_run
):
logging.info(
f"{get_emoji(action='report')} {hostname}: Suspending HA state of passive"
f"{get_emoji(action='report')} {hostname}: Suspending HA state of passive or active-secondary"
)
suspend_ha_passive(
target_device,
Expand Down Expand Up @@ -580,7 +607,10 @@ def suspend_ha_active(
"<request><high-availability><state><suspend/></state></high-availability></request>",
cmd_xml=False,
)
if "success" in suspension_response.text:

response_message = flatten_xml_to_dict(suspension_response)

if response_message["result"] == "Successfully changed HA state to suspended":
logging.info(
f"{get_emoji(action='success')} {hostname}: Active target device HA state suspended."
)
Expand Down Expand Up @@ -636,12 +666,19 @@ def suspend_ha_passive(
- Coordination with network management and understanding the process to resume HA functionality are essential to ensure the continuity of services and network redundancy.
"""

logging.info(
f"{get_emoji(action='start')} {hostname}: Suspending passive target device HA state."
)

try:
suspension_response = target_device.op(
"<request><high-availability><state><suspend/></state></high-availability></request>",
cmd_xml=False,
)
if "success" in suspension_response.text:

response_message = flatten_xml_to_dict(suspension_response)

if response_message["result"] == "Successfully changed HA state to suspended":
logging.info(
f"{get_emoji(action='success')} {hostname}: Passive target device HA state suspended."
)
Expand Down
Loading

0 comments on commit 9488df7

Please sign in to comment.