@@ -123,7 +123,10 @@ def install(self, version, load_config=None, sync=False):
123
123
)
124
124
response = self ._op (
125
125
'request system software install %s version "%s"'
126
- % ('load-config "{0}"' .format (load_config ) if load_config else "" , version ,)
126
+ % (
127
+ 'load-config "{0}"' .format (load_config ) if load_config else "" ,
128
+ version ,
129
+ )
127
130
)
128
131
if sync :
129
132
result = self .pandevice .syncjob (response )
@@ -230,7 +233,7 @@ def download_install_reboot(
230
233
self .download_install (target_version , load_config , sync = True )
231
234
# Reboot the device
232
235
self ._logger .info (
233
- "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."
234
237
% (self .pandevice .id , version )
235
238
)
236
239
self .pandevice .restart ()
@@ -253,36 +256,56 @@ def _next_upgrade_version(
253
256
install_base : bool ,
254
257
) -> PanOSVersion :
255
258
current_version = PanOSVersion (self .pandevice .version )
259
+ if target_version != "latest" and current_version == target_version :
260
+ return None
256
261
available_versions = list (map (PanOSVersion , self .versions .keys ()))
257
262
latest_version = max (available_versions )
258
263
next_minor_version = self ._next_minor_version (current_version )
264
+ if next_minor_version not in available_versions :
265
+ next_minor_version = None
259
266
if install_base :
260
267
if target_version == "latest" :
261
- return min (latest_version , next_minor_version )
262
- elif latest_version < target_version :
263
- return next_minor_version
264
- elif not self ._direct_upgrade_possible (current_version , target_version ):
265
- 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
266
280
else :
267
- return cast ( PanOSVersion , target_version )
281
+ return next_minor_version
268
282
else :
269
283
if target_version == "latest" :
270
- return latest_version
271
- elif latest_version < target_version :
272
- 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
273
294
else :
274
- 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
+ )
275
299
276
300
def _current_version_is_target (
277
- self , target_version : Union [PanOSVersion , str ]
301
+ self , target_version : Union [PanOSVersion , Literal [ "latest" ] ]
278
302
) -> bool :
279
- target_version = PanOSVersion (str (target_version ))
280
303
current_version = PanOSVersion (self .pandevice .version )
281
304
available_versions = list (map (PanOSVersion , self .versions .keys ()))
282
305
latest_version = max (available_versions )
283
- if current_version == target_version :
306
+ if target_version == "latest" and current_version == latest_version :
284
307
return True
285
- elif target_version == "latest" and current_version == latest_version :
308
+ elif current_version == target_version :
286
309
return True
287
310
else :
288
311
return False
@@ -370,14 +393,21 @@ def upgrade_to_version(
370
393
not install_base
371
394
and not self .versions [str (next_version .baseimage )]["downloaded" ]
372
395
):
373
- 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 )
374
403
375
404
# Ensure the content pack is upgraded to the latest
376
- self .pandevice .content .download_and_install_latest (sync = True )
405
+ if not dryrun :
406
+ self .pandevice .content .download_and_install_latest (sync = True )
377
407
378
408
# Upgrade to the next version
379
409
self ._logger .info (
380
- "Device %s will be upgraded to version: %s"
410
+ "Device %s will download and upgrade to version: %s"
381
411
% (self .pandevice .id , next_version )
382
412
)
383
413
if dryrun :
@@ -409,7 +439,7 @@ def _next_minor_version(self, version: Union[PanOSVersion, str]) -> PanOSVersion
409
439
# Account for 10.2.x (only release with minor version of '2')
410
440
if version .major == 10 and version .minor == 1 :
411
441
next_version = PanOSVersion ("10.2.0" )
412
- elif version .minor == 1 :
442
+ elif version .minor > 0 :
413
443
next_version = PanOSVersion (str (version .major + 1 ) + ".0.0" )
414
444
# There is no PAN-OS 5.1 for firewalls, so next minor release from 5.0.x is 6.0.0.
415
445
elif (
@@ -433,7 +463,22 @@ def _next_patch_version(self, version):
433
463
)
434
464
return next_version
435
465
436
- 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
+ ):
437
482
"""Check if current version can directly upgrade to target version
438
483
439
484
:returns True if a direct upgrade is possible, False if not
@@ -458,7 +503,7 @@ def _direct_upgrade_possible(self, current_version, target_version):
458
503
current_version .major == target_version .major
459
504
and current_version .minor == 0
460
505
and target_version .minor == 1
461
- and target_version .patch == 0
506
+ and ( not install_base or target_version .patch == 0 )
462
507
):
463
508
return True
464
509
@@ -468,10 +513,12 @@ def _direct_upgrade_possible(self, current_version, target_version):
468
513
current_version .major + 1 == target_version .major
469
514
and current_version .minor == 1
470
515
and target_version .minor == 0
471
- and target_version .patch == 0
516
+ and ( not install_base or target_version .patch == 0 )
472
517
):
473
518
return True
474
519
520
+ # SPECIAL CASES
521
+
475
522
# Upgrading a firewall from PAN-OS 5.0.x to 6.0.x
476
523
# This is a special case because there is no PAN-OS 5.1.x
477
524
from panos .firewall import Firewall
@@ -484,6 +531,17 @@ def _direct_upgrade_possible(self, current_version, target_version):
484
531
):
485
532
return True
486
533
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
+
487
545
return False
488
546
489
547
0 commit comments