Connection To Network Devices
Connection To Network Devices
Python has several modules that allow you to connect to network devices and execute
commands:
• pexpect - an implementation of expect in Python
– this module allows working with any interactive session: ssh, telnet, sftp,
etc.
– in addition, it makes possible to execute different commands in OS (this
can also be done with other modules)
– while pexpect may be less user-friendly than other modules, it implements
a more general functionality and allows it to be used in situations where other
modules do not work
• netmiko - module that simplifies the use of paramiko for network devices
– netmiko is a “wrapper” which is oriented to work with network devices
This section covers all five modules and describes how to connect to several devices in
parallel. Three routers are used in section examples. There are no requirements for them,
only configured SSHv2 and Telnet.
96
Password input
During manual connection to device the password is also manually entered.
As a rule, the same user uses the same login and password to connect to devices. And
usually it’s enough to request login and password at the start of the script and then use
them to connect to different devices.
Unfortunately, if you use input the typed password will be visible. But it is better if no
characters are displayed when entering a password.
Module getpass
Module getpass allows you to request a password without displaying input characters:
import getpass
print(password) # yourpass
Environment variables
Another way to store a password (or even a username) is by environment variables.
For example, login and password are written in variables:
$ export SSH_USER=user
$ export SSH_PASSWORD=userpass
USERNAME = os.environ.get('SSH_USER')
PASSWORD = os.environ.get('SSH_PASSWORD')
97
Module pexpect
Module pexpect allows to automate interactive connections such as:
• telnet
• ssh
• ftp
At the same time, pexpect does not implement utilities but uses ready-made ones.
pexpect.spawn
Class spawn allows you to interact with called program by sending data and waiting for a
response.
After executing this line, connection is established. Now you must specify which line to
expect. In this case, wait for password request:
ssh.expect('[Pp]assword')
Note how line that pexpect expects is written as [Pp]assword. This is a regex that
describes a password or Password string. That is, expect method can be used to pass a
regex as an argument.
Method expect returned number 0 as a result of the work. This number indicates that a
match has been found and that this element with index zero. Index appears here because
you can pass a list of strings. For example, you can pass a list with two elements:
ssh = pexpect.spawn('ssh cisco@192.168.100.1')
ssh.expect(['password', 'Password']) # 1
Note that it now returns 1. This means that Password word matched.
98
Now you can send password using sendline method:
ssh.sendline('cisco') # 6
Method sendline sends a string, automatically adds a new line character to it based on
the value of os.linesep and then returns a number indicating how many bytes were written.
After sending the command, pexpect must be told until what point to read the output. We
specify that it should read untill #:
ssh.expect('#') # 0
"""
b'sh ip int br\r\nInterface IP-Address OK? Method Status ␣
,→ Protocol\r\nEthernet0/0 192.168.100.1 YES NVRAM up ␣
,→ up \r\nEthernet0/1 192.168.200.1 YES NVRAM up ␣
,→ up \r\nEthernet0/2 19.1.1.1 YES NVRAM up ␣
,→ up \r\nEthernet0/3 192.168.230.1 YES NVRAM up ␣
,→ up \r\nEthernet0/3.100 10.100.0.1 YES NVRAM up ␣
,→ up \r\nEthernet0/3.200 10.200.0.1 YES NVRAM up ␣
,→ up \r\nEthernet0/3.300 10.30.0.1 YES NVRAM up ␣
,→ up \r\nR1'
"""
Since the result is displayed as a sequence of bytes you should convert it to a string:
show_output = ssh.before.decode('utf-8')
print(show_output)
99
Example with sandbox-iosxe-latest-1.cisco.com
import pexpect
ssh = pexpect.spawn('ssh
developer@sandbox-iosxe-latest-1.cisco.com -y')
ssh.expect('Password:')
ssh.sendline('C1sco12345')
ssh.expect('#')
ssh.sendline('enable')
ssh.expect('#')
ssh.sendline('sh ip int br')
ssh.expect('--More--')
print(ssh.before.decode('utf-8'))
ssh.close()
100
Special characters in shell
Pexpect does not interpret special shell characters such as >, |, *.
For example, in order make command ls -ls | grep SUMMARY work, shell must be
run as follows:
import pexpect
print(p.before.decode('utf-8'))
# 4 -rw-r--r-- 1 vagrant vagrant 3203 Jul 14 07:15 1_pexpect.py
pexpect.EOF
In the previous example we met pexpect.EOF.
This is a special value that allows you to react to the end of a command or session that
has been run in spawn.
When calling ls -ls command, pexpect does not receive an interactive session.
Command is simply executed and that ends its work.
Method pexpect.expect
In pexpect.expect as a value can be used:
• regex
• EOF - this template allows you to react to EOF exception
• TIMEOUT - timeout exception (default timeout = 30 seconds)
• compiled regex
Another very useful feature of pexpect.expect is that you can pass not a single value, but a
list.
For example:
p = pexpect.spawn('/bin/bash -c "ls -ls | grep netmiko"')
101
Here are some important points:
• when pexpect.expect is called with a list, you can specify different expected strings
• apart strings, exceptions also can be specified
• pexpect.expect returns number of element that matched
– in this case number 2 because EOF exception is number two in the list
• with this format you can make branches in the program depending on the element
which had a match
result = {}
for command in commands:
ssh.sendline(command)
match = ssh.expect([prompt, pexpect.TIMEOUT, pexpect.EOF])
if match == 1:
print(f"Symbol {prompt} is not found in output. Resulting
output is written to dictionary"
if match == 2:
print("Connection was terminated by server")
return result
else:
output = ssh.before
result[command] = output.replace("\r\n", "\n")
return result
if __name__ == "__main__":
devices = ["192.168.100.1", "192.168.100.2", "192.168.100.3"]
commands = ["sh clock", "sh int desc"]
for ip in devices:
result = send_show_command(ip, "cisco", "cisco", "cisco", commands)
pprint(result, width=120)
Output after script execution:
102
{'sh clock': 'sh clock\n*13:13:47.525 UTC Sun Jul 19 2022\n',
'sh int desc': 'sh int desc\n'
'Interface Status Protocol Description\n'
'Et0/0 up up \n'
'Lo0 up up \n'}
{'sh clock': 'sh clock\n*13:13:50.450 UTC Sun Jul 19 2022\n',
'sh int desc': 'sh int desc\n'
'Interface Status Protocol Description\n'
'Et0/0 up up \n'
'Et0/1 up up \n'}
{'sh clock': 'sh clock\n*13:13:53.360 UTC Sun Jul 19 2022\n',
'sh int desc': 'sh int desc\n'
'Interface Status Protocol Description\n'
'Et0/0 up up \n'
'Lo100 up up \n'}
ssh.sendline(command)
output = ""
while True:
match = ssh.expect([prompt, "--More--", pexpect.TIMEOUT])
page = ssh.before.replace("\r\n", "\n")
page = re.sub(" +\x08+ +\x08+", "\n", page)
output += page
if match == 0:
break
elif match == 1:
ssh.send(" ")
else:
103
print("Error: timeout")
break
output = re.sub("\n +\n", "\n", output)
return output
if __name__ == "__main__":
devices = ["192.168.100.1", "192.168.100.2", "192.168.100.3"]
for ip in devices:
result = send_show_command(ip, "cisco", "cisco", "cisco", "sh run")
with open(f"{ip}_result.txt", "w") as f:
f.write(result)
Now after sending the command, expect method waits for another option --More-- -
sign, that there will be one more page further. Since it’s not known in advance how many
pages will be in the output, reading is performed in a loop while True. Loop is interrupted if
prompt is met # or no prompt appears within 10 seconds or --More--.
If --More-- is met, pages are not over yet and you have to scroll through the next one. In
Cisco, you need to press space bar to do this (without new line). Therefore, send method
is used here, not sendline - sendline automatically adds a new line character.
This string page = re.sub(" +\x08+ +\x08+", "\n", page) removes backspace
symbols which are around --More-- so they don’t end up in the final output.
104
Module telnetlib
Module telnetlib is part of standard Python library. This is telnet client implementation.
Note: It is also possible to connect via telnet using pexpect. The advantage of telnetlib is
that this module is part of standard Python library.
Telnetlib resembles pexpect but has several differences. The most notable difference is
that telnetlib requires a pass of a byte string, rather than normal one.
Method read_until
Method read_until specifies till which line the output should be read. However, as an
argument, it is necessary to pass bytes, not the usual string:
telnet.read_until(b'Username')
# b'\r\n\r\nUser Access Verification\r\n\r\nUsername'
Method write
The write method is used to transmit data. You must pass a byte string as an argument:
telnet.write(b'cisco\n')
You can now specify what should be read untill prompt and then send the command:
telnet.read_until(b'>') # b': \r\nR1>'
105
Method read_very_eager
Or use another read method read_very_eager. When using read_very_eager method,
you can send multiple commands and then read all available output:
telnet.write(b'sh arp\n')
telnet.write(b'sh clock\n')
telnet.write(b'sh ip int br\n')
all_result = telnet.read_very_eager().decode('utf-8')
print(all_result)
read_until vs read_very_eager
An important difference between read_until and read_very_eager is how they react
to the lack of output.
Method read_until waits for a certain string. By default, if it does not exist, method will
“freeze”.
Timeout option allows you to specify how long to wait for the desired string:
telnet.read_until(b'>', timeout=5) # b''
Method expect
Method expect allows you to specify a list with regular expressions. It works like
pexpect but telnetlib always has to pass a list of regular expressions.
106
Accordingly, if necessary you can continue working with these elements:
telnet.write(b'sh clock\n')
regex_idx, match, output = telnet.expect([b'[>#]'])
regex_idx # 0
match.group() # b'>'
Method close
Method close closes connection but it’s better to open and close connection using context
manager:
telnet.close()
def to_bytes(line):
return f"{line}\n".encode("utf-8")
def send_show_command(ip, username, password, enable, commands):
with telnetlib.Telnet(ip) as telnet:
telnet.read_until(b"Username")
telnet.write(to_bytes(username))
telnet.read_until(b"Password")
telnet.write(to_bytes(password))
index, m, output = telnet.expect([b">", b"#"])
if index == 0:
telnet.write(b"enable\n")
telnet.read_until(b"Password")
telnet.write(to_bytes(enable))
telnet.read_until(b"#", timeout=5)
telnet.write(b"terminal length 0\n")
telnet.read_until(b"#", timeout=5)
time.sleep(3)
telnet.read_very_eager()
result = {}
for command in commands:
telnet.write(to_bytes(command))
output = telnet.read_until(b"#", timeout=5).decode("utf-8")
result[command] = output.replace("\r\n", "\n")
return result
if __name__ == "__main__":
devices = ["192.168.100.1", "192.168.100.2", "192.168.100.3"]
commands = ["sh ip int br", "sh arp"]
for ip in devices:
result = send_show_command(ip, "cisco", "cisco", "cisco", commands)
pprint(result, width=120)
107
Since bytes need to be passed to write method and new line character should be added
each time, a small function to_bytes is created that does the conversion to bytes and adds
a new line.
108
Module paramiko
Paramiko is an implementation of SSHv2 protocol on Python. Paramiko provides
client-server functionality.
Since Paramiko is not part of standard Python module library, it needs to be installed:
pip install paramiko
Connection is established in this way: first, client is created and client configuration is set,
then connection is initiated and an interactive session is returned:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname="192.168.100.1", username="cisco",
password="cisco", ...: look_for_keys=False, allow_agent=False) 7
ssh = client.invoke_shell()
Method connect connects to SSH server and authenticates the connection. Parameters:
• look_for_keys - by default paramiko performs key authentication. To disable
this, put the flag in False
• allow_agent - paramiko can connect to a local SSH agent. This is necessary
when working with keys and since in this case authentication is done by
login/password, it should be disabled.
Method send
Method send - sends specified string to session and returns amount of sent bytes.
ssh.send("enable\n") # 7
ssh.send("cisco\n") # 6
ssh.send("sh ip int br\n") # 13
109
Warning: In code, after send you will need to put time.sleep, especially between send and
recv. Since this is an interactive session and commands are slow to type, everything works
without pauses.
Method recv
Method recv receives data from session. In parentheses, the maximum value in bytes
that can be obtained is indicated. This method returns a received string
ssh.recv(3000)
Method close
ssh.close()
def send_show_command(
ip,
username,
password,
enable,
command,
max_bytes=60000,
short_pause=1,
long_pause=5,
):
cl = paramiko.SSHClient()
cl.set_missing_host_key_policy(paramiko.AutoAddPolicy())
cl.connect(
hostname=ip,
username=username,
password=password,
look_for_keys=False,
allow_agent=False,
)
with cl.invoke_shell() as ssh:
ssh.send("enable\n")
110
ssh.send(f"{enable}\n")
time.sleep(short_pause)
ssh.send("terminal length 0\n")
time.sleep(short_pause)
ssh.recv(max_bytes)
result = {}
for command in commands:
ssh.send(f"{command}\n")
ssh.settimeout(5)
output = ""
while True:
try:
part = ssh.recv(max_bytes).decode("utf-8")
output += part
time.sleep(0.5)
except socket.timeout:
break
result[command] = output
return result
if __name__ == "__main__":
devices = ["192.168.100.1", "192.168.100.2", "192.168.100.3"]
commands = ["sh clock", "sh arp"]
result = send_show_command("192.168.100.1", "cisco", "cisco",
"cisco", commands)
pprint(result, width=120)
111
Module netmiko
Netmiko is a module that makes it easier to use paramiko for network devices. Netmiko
uses paramiko but also creates interface and methods needed to work with network
devices.
Enable mode
Switch to enable mode:
112
ssh.enable()
Sending commands
Netmiko has several ways to send commands:
• send_command - send one command
• send_config_set - send list of commands or command in configuration mode
• send_config_from_file - send commands from the file (uses
send_config_set method inside)
• send_command_timing - send command and wait for the output based on timer
send_command
Method send_command allows you to send one command to device.
For example:
result = ssh.send_command('show ip int br')
113
send_config_set
Method send_config_set allows you to send command or multiple commands in
configuration mode.
Example:
commands = ['router ospf 1',
'network 10.0.0.0 0.255.255.255 area 0',
'network 192.168.100.0 0.0.0.255 area 1']
result = ssh.send_config_set(commands)
send_config_from_file
Method send_config_from_file sends commands from specified file to configuration
mode.
Example of use:
result = ssh.send_config_from_file('config_ospf.txt')
Method opens a file, reads commands and passes them to send_config_set method.
Additional methods
Besides the above methods for sending commands, netmiko supports such methods:
• config_mode - switch to configuration mode: ssh.config_mode
• exit_config_mode - exit configuration mode: ssh.exit_config_mode
• check_config_mode - check whether netmiko is in configuration mode (returns
True if in configuration mode and False if not): ssh.check_config_mode
• find_prompt - returns the current prompt of device: ssh.find_prompt
• commit - commit on IOS-XR and Juniper: ssh.commit
• disconnect - terminate SSH connection
114
Telnet support
Since version 1.0.0 netmiko supports Telnet connections, so far only for Cisco IOS
devices. Inside netmiko uses telnetlib to connect via Telnet. But, at the same time, it
provides the same interface for work as for SSH connection.
In order to connect via Telnet, it is enough in the dictionary that defines connection
parameters specify device type cisco_ios_telnet:
device = {
"device_type": "cisco_ios_telnet",
"host": "192.168.100.1",
"username": "cisco",
"password": "cisco",
"secret": "cisco",
}
if __name__ == "__main__":
device = {
"device_type": "cisco_ios_telnet",
"host": "192.168.100.1",
"username": "cisco",
"password": "cisco",
"secret": "cisco",
}
result = send_show_command(device, ["sh clock", "sh ip int br"])
pprint(result, width=120)
* collects all the positional arguments in a tuple.
** collects all the keyword arguments in a dictionary.
115
Example of netmiko use
from pprint import pprint
import yaml
from netmiko import (
ConnectHandler,
NetmikoTimeoutException,
NetmikoAuthenticationException,
)
if __name__ == "__main__":
with open("devices.yaml") as f:
devices = yaml.safe_load(f)
for device in devices:
result = send_show_command(device, ["sh clock", "sh ip int br"])
pprint(result, width=120)
- devices.yaml content:
- device_type: cisco_ios
host: 192.168.100.1
username: cisco
password: cisco
secret: cisco
timeout: 5
fast_cli: true
- device_type: cisco_ios
host: 192.168.100.2
username: cisco
password: cisco
secret: cisco
timeout: 5
fast_cli: true
- device_type: cisco_ios
host: 192.168.100.3
username: cisco
password: cisco
secret: cisco
timeout: 5
fast_cli: true
116
Paginated command output
Example of using netmiko with paginated output of show command:
from netmiko import ConnectHandler, NetmikoTimeoutException
import yaml
if __name__ == "__main__":
with open("devices.yaml") as f:
devices = yaml.safe_load(f)
print(send_show_command(devices[0], "sh run"))
117
Module scrapli
scrapli is a module that allows you to connect to network equipment using Telnet, SSH or
NETCONF.
Just like netmiko, scrapli can use paramiko or telnetlib (and other modules) for the
connection itself, but it provides the same interface for different types of connections and
different equipment.
Installing scrapli:
pip install scrapli
Most of the examples will be using the system transport. Since the module interface is the
same for all synchronous transport options, to use a different transport, you just need to
specify it (for telnet transport, you must also specify the port).
Supported platforms:
• Cisco IOS-XE
• Cisco NX-OS
• Juniper JunOS
• Cisco IOS-XR
• Arista EOS
In addition to these platforms, there are also scrapli community platforms. And one of the
advantages of scrapli is that it is relatively easy to add new platforms.
118
There are two connection options in scrapli: using the general Scrapli class, which selects
the required driver by the platform parameter, or a specific driver, for example,
IOSXEDriver. The same parameters are passed to the specific driver and Scrapli.
Note: In addition to these options, there are also generic (base) drivers.
Connection parameters
Basic connection parameters:
• host - IP address or hostname
• auth_username - username for authentication
• auth_password - password for authentication
• auth_secondary - enable password
• auth_strict_key - strict key checking (True by default)
• platform - must be specified when using Scrapli
• transport - which transport to use
• transport_options - options for a specific transport
The connection process is slightly different depending on whether you are using a context
manager or not. When connecting without a context manager, you first need to pass
parameters to the driver or Scrapli, and then call the open method:
from scrapli import Scrapli
r1 = {
"host": "192.168.100.1",
"auth_username": "cisco",
"auth_password": "cisco",
"auth_secondary": "cisco",
"auth_strict_key": False,
"platform": "cisco_iosxe"
}
ssh = Scrapli(**r1)
ssh.open()
ssh.get_prompt() # 'R1#'
ssh.close()
119
Using the driver
Available drivers:
r1_driver = {
"host": "192.168.100.1",
"auth_username": "cisco",
"auth_password": "cisco",
"auth_secondary": "cisco",
"auth_strict_key": False,
}
Sending commands
Scrapli has several methods for sending commands:
• send_command - send one show command
• send_commands - send a list of show commands
• send_commands_from_file - send show commands from a file
• send_config - send one command in configuration mode
• send_configs - send a list of commands in configuration mode
• send_configs_from_file - send commands from file in configuration mode
All of these methods return a Response object, not the output of the command as a string.
120
Response object
The send_command method and other methods for sending commands return a
Response object (not the output of the command). Response allows you to get not only
the output of the command, but also such things as the execution time of the command,
whether there were errors during the execution of the command, structured output using
textfsm, and so on.
reply = ssh.send_command("sh clock") # Response <Success: True>
You can get the output of the command by accessing the result attribute:
print(reply.result) # '*17:31:54.232 UTC Wed Mar 31 2021'
For commands that take longer than normal show, it may be necessary to know the
command execution time:
r = ssh.send_command("ping 10.1.1.1")
r.result
# 'Type escape sequence to abort.\nSending 5, 100-byte ICMP Echos to
10.1.1.1,␣ ,→timeout is 2 seconds:\n.....\nSuccess rate is 0 percent
(0/5)'
r.elapsed_time # 10.047594
r.start_time # datetime.datetime(2022, 7, 1, 7, 10, 56, 63697)
r.finish_time # datetime.datetime(2022, 7, 1, 7, 11, 6, 111291)
The channel_input attribute returns the command that was sent to the equipment:
r.channel_input # 'ping 10.1.1.1'
send_command method
The send_command method allows you to send one command to a device.
121
The timeout_ops parameter specifies how long to wait for the command to execute:
ssh.send_command("ping 8.8.8.8", timeout_ops=20)
# Response <Success: True>
If the command does not complete within the specified time, a ScrapliTimeout exception
will be raised (output is truncated).
In addition to receiving normal command output, scrapli also allows you to receive
structured output, for example using the textfsm_parse_output method:
reply = ssh.send_command("sh ip int br")
reply.textfsm_parse_output()
# [{'intf': 'Ethernet0/0',
'ipaddr': '192.168.100.1',
'status': 'up',
'proto': 'up'},
{'intf': 'Ethernet0/1',
'ipaddr': '192.168.200.1',
'status': 'up',
'proto': 'up'}]
Note: Scrapli uses ready-made templates in order to receive structured output and in basic
cases does not require knowledge of TextFSM.
Error detection
Methods for sending commands automatically check the output for errors. For each
vendor/type of equipment, these are different errors, plus you can specify which lines in
the output will be considered an error. By default, IOSXEDriver will consider the following
lines as errors:
ssh.failed_when_contains
# ['% Ambiguous command',
'% Incomplete command',
'% Invalid input detected',
'% Unknown command']
The failed attribute of the Response object returns False if the command finished without
error and True if it failed.
reply = ssh.send_command("sh clck")
reply.result # " ^\n% Invalid input detected at '^' marker."
reply # Response <Success: False>
reply.failed # True
122
send_config method
The send_config method allows you to send one configuration mode command.
Example:
r = ssh.send_config("username user1 password password1")
Since scrapli removes the command from the output, by default, when using send_config,
the result attribute will contain an empty string (if there was no error while executing the
command).
send_commands, send_configs
The send_commands, send_configs methods differ from send_command,
send_config in that they can send several commands. In addition, these methods do not
return a Response, but a MultiResponse object, which can generally be thought of as a list
of Response objects, one for each command.
reply = ssh.send_commands(["sh clock", "sh ip int br"])
reply # MultiResponse <Success: True; Response Elements: 2>
for r in reply:
print(r)
print(r.result)
When sending multiple commands, it is also very convenient to use the stop_on_failed
parameter. By default, it is False, so all commands are executed, but if you specify
stop_on_failed=True, after an error occurs in some command, the following
commands will not be executed:
reply = ssh.send_commands(["ping 192.168.100.2", "sh clck", "sh ip int
br"], stop_on_failed=True)
123
Telnet connection
To connect to equipment via Telnet, you must specify transport equal to telnet and be sure
to specify the port parameter equal to 23 (or the port that you use to connect via Telnet):
from scrapli.driver.core import IOSXEDriver
from scrapli.exceptions import ScrapliException
import socket
r1 = {
"host": "192.168.100.1",
"auth_username": "cisco",
"auth_password": "cisco2",
"auth_secondary": "cisco",
"auth_strict_key": False,
"transport": "telnet",
"port": 23, # must be specified when connecting telnet
}
if __name__ == "__main__":
output = send_show(r1, "sh ip int br")
print(output)
Scrapli examples
Basic example of sending show command:
from scrapli.driver.core import IOSXEDriver
from scrapli.exceptions import ScrapliException
r1 = {
"host": "192.168.100.1",
"auth_username": "cisco",
"auth_password": "cisco",
"auth_secondary": "cisco",
"auth_strict_key": False,
124
"timeout_socket": 5, # timeout for establishing socket/initial
connection
"timeout_transport": 10, # timeout for ssh|telnet transport
}
if __name__ == "__main__":
output = send_show(r1, "sh ip int br")
print(output)
r1 = {
"host": "192.168.100.1",
"auth_username": "cisco",
"auth_password": "cisco",
"auth_secondary": "cisco",
"auth_strict_key": False,
"platform": "cisco_iosxe",
}
if __name__ == "__main__":
print("show".center(20, "#"))
output = send_show(r1, ["sh ip int br", "sh ver | i uptime"])
pprint(output, width=120)
125
An example of sending configuration commands with error checking:
from pprint import pprint
from scrapli import Scrapli
r1 = {
"host": "192.168.100.1",
"auth_username": "cisco",
"auth_password": "cisco",
"auth_secondary": "cisco",
"auth_strict_key": False,
"platform": "cisco_iosxe",
}
if __name__ == "__main__":
output_cfg = send_cfg(
r1, ["interfacelo11", "ip address 11.1.1.1 255.255.255.255"],
strict=True
)
print(output_cfg)
126
Tasks
Task 18.1
Create send_show_command function.
The function connects via SSH (using netmiko) to ONE device and executes the specified
command.
Function parameters:
• device - a dictionary with parameters for connecting to a device
• command - the command to be executed
The function should return a string with the command output.
The script should send command to all devices from the devices.yaml file using the
send_show_command function (this part of the code is written).
import yaml
if __name__ == "__main__":
command = "sh ip int br"
with open("devices.yaml") as f:
devices = yaml.safe_load(f)
Task 18.1a
Copy the send_show_command function from task 18.1 and rewrite it to handle the
exception that is thrown on authentication failure on the device.
Task 18.1b
Copy the send_show_command function from task 18.1a and rewrite it to handle not only
the exception that is raised when authentication fails on the device, but also the exception
that is raised when the IP address of the device is not available.
127
Task 18.2
Create send_config_commands function.
The function connects via SSH (using netmiko) to ONE device and executes a list of
commands in configuration mode based on the passed arguments.
Function parameters:
• device - a dictionary with parameters for connecting to a device
• config_commands - list of configuration commands to be executed
The function should return a string with the results of the command:
print(r1)
# {'device_type': 'cisco_ios',
'ip': '192.168.100.1',
'username': 'cisco',
'password': 'cisco',
'secret': 'cisco'}
print(commands)
# ['logging 10.255.255.1', 'logging buffered 20010', 'no logging
console']
The script should send command command to all devices from the devices.yaml file using
the send_config_commands function.
commands = [
'logging 10.255.255.1', 'logging buffered 20010', 'no logging
console'
]
128
Task 18.2a
Copy the send_config_commands function from job 18.2 and add the log parameter. The
log parameter controls whether information is displayed about which device the connection
is to:
• if log is equal to True - information is printed
• if log is equal to False - information is not printed
The script should send command to all devices from the devices.yaml file using the
send_config_commands function.
129