@@ -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