Skip to content

Commit d744317

Browse files
authored
Add reboot flag to install_os (#376)
* add reboot argument to install_os, vendor pynxos and update to support a reboot argument on set_boot_options * add comment * fix gitignore to allow pynxos/lib * changelog * PR feedback
1 parent 803d114 commit d744317

29 files changed

Lines changed: 1089 additions & 300 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,6 @@ public
309309
/compose.yaml
310310
/dump.sql
311311
/pyntc/static/pyntc/docs
312+
313+
# Exception for pynxos/lib
314+
!/pyntc/devices/pynxos/lib/

changes/376.added

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added reboot flag to Device.install_os for supported platforms.
2+
Vendored pynxos library and added reboot flag to Device.set_boot_options.

docs/generate_code_reference_pages.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
import mkdocs_gen_files
66

7+
EXCLUDE_PATHS = {
8+
"pyntc/devices/pynxos", # Exclude vendored package pynxos
9+
}
10+
711
for file_path in Path("pyntc").rglob("*.py"):
12+
if any(str(file_path).startswith(excluded) for excluded in EXCLUDE_PATHS):
13+
continue
814
module_path = file_path.with_suffix("")
915
doc_path = file_path.with_suffix(".md")
1016
full_doc_path = Path("code-reference", doc_path)

poetry.lock

Lines changed: 234 additions & 276 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyntc/devices/aireos_device.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,12 +971,15 @@ def hostname(self):
971971
hostname_string = hostname.group(1)
972972
return hostname_string
973973

974-
def install_os(self, image_name, controller="both", save_config=True, disable_wlans=None, **vendor_specifics):
974+
def install_os(
975+
self, image_name, reboot=True, controller="both", save_config=True, disable_wlans=None, **vendor_specifics
976+
):
975977
"""
976978
Install an operating system on the controller.
977979
978980
Args:
979981
image_name (str): The version to install on the device.
982+
reboot (bool): Whether to reboot the device after setting the boot options. Defaults to true.
980983
controller (str): The controller(s) to reboot for install (only applies to HA device).
981984
save_config (bool): Whether the config should be saved to the device before reboot.
982985
disable_wlans (str|list): Which WLANs to disable/enable before/after upgrade. Default is None.
@@ -1014,6 +1017,9 @@ def install_os(self, image_name, controller="both", save_config=True, disable_wl
10141017
if not self._image_booted(image_name):
10151018
peer_redundancy = self.peer_redundancy_state
10161019
self.set_boot_options(image_name, **vendor_specifics)
1020+
if not reboot:
1021+
log.info("Host %s: OS image %s boot options set. Reboot the device to apply", self.host, image_name)
1022+
return True
10171023
if disable_wlans is not None:
10181024
self.disable_wlans(disable_wlans)
10191025
self.reboot(controller=controller, save_config=save_config)

pyntc/devices/asa_device.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,12 +685,13 @@ def get_remote_checksum(self, filename, hashing_algorithm="md5", **kwargs: Any):
685685
log.error("Host %s: Unable to parse checksum for %s from output: %s", self.host, filename, result)
686686
raise CommandError(cmd, f"Unable to parse checksum for {filename}")
687687

688-
def install_os(self, image_name, **vendor_specifics):
688+
def install_os(self, image_name, reboot=True, **vendor_specifics):
689689
"""
690690
Install OS on device.
691691
692692
Args:
693693
image_name (str): Name of the image to be installed.
694+
reboot (bool): Whether to reboot the device after setting the boot options. Defaults to true.
694695
vendor_specifics (dict): Vendor specific arguments to pass to the install process.
695696
696697
Raises:
@@ -702,6 +703,9 @@ def install_os(self, image_name, **vendor_specifics):
702703
timeout = vendor_specifics.get("timeout", 3600)
703704
if not self._image_booted(image_name):
704705
self.set_boot_options(image_name, **vendor_specifics)
706+
if not reboot:
707+
log.info("Host %s: OS image %s boot options set. Reboot the device to apply", self.host, image_name)
708+
return True
705709
self.reboot()
706710
self._wait_for_device_reboot(timeout=timeout)
707711
if not self._image_booted(image_name):

pyntc/devices/base_device.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,11 +450,12 @@ def verify_file(self, checksum, filename, hashing_algorithm="md5", **kwargs):
450450
"""
451451
raise NotImplementedError
452452

453-
def install_os(self, image_name, **vendor_specifics):
453+
def install_os(self, image_name, reboot=True, **vendor_specifics):
454454
"""Install the OS from specified image_name.
455455
456456
Args:
457457
image_name (str): The name of the image on the device to install.
458+
reboot (bool): Whether to reboot the device after setting the boot options. Defaults to true.
458459
459460
Keyword Args:
460461
kickstart (str): Option for ``NXOSDevice`` for devices that require a kickstart image.

pyntc/devices/eos_device.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,11 +715,12 @@ def verify_file(self, checksum, filename, hashing_algorithm="md5", **kwargs):
715715
)
716716
return False
717717

