Skip to content

Commit 388da2d

Browse files
authored
chore: Fix issues with PANOS software updater subsystem
1 parent 3b412f9 commit 388da2d

File tree

1 file changed

+77
-22
lines changed

1 file changed

+77
-22
lines changed

panos/updater.py

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ def download_install_reboot(
233233
self.download_install(target_version, load_config, sync=True)
234234
# Reboot the device
235235
self._logger.info(
236-
"Device %s is rebooting after upgrading to version %s. This will take a while."
236+
"Device %s is rebooting after upgrading to version %s. This will take a while."
237237
% (self.pandevice.id, version)
238238
)
239239
self.pandevice.restart()
@@ -256,36 +256,56 @@ def _next_upgrade_version(
256256
install_base: bool,
257257
) -> PanOSVersion:
258258
current_version = PanOSVersion(self.pandevice.version)
259+
if target_version != "latest" and current_version == target_version:
260+
return None
259261
available_versions = list(map(PanOSVersion, self.versions.keys()))
260262
latest_version = max(available_versions)
261263
next_minor_version = self._next_minor_version(current_version)
264+
if next_minor_version not in available_versions:
265+
next_minor_version = None
262266
if install_base:
263267
if target_version == "latest":
264-
return min(latest_version, next_minor_version)
265-
elif latest_version < target_version:
266-
return next_minor_version
267-
elif not self._direct_upgrade_possible(current_version, target_version):
268-
return next_minor_version
268+
return (
269+
next_minor_version
270+
if next_minor_version is not None
271+
else latest_version
272+
)
273+
elif self._direct_upgrade_possible(
274+
current_version, target_version, install_base
275+
):
276+
# No minor upgrade needed to target
277+
return target_version
278+
elif next_minor_version is None:
279+
return latest_version
269280
else:
270-
return cast(PanOSVersion, target_version)
281+
return next_minor_version
271282
else:
272283
if target_version == "latest":
273-
return latest_version
274-
elif latest_version < target_version:
275-
return latest_version
284+
if next_minor_version is None:
285+
return latest_version
286+
else:
287+
return self._latest_patch_version(
288+
next_minor_version, available_versions
289+
)
290+
elif self._direct_upgrade_possible(
291+
current_version, target_version, install_base
292+
):
293+
return target_version
276294
else:
277-
return cast(PanOSVersion, target_version)
295+
# More than one minor upgrade needed to target
296+
return self._latest_patch_version(
297+
next_minor_version, available_versions
298+
)
278299

279300
def _current_version_is_target(
280-
self, target_version: Union[PanOSVersion, str]
301+
self, target_version: Union[PanOSVersion, Literal["latest"]]
281302
) -> bool:
282-
target_version = PanOSVersion(str(target_version))
283303
current_version = PanOSVersion(self.pandevice.version)
284304
available_versions = list(map(PanOSVersion, self.versions.keys()))
285305
latest_version = max(available_versions)
286-
if current_version == target_version:
306+
if target_version == "latest" and current_version == latest_version:
287307
return True
288-
elif target_version == "latest" and current_version == latest_version:
308+
elif current_version == target_version:
289309
return True
290310
else:
291311
return False
@@ -373,14 +393,21 @@ def upgrade_to_version(
373393
not install_base
374394
and not self.versions[str(next_version.baseimage)]["downloaded"]
375395
):
376-
self.download(next_version.baseimage, sync=True)
396+
if dryrun:
397+
self._logger.info(
398+
"Device %s will download base image: %s"
399+
% (self.pandevice.id, next_version.baseimage)
400+
)
401+
else:
402+
self.download(next_version.baseimage, sync=True)
377403

378404
# Ensure the content pack is upgraded to the latest
379-
self.pandevice.content.download_and_install_latest(sync=True)
405+
if not dryrun:
406+
self.pandevice.content.download_and_install_latest(sync=True)
380407

381408
# Upgrade to the next version
382409
self._logger.info(
383-
"Device %s will be upgraded to version: %s"
410+
"Device %s will download and upgrade to version: %s"
384411
% (self.pandevice.id, next_version)
385412
)
386413
if dryrun:
@@ -412,7 +439,7 @@ def _next_minor_version(self, version: Union[PanOSVersion, str]) -> PanOSVersion
412439
# Account for 10.2.x (only release with minor version of '2')
413440
if version.major == 10 and version.minor == 1:
414441
next_version = PanOSVersion("10.2.0")
415-
elif version.minor == 1:
442+
elif version.minor > 0:
416443
next_version = PanOSVersion(str(version.major + 1) + ".0.0")
417444
# There is no PAN-OS 5.1 for firewalls, so next minor release from 5.0.x is 6.0.0.
418445
elif (
@@ -436,7 +463,22 @@ def _next_patch_version(self, version):
436463
)
437464
return next_version
438465

439-
def _direct_upgrade_possible(self, current_version, target_version):
466+
def _latest_patch_version(
467+
self, version: Union[str, PanOSVersion], available_versions: List[PanOSVersion]
468+
):
469+
if isstring(version):
470+
version = PanOSVersion(version)
471+
found_patch = False
472+
latest_patch: PanOSVersion = PanOSVersion("0.0.0")
473+
for v in available_versions:
474+
if v.major == version.major and v.minor == version.minor:
475+
latest_patch = max(latest_patch, v)
476+
found_patch = True
477+
return latest_patch if found_patch else None
478+
479+
def _direct_upgrade_possible(
480+
self, current_version, target_version, install_base=True
481+
):
440482
"""Check if current version can directly upgrade to target version
441483
442484
:returns True if a direct upgrade is possible, False if not
@@ -461,7 +503,7 @@ def _direct_upgrade_possible(self, current_version, target_version):
461503
current_version.major == target_version.major
462504
and current_version.minor == 0
463505
and target_version.minor == 1
464-
and target_version.patch == 0
506+
and (not install_base or target_version.patch == 0)
465507
):
466508
return True
467509

@@ -471,10 +513,12 @@ def _direct_upgrade_possible(self, current_version, target_version):
471513
current_version.major + 1 == target_version.major
472514
and current_version.minor == 1
473515
and target_version.minor == 0
474-
and target_version.patch == 0
516+
and (not install_base or target_version.patch == 0)
475517
):
476518
return True
477519

520+
# SPECIAL CASES
521+
478522
# Upgrading a firewall from PAN-OS 5.0.x to 6.0.x
479523
# This is a special case because there is no PAN-OS 5.1.x
480524
from panos.firewall import Firewall
@@ -487,6 +531,17 @@ def _direct_upgrade_possible(self, current_version, target_version):
487531
):
488532
return True
489533

534+
# Upgrade from PAN-OS 10.1.x to 10.2.x
535+
# This is a special case because only minor release with a 2
536+
if (
537+
current_version.major == 10
538+
and current_version.minor == 1
539+
and target_version.major == 10
540+
and target_version.minor == 2
541+
and (not install_base or target_version.patch == 0)
542+
):
543+
return True
544+
490545
return False
491546

492547

0 commit comments

Comments
 (0)