def reconnect(self, steps, device): with steps.start("Reconnect to device {} after TFTP boot". \ format(device.name)) as step: if hasattr(device, 'chassis_type') and device.chassis_type.lower() == 'stack': log.info("Sleep for 90 seconds in order to sync ") time.sleep(90) if not _disconnect_reconnect(device): # If that still doesnt work, Thats all we got step.failed("Cannot reconnect to the device {d} after TFTP boot". format(d=device.name), ) else: log.info("Success - Have recovered and reconnected to device '{}'". \ format(device.name))
def tftp_boot(section, steps, device, ip_address, subnet_mask, gateway, tftp_server, image, recovery_password=None, save_system_config=True, timeout=600, config_reg_timeout=30): """ This stage boots a new image onto your device using the tftp booting method. Stage Schema ------------ tftp_boot: image (list): Image to boot with ip_address (list): Management ip address to configure to reach to the tftp server subnet_mask (str): Management subnet mask gateway (str): Management gateway tftp_server (str): Tftp server that is reachable with management interface recovery_password (str, optional): Enable password for device required after bootup. Defaults to None. save_system_config (bool, optional): Whether or not to save the system config if it was modified. Defaults to True. timeout (int, optional): Max time during which tftp boot must complete. Defaults to 600. config_reg_timeout (int, optional): Max time to set config-register. Defaults to 30. Example ------- tftp_boot: image: - /auto/some-location/that-this/image/stay-isr-image.bin ip_address: [10.1.7.126, 10.1.7.127] gateway: 10.1.7.1 subnet_mask: 255.255.255.0 tftp_server: 11.1.7.251 recovery_password: nbv_12345 save_system_config: False timeout: 600 config_reg_timeout: 10 There is more than one ip address, one for each supervisor. """ log.info("Section steps:" "\n1- Set config-register to 0x0" "\n2- Bring device down to rommon> prompt prior to TFTP boot" "\n3- Begin TFTP boot" "\n4- Reconnect to device after TFTP boot" "\n5- Reset config-register to 0x2101" "\n6- Execute 'write memory'") # Set config-register to 0x0 with steps.start("Set config-register to 0x0 on {}".format( device.name)) as step: try: device.api.execute_set_config_register(config_register='0x0', timeout=config_reg_timeout) except Exception as e: step.failed( "Unable to set config-register to 0x0 prior to TFTP" " boot on {}".format(device.name), ) # Bring the device down to rommon> prompt prior to TFTP boot with steps.start("Bring device {} down to rommon> prompt prior to TFTP boot".\ format(device.name)) as step: reload_dialog = Dialog([ Statement( pattern= r".*System configuration has been modified\. Save\? \[yes\/no\].*", action='sendline(yes)' if save_system_config else 'sendline(no)', loop_continue=True, continue_timer=False), Statement(pattern=r".*Proceed with reload\? \[confirm\].*", action='sendline()', loop_continue=False, continue_timer=False), ]) # Using sendline, as we dont want unicon boot to kick in and send "boot" # to the device. Cannot use device.reload() directly as in case of HA, # we need both sup to do the commands device.sendline('reload') reload_dialog.process(device.spawn) if device.is_ha: def reload_check(device, target): device.expect(['.*Initializing Hardware.*'], target=target, timeout=60) pcall(reload_check, ckwargs={'device': device}, ikwargs=[{ 'target': 'active' }, { 'target': 'standby' }]) else: device.expect(['.*Initializing Hardware.*'], timeout=60) log.info("Device is reloading") device.destroy_all() # Begin TFTP boot of device with steps.start("Begin TFTP boot of device {}".format( device.name)) as step: # Need to instantiate to get the device.start # The device.start only works because of a|b device.instantiate(connection_timeout=timeout) tftp_boot = { 'ip_address': ip_address, 'subnet_mask': subnet_mask, 'gateway': gateway, 'tftp_server': tftp_server, 'image': image } try: abstract = Lookup.from_device(device, packages={'clean': clean}) # Item is needed to be able to know in which parallel child # device.start only gets filled with single rp devices # for multiple rp devices we need to use subconnections if device.is_ha and hasattr(device, 'subconnections'): start = [i.start[0] for i in device.subconnections] else: start = device.start result = pcall(abstract.clean.recovery.recovery.recovery_worker, start=start, ikwargs = [{'item': i} for i, _ in enumerate(start)], ckwargs = \ {'device': device, 'timeout': timeout, 'tftp_boot': tftp_boot, 'break_count': 0, # Irrelevant as we will not use this pattern anyway # But needed for the recovery 'console_activity_pattern': '\\.\\.\\.\\.', 'golden_image': None, 'recovery_password': recovery_password}) except Exception as e: log.error(str(e)) step.failed("Failed to TFTP boot the device '{}'".\ format(device.name), ) else: log.info("Successfully performed TFTP boot on device '{}'".\ format(device.name)) # Disconnect and reconnect to the device with steps.start("Reconnect to device {} after TFTP boot".\ format(device.name)) as step: if not _disconnect_reconnect(device): # If that still doesnt work, Thats all we got step.failed( "Cannot reconnect to the device {d} after TFTP boot".format( d=device.name), ) else: log.info("Success - Have recovered and reconnected to device '{}'".\ format(device.name)) # Reset config-register to 0x2101 with steps.start("Reset config-register to 0x2101 on {}".\ format(device.name)) as step: try: device.api.execute_set_config_register(config_register='0x2102', timeout=config_reg_timeout) except Exception as e: log.error(str(e)) step.failed( "Unable to reset config-register to 0x2101 after TFTP" " boot on {}".format(device.name), ) # Execute 'write memory' with steps.start("Execute 'write memory' on {}".format( device.name)) as step: try: device.api.execute_write_memory() except Exception as e: log.error(str(e)) step.failed( "Unable to execute 'write memory' after TFTP boot " "on {}".format(device.name), ) else: section.passed("Successfully performed TFTP boot on device {}".\ format(device.name))
def tftp_boot(self, device, ip_address, subnet_mask, gateway, tftp_server, image, timeout, reconnect_delay=RECONNECT_DELAY, reboot_delay=REBOOT_DELAY): device.api.execute_write_erase_boot() # Using sendline, as we dont want unicon boot to kick in and send "boot" to # the device # Cannot use .reload as in case of HA, we need both sup to do the commands device.sendline('reload') device.sendline('y') device.sendline() log.info('** Rebooting the device **') # We now want to overwrite the statemachine device.destroy_all() # Sleep to make sure the device is reloading time.sleep(reboot_delay) # Need to instantiate to get the device.start # The device.start only works because of a|b device.instantiate(connection_timeout=timeout) tftp_boot = {'ip_address': ip_address, 'subnet_mask': subnet_mask, 'gateway': gateway, 'tftp_server': tftp_server, 'image': image} try: abstract = Lookup.from_device(device, packages={'clean': clean}) # Item is needed to be able to know in which parallel child # we are # device.start only gets filled with single rp devices # for multiple rp devices we need to use subconnections if device.is_ha and hasattr(device, 'subconnections'): start = [i.start[0] for i in device.subconnections] else: start = device.start result = pcall(abstract.clean.recovery.recovery.recovery_worker, start=start, ikwargs = [{'item': i} for i, _ in enumerate(start)], ckwargs = \ {'device': device, 'timeout': timeout, 'tftp_boot': tftp_boot, # Irrelevant as we will not use this pattern anyway # But needed for the recovery 'break_count': 0, 'console_activity_pattern': '\\.\\.\\.\\.', 'golden_image': None, 'recovery_password': None}) except Exception as e: log.error(str(e)) self.failed("Failed to recover the device '{}'".\ format(device.name)) else: log.info("Successfully recovered the device '{}'".\ format(device.name)) log.info('Sleeping for {r} before reconnection'.format(r=reconnect_delay)) time.sleep(reconnect_delay) # Disconnect and reconnect to the device if not _disconnect_reconnect(device): # If that still doesnt work, Thats all we got self.failed("Cannot reconnect to the device {d}". format(d=device.name)) else: log.info("Success - Have recovered and reconnected to device '{}'".\ format(device.name)) log.info('Set the boot variables') output = device.api.get_running_image() if not output: self.failed('Could not retrieved the running image') image = output[0].rsplit('/', 1)[1] device.api.execute_change_boot_variable(system='bootflash:/{image}' .format(image=image)) device.api.execute_copy_run_to_start()
def tftp_boot(section, steps, device, ip_address, subnet_mask, gateway, tftp_server, image, timeout=600, config_reg_timeout=30, device_reload_sleep=20, recovery_username=None, recovery_password=None): """ This stage boots a new image onto your device using the tftp booting method. Stage Schema ------------ tftp_boot: image: <Image to boot with `list`> (Mandatory) ip_address: <Management ip address to configure to reach to the TFTP server `str`> (Mandatory) subnet_mask: <Management subnet mask `str`> (Mandatory) gateway: <Management gateway `str`> (Mandatory) tftp_server: <tftp server is reachable with management interface `str`> (Mandatory) timeout: <Maximum time during which TFTP boot process must complete `int`> (Optional, Default 600 seconds) config_reg_timeout: <Time to wait after setting config-register `int`> (Optional, Default 30 seconds) device_reload_sleep: <Time to wait after reloading device `int`> (Optional, Default 20 seconds) recovery_username: <Enable username for device required after bootup `str`> (Optional, Default None) recovery_password: <Enable password for device required after bootup `str`> (Optional, Default None) Example ------- tftp_boot: image: - /auto/some-location/that-this/image/asr9k-mini-px.vm ip_address: [10.1.7.126, 10.1.7.127] gateway: 10.1.7.1 subnet_mask: 255.255.255.0 tftp_server: 11.1.7.251 timeout: 1200 config_reg_timeout: 60 device_reload_sleep: 300 recovery_username: admin recovery_password: nbv_12345 Note: There is more than one ip address, one for each supervisor. """ log.info("Section steps:" "\n1- Set config-register to 0x1820" "\n2- Bring device down to rommon> prompt prior to TFTP boot" "\n3- Begin TFTP boot" "\n4- Reconnect to device after TFTP boot" "\n5- Reset config-register to 0x1922") # Set config-register to 0x1820 with steps.start("Set config-register to 0x1820 on {}".\ format(device.name)) as step: try: device.api.execute_set_config_register(config_register='0x1820', timeout=config_reg_timeout) except Exception as e: step.failed("Unable to set config-register to 0x1820 prior to TFTP" " boot on {}".format(device.name)) # Bring the device down to rommon > prompt prior to TFTP boot with steps.start("Bring device {} down to rommon > prompt prior to TFTP boot".\ format(device.name)) as step: # Reload device try: device.admin_execute("reload location all") except Exception as e: # We now want to overwrite the statemachine device.destroy_all() # Sleep to make sure the device is reloading time.sleep(device_reload_sleep) else: step.failed("Unable to bring the device down to rommon> prompt") # Begin TFTP boot of device with steps.start("Begin TFTP boot of device {}".format(device.name)) as step: # Need to instantiate to get the device.start # The device.start only works because of a|b device.instantiate(connection_timeout=timeout) tftp_boot = {'ip_address': ip_address, 'subnet_mask': subnet_mask, 'gateway': gateway, 'tftp_server': tftp_server, 'image': image} try: abstract = Lookup.from_device(device, packages={'clean': clean}) # Item is needed to be able to know in which parallel child # we are # device.start only gets filled with single rp devices # for multiple rp devices we need to use subconnections if device.is_ha and hasattr(device, 'subconnections'): start = [i.start[0] for i in device.subconnections] else: start = device.start result = pcall(abstract.clean.recovery.recovery.recovery_worker, start=start, ikwargs = [{'item': i} for i, _ in enumerate(start)], ckwargs = \ {'device': device, 'timeout': timeout, 'tftp_boot': tftp_boot, 'break_count': 0, # Irrelevant as we will not use this pattern anyway # But needed for the recovery 'console_activity_pattern': '\\.\\.\\.\\.', 'golden_image': None, 'recovery_username': recovery_username, 'recovery_password': recovery_password}) except Exception as e: log.error(str(e)) step.failed("Failed to TFTP boot the device '{}'".\ format(device.name)) else: log.info("Successfully performed TFTP boot on device '{}'".\ format(device.name)) # Disconnect and reconnect to the device with steps.start("Reconnect to device {} after TFTP boot".\ format(device.name)) as step: if not _disconnect_reconnect(device): # If that still doesnt work, Thats all we got step.failed("Cannot reconnect to the device {d} after TFTP boot". format(d=device.name)) else: log.info("Success - Have recovered and reconnected to device '{}'".\ format(device.name)) # Reset config-register to 0x1922 with steps.start("Reset config-register to 0x1922 on {}".\ format(device.name)) as step: try: device.api.execute_set_config_register(config_register='0x1922', timeout=config_reg_timeout) except Exception as e: log.error(str(e)) step.failed("Unable to reset config-register to 0x1922 after TFTP" " boot on {}".format(device.name))
def tftp_boot(section, steps, device, ip_address, subnet_mask, gateway, tftp_server, image, timeout, reconnect_delay=60, reboot_delay=20): """ This stage boots a new image onto your device using the tftp booting method. Stage Schema ------------ tftp_boot: image: <Image to boot with `str`> (Mandatory) ip_address: <Management ip address to configure to reach to the TFTP server `str`> (Mandatory) subnet_mask: <Management subnet mask `str`> (Mandatory) gateway: <Management gateway `str`> (Mandatory) tftp_server: <tftp server is reachable with management interface> (Mandatory) timeout: <Maximum time for tftp boot `int`> (Mandatory) reboot_delay: <Maximum time for tftp boot `int`> (Optional) reconnect_delay: <Once device recovered, delay before final reconnect>, 'int'> (Default: 60) Example: -------- tftp_boot: image: - /auto/some-location/that-this/image/stay-isr-image.bin ip_address: [10.1.7.126, 10.1.7.127] gateway: 10.1.7.1 subnet_mask: 255.255.255.0 tftp_server: 11.1.7.251 There is more than one ip address, one for each supervisor. """ device.api.execute_write_erase_boot() # Using sendline, as we dont want unicon boot to kick in and send "boot" to # the device # Cannot use .reload as in case of HA, we need both sup to do the commands device.sendline('reload') device.sendline('y') device.sendline() log.info('** Rebooting the device **') # We now want to overwrite the statemachine device.destroy_all() # Sleep to make sure the device is reloading time.sleep(reboot_delay) # Need to instantiate to get the device.start # The device.start only works because of a|b device.instantiate(connection_timeout=timeout) tftp_boot = {'ip_address': ip_address, 'subnet_mask': subnet_mask, 'gateway': gateway, 'tftp_server': tftp_server, 'image': image} try: abstract = Lookup.from_device(device, packages={'clean': clean}) # Item is needed to be able to know in which parallel child # we are # device.start only gets filled with single rp devices # for multiple rp devices we need to use subconnections if device.is_ha and hasattr(device, 'subconnections'): start = [i.start[0] for i in device.subconnections] else: start = device.start result = pcall(abstract.clean.recovery.recovery.recovery_worker, start=start, ikwargs = [{'item': i} for i, _ in enumerate(start)], ckwargs = \ {'device': device, 'timeout': timeout, 'tftp_boot': tftp_boot, # Irrelevant as we will not use this pattern anyway # But needed for the recovery 'break_count': 0, 'console_activity_pattern': '\\.\\.\\.\\.', 'golden_image': None, 'recovery_password': None}) except Exception as e: log.error(str(e)) section.failed("Failed to recover the device '{}'".\ format(device.name)) else: log.info("Successfully recovered the device '{}'".\ format(device.name)) log.info('Sleeping for {r} before reconnection'.format(r=reconnect_delay)) time.sleep(reconnect_delay) # Disconnect and reconnect to the device if not _disconnect_reconnect(device): # If that still doesnt work, Thats all we got section.failed("Cannot reconnect to the device {d}". format(d=device.name)) else: log.info("Success - Have recovered and reconnected to device '{}'".\ format(device.name)) log.info('Set the boot variables') output = device.api.get_running_image() if not output: section.failed('Could not retrieved the running image') image = output[0].rsplit('/', 1)[1] device.api.execute_change_boot_variable(system='bootflash:/{image}' .format(image=image)) device.api.execute_copy_run_to_start()