718-
def install_os(self, image_name, **vendor_specifics):
718+
def install_os(self, image_name, reboot=True, **vendor_specifics):
719719
"""Install new OS on device.
720720
721721
Args:
722722
image_name (str): Name of the image name to be installed.
723+
reboot (bool): Whether to reboot the device after setting the boot options. Defaults to true.
723724
vendor_specifics (dict): Vendor specific options for installing OS, such as timeout.
724725
725726
Raises:
@@ -731,6 +732,9 @@ def install_os(self, image_name, **vendor_specifics):
731732
timeout = vendor_specifics.get("timeout", 3600)
732733
if not self._image_booted(image_name):
733734
self.set_boot_options(image_name, **vendor_specifics)
735+
if not reboot:
736+
log.info("Host %s: OS image %s boot options set. Reboot the device to apply", self.host, image_name)
737+
return True
734738
self.reboot()
735739
self._wait_for_device_reboot(timeout=timeout)
736740
if not self._image_booted(image_name):

pyntc/devices/f5_device.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,11 +654,12 @@ def image_installed(self, image_name, volume):
654654
log.debug("Host %s: Image %s not installed on volume %s.", self.host, image_name, volume)
655655
return False
656656

657-
def install_os(self, image_name, **vendor_specifics):
657+
def install_os(self, image_name, reboot=False, **vendor_specifics):
658658
"""Install OS on device.
659659
660660
Args:
661661
image_name (str): Image name.
662+
reboot (bool): Whether to reboot the device after setting the boot options. Defaults to false.
662663
vendor_specifics (dict): Vendor specific arguments.
663664
664665
Raises:
@@ -667,6 +668,10 @@ def install_os(self, image_name, **vendor_specifics):
667668
Returns:
668669
(bool): True if image is installed successfully. Otherwise, false.
669670
"""
671+
if reboot:
672+
# TODO: Implement reboot after OS installation
673+
raise NotImplementedError("F5 reboot after OS installation is not supported.")
674+
670675
volume = vendor_specifics.get("volume")
671676
if not self.image_installed(image_name, volume):
672677
self._check_free_space(min_space=6)

pyntc/devices/ios_device.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,11 +877,12 @@ def file_copy_remote_exists(self, src, dest=None, file_system=None):
877877
log.debug("Host %s: File %s does not already exist on remote.", self.host, src)
878878
return False
879879

880-
def install_os(self, image_name, install_mode=False, read_timeout=2000, **vendor_specifics):
880+
def install_os(self, image_name, reboot=True, install_mode=False, read_timeout=2000, **vendor_specifics):
881881
"""Installs the prescribed Network OS, which must be present before issuing this command.
882882
883883
Args:
884884
image_name (str): Name of the IOS image to boot into
885+
reboot (bool): Whether to reboot the device after setting the boot options. Defaults to true.
885886
install_mode (bool, optional): Uses newer install method on devices. Defaults to False.
886887
read_timeout (int, optional): Netmiko timeout when waiting for device prompt. Default 2000.
887888
vendor_specifics (dict, optional): Vendor specific arguments to pass to the install command.
@@ -894,6 +895,11 @@ def install_os(self, image_name, install_mode=False, read_timeout=2000, **vendor
894895
"""
895896
timeout = vendor_specifics.get("timeout", 3600)
896897
if not self._image_booted(image_name):
898+
if install_mode and not reboot:
899+
raise ValueError(
900+
"IOS devices automatically reboot after installation when using install mode but the reboot argument was set to false."
901+
)
902+
897903
if install_mode:
898904
# Change boot statement to be boot system <flash>:packages.conf
899905
self.set_boot_options(INSTALL_MODE_FILE_NAME, **vendor_specifics)
@@ -926,6 +932,9 @@ def install_os(self, image_name, install_mode=False, read_timeout=2000, **vendor
926932
self.reboot()
927933
else:
928934
self.set_boot_options(image_name, **vendor_specifics)
935+
if not reboot:
936+
log.info("Host %s: OS image %s boot options set. Reboot the device to apply", self.host, image_name)
937+
return True
929938
self.reboot()
930939

931940
# Wait for the reboot to finish

0 commit comments

Comments
 (0)