Skip to content

Commit

Permalink
Releasing v23.9
Browse files Browse the repository at this point in the history
  • Loading branch information
tasarath committed Sep 25, 2023
1 parent 41d96dc commit aa7ba45
Show file tree
Hide file tree
Showing 10 changed files with 33 additions and 265 deletions.
3 changes: 0 additions & 3 deletions pkgs/clean-pkg/changelog/2023/september.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
* Added
* Class ConfigureReplace in clean stages

* stages/iosxe
* Updated connect stage to support rommon boot


--------------------------------------------------------------------------------
Fix
Expand Down
7 changes: 1 addition & 6 deletions pkgs/clean-pkg/sdk_generator/output/github_clean.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,18 +166,13 @@
"url": "https://github.com/CiscoTestAutomation/genielibs/tree/master/pkgs/clean-pkg/src/genie/libs/clean/stages/stages.py#L33"
},
"iosxe": {
"doc": "This stage connects to the device that is being cleaned.\nStage Schema\n------------\nconnect:\n via (str, optional): Which connection to use from the testbed file. Uses the\n default connection if not specified.\n alias (str, optional): Which connection alias to use from the testbed file.\n timeout (int, optional): The timeout for the connection to complete in seconds.\n Defaults to 200.\n retry_timeout (int, optional): Overall timeout for retry mechanism in seconds.\n Defaults to 0 which means no retry.\n retry_interval (int, optional): Interval for retry mechanism in seconds. Defaults\n to 0 which means no retry.\nExample\n-------\nconnect:\n timeout: 60\n",
"module_name": "stages.stages",
"package": "genie.libs.clean",
"sdwan": {
"doc": "This stage connects to the device that is being cleaned.\n\nStage Schema\n------------\nconnect:\n\n via (str, optional): Which connection to use from the testbed file. Uses the\n default connection if not specified.\n\n timeout (int, optional): The timeout for the connection to complete in seconds.\n Defaults to 200.\n\n retry_timeout (int, optional): Overall timeout for retry mechanism in seconds.\n Defaults to 0 which means no retry.\n\n retry_interval (int, optional): Interval for retry mechanism in seconds. Defaults\n to 0 which means no retry.\n\nExample\n-------\nconnect:\n timeout: 60\n",
"module_name": "stages.stages",
"package": "genie.libs.clean",
"uid": "Connect",
"url": "https://github.com/CiscoTestAutomation/genielibs/tree/master/pkgs/clean-pkg/src/genie/libs/clean/stages/iosxe/sdwan/stages.py#L31"
},
"uid": "Connect",
"url": "https://github.com/CiscoTestAutomation/genielibs/tree/master/pkgs/clean-pkg/src/genie/libs/clean/stages/iosxe/stages.py#L2039"
}
},
"linux": {
"wsim": {
Expand Down
3 changes: 1 addition & 2 deletions pkgs/clean-pkg/src/genie/libs/clean/recovery/recovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,7 @@ def _connectivity(device, console_activity_pattern=None, console_breakboot_char=
'ip_address': list,
'subnet_mask': str,
'gateway': str,
'tftp_server': str,
Optional('ether_port'): int,
'tftp_server': str
},
Optional('recovery_password'): str,
Optional('clear_line'): bool,
Expand Down
155 changes: 2 additions & 153 deletions pkgs/clean-pkg/src/genie/libs/clean/stages/iosxe/stages.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import time
import os.path
import logging
from ipaddress import IPv4Address, IPv6Address, IPv4Interface, IPv6Interface
from ipaddress import IPv4Interface, IPv6Interface

# pyATS
from pyats.async_ import pcall
Expand All @@ -18,7 +18,7 @@
from genie.abstract import Lookup
from genie.libs import clean
from genie.libs.clean.recovery.recovery import _disconnect_reconnect
from genie.metaparser.util.schemaengine import Optional, Required, Any, Or, ListOf
from genie.metaparser.util.schemaengine import Optional, Required, Any
from genie.utils import Dq
from genie.metaparser.util.schemaengine import Optional, Required, Any, Or, ListOf
from genie.utils import Dq
Expand Down Expand Up @@ -2034,154 +2034,3 @@ def configure_replace(self, steps, device, path, file, config_replace_options=CO

except Exception as e:
step.failed("Configure replace failed", from_exception=e)


class Connect(BaseStage):
"""This stage connects to the device that is being cleaned.
Stage Schema
------------
connect:
via (str, optional): Which connection to use from the testbed file. Uses the
default connection if not specified.
alias (str, optional): Which connection alias to use from the testbed file.
timeout (int, optional): The timeout for the connection to complete in seconds.
Defaults to 200.
retry_timeout (int, optional): Overall timeout for retry mechanism in seconds.
Defaults to 0 which means no retry.
retry_interval (int, optional): Interval for retry mechanism in seconds. Defaults
to 0 which means no retry.
Example
-------
connect:
timeout: 60
"""

# =================
# Argument Defaults
# =================
VIA = None
ALIAS = None
TIMEOUT = 200
RETRY_TIMEOUT = 0
RETRY_INTERVAL = 0


# ============
# Stage Schema
# ============
schema = {
Optional('via', description="Which connection to use from the testbed file. Uses the default connection if not specified."): str,
Optional('alias', description="Which connection alias to use."): str,
Optional('timeout', description=f"The timeout for the connection to complete in seconds. Defaults to {TIMEOUT}.", default=TIMEOUT): Or(str, int),
Optional('retry_timeout', description=f"Overall timeout for retry mechanism in seconds. Defaults to {RETRY_TIMEOUT} which means no retry.", default=RETRY_TIMEOUT): Or(str, int, float),
Optional('retry_interval', description=f"Interval for retry mechanism in seconds. Defaults to {RETRY_INTERVAL} which means no retry.", default=RETRY_INTERVAL): Or(str, int, float),
}

# ==============================
# Execution order of Stage steps
# ==============================
exec_order = [
'connect'
]

def connect(self, steps, device, via=VIA, alias=ALIAS, timeout=TIMEOUT,
retry_timeout=RETRY_TIMEOUT, retry_interval=RETRY_INTERVAL):

with steps.start("Connecting to the device") as step:

log.info('Checking connection to device: %s' % device.name)

# Create a timeout that will loop
retry_timeout = Timeout(float(retry_timeout), float(retry_interval))
retry_timeout.one_more_time = True
# Without this we see 'Performing the last attempt' even if retry
# is not being used.
retry_timeout.disable_log = True

while retry_timeout.iterate():
retry_timeout.disable_log = False

# mit=True is used to make sure we do not initialize the connection
# and we can check if the device is in rommon.
device.instantiate(connection_timeout=timeout,
learn_hostname=True,
prompt_recovery=True,
via=via,
alias=alias,
mit=True)
try:
if alias:
getattr(device, alias).connect()
else:
device.connect()
except Exception:
log.error("Connection to the device failed", exc_info=True)
device.destroy_all()
# Loop
else:
step.passed("Successfully connected".format(device.name))
# Don't loop

retry_timeout.sleep()

step.failed("Could not connect. Scroll up for tracebacks.")

with steps.start(f'Checking the current state of the device: {device.name}') as step:

log.info(f'Checking the current state of the device: {device.name}')

state = ""
try:
# To check the state for HA devices
if device.is_ha and hasattr(device, 'subconnections'):
if isinstance(device.subconnections, list):
states = list(set([con.state_machine.current_state for con in device.subconnections]))
if states == ['rommon']:
state = 'rommon'
# Remove the one rp connection for Recovery worker API device_recovery_boot
# to boot a single RP as HA recovery is not yet implemented fully.
device.subconnections = [device.subconnections[0]]
elif 'rommon' in states:
step.failed(f'One of the device connection is in rommon state, need to recover device.')
else:
state = device.state_machine.current_state
except Exception as e:
log.warning(f'There is no connection in device.subconnections: {e}')

if state == "rommon":

with steps.start("Setting the rommon variables") as step:

log.info('Setting the rommon variables for TFTP boot')

try:
device.api.configure_rommon_tftp()
except Exception as e:
step.failed(f'Failed to set rommon variables. {e}')
else:
log.info("Successfully set the rommon variables")

with steps.start("Booting the device from rommon") as step:

log.info('Booting the device from rommon')

try:
# Gets the recovery details from clean yaml
device.api.device_recovery_boot()
except Exception as e:
step.failed(f'Failed to device boot device from rommon. {e}')
else:
log.info("Successfully booted the device from rommon.")


with steps.start("Disconnect and reconnect to the device") as step:

try:
_disconnect_reconnect(device)
except Exception as e:
step.failed(f'Failed to initialize the connection. {e}')
else:
step.passed("Successfully connected to the device")



This file was deleted.

2 changes: 1 addition & 1 deletion pkgs/sdk-pkg/sdk_generator/output/github_apis.json
Original file line number Diff line number Diff line change
Expand Up @@ -13698,7 +13698,7 @@
},
"device_recovery_boot": {
"com": {
"doc": "Boot device using golden image or using tftp server\n Args:\n device: device object\n break_count: <Send break count, 'int'>\n console_activity_pattern: <Break pattern on the device for normal boot mode, 'str'>\n console_breakboot_char: <Character to send when console_activity_pattern is matched, 'str'>\n console_breakboot_telnet_break: Use telnet `send break` to interrupt device boot\n grub_activity_pattern: <Break pattern on the device for grub boot mode, 'str'>\n grub_breakboot_char: <Character to send when grub_activity_pattern is matched, 'str'>\n timeout: <Timeout in seconds to recover the device, 'int'>\n recovery_password: <Device password after coming up, 'str'>\n golden_image: <Golden image to boot the device with, 'list' or 'dict' in the format below>\n kickstart: <Golden kickstart image, 'str'>\n system: <Golden system image, 'str'>\n tftp_boot:\n image: <Image to boot with `list`> (Mandatory)\n ip_address: <Management ip address to configure to reach to the TFTP server `list`> (Mandatory)\n subnet_mask: <Management subnet mask `str`> (Mandatory)\n gateway: <Management gateway `str`> (Mandatory)\n tftp_server: <tftp server is reachable with management interface> (Mandatory)\n ether_port: <To configure the ether_port> (Optional) (Default to 0)\n Return:\n None\n Raise:\n Exception\n ",
"doc": "Boot device using golden image or using tftp server\n Args:\n device: device object\n break_count: <Send break count, 'int'>\n console_activity_pattern: <Break pattern on the device for normal boot mode, 'str'>\n console_breakboot_char: <Character to send when console_activity_pattern is matched, 'str'>\n console_breakboot_telnet_break: Use telnet `send break` to interrupt device boot\n grub_activity_pattern: <Break pattern on the device for grub boot mode, 'str'>\n grub_breakboot_char: <Character to send when grub_activity_pattern is matched, 'str'>\n timeout: <Timeout in seconds to recover the device, 'int'>\n recovery_password: <Device password after coming up, 'str'>\n golden_image: <Golden image to boot the device with, 'list' or 'dict' in the format below>\n kickstart: <Golden kickstart image, 'str'>\n system: <Golden system image, 'str'>\n tftp_boot:\n image: <Image to boot with `list`> (Mandatory)\n ip_address: <Management ip address to configure to reach to the TFTP server `list`> (Mandatory)\n subnet_mask: <Management subnet mask `str`> (Mandatory)\n gateway: <Management gateway `str`> (Mandatory)\n tftp_server: <tftp server is reachable with management interface> (Mandatory)\n Return:\n None\n Raise:\n Exception\n ",
"module_name": "utils",
"package": "genie.libs.sdk.apis",
"uid": "device_recovery_boot",
Expand Down
23 changes: 1 addition & 22 deletions pkgs/sdk-pkg/src/genie/libs/sdk/apis/iosxe/rommon/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,6 @@ def configure_rommon_tftp(device, ipv6_address=False):
"""
tftp = {}

# Get the current device state from the device
if device.is_ha and hasattr(device, 'subconnections'):
if isinstance(device.subconnections, list):
states = list(set([con.state_machine.current_state for con in device.subconnections]))
if states == ['rommon']:
state = 'rommon'
elif 'rommon' in states:
raise Exception(f'One of the device connection is in rommon state, need to recover device.')
else:
state = device.state_machine.current_state

# check the device is in rommon
if state != 'rommon':
raise Exception(f'The device is not in rommon state')


# Check if management attribute in device object, if not set to empty dict
if not hasattr(device, 'management'):
setattr(device, "management", {})
Expand Down Expand Up @@ -75,15 +59,10 @@ def configure_rommon_tftp(device, ipv6_address=False):
log.warning(f"Some TFTP information is missing: {tftp}")

for set_command, value in tftp.items():

# To set rommon variables
cmd = f'{set_command}={value}'
try:
# Configure tftp rommon variables in active rp
if device.is_ha and hasattr(device, 'subconnections'):
device.subconnections[0].execute(cmd)
else:
device.execute(cmd)
device.execute(cmd)
except Exception as e:
raise SubCommandFailure(
f"Failed to set the rommon variable {set_command}. Error:\n{e}")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
configure:
commands:
end:
new_state: execute
line console 0:
new_state: configure_line
no logging console: ''
prompt: ott-c9300-63(config)#
configure_line:
commands:
end:
new_state: execute
exec-timeout 0: ''
prompt: ott-c9300-63(config-line)#
connect:
commands:
? ''
Expand Down Expand Up @@ -26,4 +40,11 @@ execute:
response:
- ''
response_type: circular
prompt: 'switch:'
config term:
new_state: configure
config-transaction:
new_state: configure
show version: ''
term length 0: ''
term width 0: ''
prompt: ott-c9300-63#
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ def setUpClass(self):
self.testbed = loader.load(testbed)
self.device = self.testbed.devices['ott-c9300-63']
self.device.connect(
mit=True
learn_hostname=True,
init_config_commands=[],
init_exec_commands=[]
)

def test_configure_rommon_tftp(self):
Expand Down
Loading

0 comments on commit aa7ba45

Please sign in to comment.