Skip to content

Commit

Permalink
chore: Fix issues with PANOS software updater subsystem
Browse files Browse the repository at this point in the history
  • Loading branch information
btorresgil authored Jan 18, 2024
1 parent b76d567 commit f986e03
Showing 1 changed file with 81 additions and 23 deletions.
104 changes: 81 additions & 23 deletions panos/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ def install(self, version, load_config=None, sync=False):
)
response = self._op(
'request system software install %s version "%s"'
% ('load-config "{0}"'.format(load_config) if load_config else "", version,)
% (
'load-config "{0}"'.format(load_config) if load_config else "",
version,
)
)
if sync:
result = self.pandevice.syncjob(response)
Expand Down Expand Up @@ -230,7 +233,7 @@ def download_install_reboot(
self.download_install(target_version, load_config, sync=True)
# Reboot the device
self._logger.info(
"Device %s is rebooting after upgrading to version %s. This will take a while."
"Device %s is rebooting after upgrading to version %s. This will take a while."
% (self.pandevice.id, version)
)
self.pandevice.restart()
Expand All @@ -253,36 +256,56 @@ def _next_upgrade_version(
install_base: bool,
) -> PanOSVersion:
current_version = PanOSVersion(self.pandevice.version)
if target_version != "latest" and current_version == target_version:
return None
available_versions = list(map(PanOSVersion, self.versions.keys()))
latest_version = max(available_versions)
next_minor_version = self._next_minor_version(current_version)
if next_minor_version not in available_versions:
next_minor_version = None
if install_base:
if target_version == "latest":
return min(latest_version, next_minor_version)
elif latest_version < target_version:
return next_minor_version
elif not self._direct_upgrade_possible(current_version, target_version):
return next_minor_version
return (
next_minor_version
if next_minor_version is not None
else latest_version
)
elif self._direct_upgrade_possible(
current_version, target_version, install_base
):
# No minor upgrade needed to target
return target_version
elif next_minor_version is None:
return latest_version
else:
return cast(PanOSVersion, target_version)
return next_minor_version
else:
if target_version == "latest":
return latest_version
elif latest_version < target_version:
return latest_version
if next_minor_version is None:
return latest_version
else:
return self._latest_patch_version(
next_minor_version, available_versions
)
elif self._direct_upgrade_possible(
current_version, target_version, install_base
):
return target_version
else:
return cast(PanOSVersion, target_version)
# More than one minor upgrade needed to target
return self._latest_patch_version(
next_minor_version, available_versions
)

def _current_version_is_target(
self, target_version: Union[PanOSVersion, str]
self, target_version: Union[PanOSVersion, Literal["latest"]]
) -> bool:
target_version = PanOSVersion(str(target_version))
current_version = PanOSVersion(self.pandevice.version)
available_versions = list(map(PanOSVersion, self.versions.keys()))
latest_version = max(available_versions)
if current_version == target_version:
if target_version == "latest" and current_version == latest_version:
return True
elif target_version == "latest" and current_version == latest_version:
elif current_version == target_version:
return True
else:
return False
Expand Down Expand Up @@ -370,14 +393,21 @@ def upgrade_to_version(
not install_base
and not self.versions[str(next_version.baseimage)]["downloaded"]
):
self.download(next_version.baseimage, sync=True)
if dryrun:
self._logger.info(
"Device %s will download base image: %s"
% (self.pandevice.id, next_version.baseimage)
)
else:
self.download(next_version.baseimage, sync=True)

# Ensure the content pack is upgraded to the latest
self.pandevice.content.download_and_install_latest(sync=True)
if not dryrun:
self.pandevice.content.download_and_install_latest(sync=True)

# Upgrade to the next version
self._logger.info(
"Device %s will be upgraded to version: %s"
"Device %s will download and upgrade to version: %s"
% (self.pandevice.id, next_version)
)
if dryrun:
Expand Down Expand Up @@ -409,7 +439,7 @@ def _next_minor_version(self, version: Union[PanOSVersion, str]) -> PanOSVersion
# Account for 10.2.x (only release with minor version of '2')
if version.major == 10 and version.minor == 1:
next_version = PanOSVersion("10.2.0")
elif version.minor == 1:
elif version.minor > 0:
next_version = PanOSVersion(str(version.major + 1) + ".0.0")
# There is no PAN-OS 5.1 for firewalls, so next minor release from 5.0.x is 6.0.0.
elif (
Expand All @@ -433,7 +463,22 @@ def _next_patch_version(self, version):
)
return next_version

def _direct_upgrade_possible(self, current_version, target_version):
def _latest_patch_version(
self, version: Union[str, PanOSVersion], available_versions: List[PanOSVersion]
):
if isstring(version):
version = PanOSVersion(version)
found_patch = False
latest_patch: PanOSVersion = PanOSVersion("0.0.0")
for v in available_versions:
if v.major == version.major and v.minor == version.minor:
latest_patch = max(latest_patch, v)
found_patch = True
return latest_patch if found_patch else None

def _direct_upgrade_possible(
self, current_version, target_version, install_base=True
):
"""Check if current version can directly upgrade to target version
:returns True if a direct upgrade is possible, False if not
Expand All @@ -458,7 +503,7 @@ def _direct_upgrade_possible(self, current_version, target_version):
current_version.major == target_version.major
and current_version.minor == 0
and target_version.minor == 1
and target_version.patch == 0
and (not install_base or target_version.patch == 0)
):
return True

Expand All @@ -468,10 +513,12 @@ def _direct_upgrade_possible(self, current_version, target_version):
current_version.major + 1 == target_version.major
and current_version.minor == 1
and target_version.minor == 0
and target_version.patch == 0
and (not install_base or target_version.patch == 0)
):
return True

# SPECIAL CASES

# Upgrading a firewall from PAN-OS 5.0.x to 6.0.x
# This is a special case because there is no PAN-OS 5.1.x
from panos.firewall import Firewall
Expand All @@ -484,6 +531,17 @@ def _direct_upgrade_possible(self, current_version, target_version):
):
return True

# Upgrade from PAN-OS 10.1.x to 10.2.x
# This is a special case because only minor release with a 2
if (
current_version.major == 10
and current_version.minor == 1
and target_version.major == 10
and target_version.minor == 2
and (not install_base or target_version.patch == 0)
):
return True

return False


Expand Down

0 comments on commit f986e03

Please sign in to comment.