Fundamental Of Python¶
Devices can be manage by human with three ways. Python can be sumilate these with Python Libraries
graph TD
A[Device Management] --> B[GUI];
B[GUI] --> C([BeatifulSoup]);
B[GUI] --> D([Selenium]);
A[Device Management] --> E[Telnet / SSH];
E[Telnet / SSH] --> F([Netmiko]);
E[Telnet / SSH] --> G([Telnetlib]);
A[Device Management] --> H([API]);
H([API]) --> I([request]);
H([API]) --> J([zeep]);
Python can be used for network devices with below reason
- Backup Configuration
- Daily routine
- Automation Bulk Configuration
- Configuration Depend on Condition
- Pull information from device
- Health check
COMMON DATA TYPE IN PYTHON
String¶
- String can use single, double quotes
10.0.0.1
8
10.0.0.2
- or both
Einstein = "If you can't explain it simply, you don't understand it well enough"
print (Einstein)
print (len(Einstein))
If you can't explain it simply, you don't understand it well enough
67
-
STRING OPERATIONS
-
You can add strings together to concatenate them
10.0.0.110.0.0.2
- You can use whitespace between strings
10.0.0.1 10.0.0.2
- Easy way to add more whitespace between strings another words strings can be multiply
10.0.0.1 10.0.0.2
- You can't add strings and numbers
TypeError: can only concatenate str (not "int") to str
- But you can if you turn the number into a string first:
You are 40
- SOME ESCAPE CHARACTERS
If you can't explain it simply, you don't understand it well enough
Einstein = "If you can't explain it simply,\n\n you don't understand it well enough"
print (Einstein)
If you can't explain it simply,
you don't understand it well enough
nameandsurname = 'ilker\tmansur'
print (nameandsurname)
```
> ilker mansur
```python
Einstein = 'If you can\'t explain it simply, you don\'t understand it well enough'
print (Einstein)
'If you can\'t explain it simply, you don\'t understand it well enough'
- INDEX of STRING
i
l
k
e
r
- or specific part of string
ilker mansur
mansur
ilker
ke
- Actually data types ,that we use, are classes at the same time
- SOME METHOD of STR CLASS
2
False
True
True
ilker mansur
İLKER MANSUR
İlker Mansur
İlker Mansur
İlker Mansur
['10.0.0.1', '255.255.255.0']
['10', '0', '0', '1 255', '255', '255', '0']
20.0.0.1 255.255.255.0
PS: replace
converts all parameters which is match the given parameter, if you want to use one time or specific times, you should use extra parameter like ('10','20',2).
0.552.552.552 1.0.0.01
Integer & Float¶
- In network automation scripts, use str for expressing ip address instead of integer because of syntax
- MATH with operator ('+' '-' '*' '/' '//' '%')
11
7
4.5
4
1
- It is possibble to convert int <-> float
9.0
7
5
Boolean¶
- Booleans returns only 'True' or 'False'
False
True
False
True
False
True
True
False
List¶
- Lists are the object type called list, and at their most basic level are an ordered sequence of objects.
hostnames = ['r1' , 'r2' , 'r3' , 'r4' , 'r5']
commands = ['conf t' , 'interface Ethernet1/1' , 'no shutdown']
- Each object can be different data type
- Can be use each element from list
Eth1/1
Eth½
- SOME METHOD of LIST
voice_interfaces = ['Eth1/1' , 'Eth1/2']
data_interfaces = ['Eth1/1' , 'Eth1/2' , 'Eth1/3' , 'Eth1/4']
voice_interfaces.append('Eth1/3')
print(voice_interfaces)
['Eth1/1', 'Eth½', 'Eth⅓']
[]
3
['Eth1/1', 'Eth½', 'Eth⅓', 'Eth⅕', 'Eth¼']
['Eth1/1', 'Eth½', 'Eth⅓', 'Eth⅕', 'Eth¼', 'Eth⅙']
['Eth1/1', 'Eth⅓', 'Eth⅕', 'Eth¼', 'Eth⅙']
['Eth1/1', 'Eth⅓', 'Eth⅕', 'Eth¼']
['Eth1/1', 'Eth⅕', 'Eth¼']
['Eth1/1', 'Eth¼', 'Eth⅕']
port_status = ['connected' , 'notconnected', 'notconnected', 'notconnected' , 'connected']
print (port_status.count('connected'))
print (port_status.count('notconnected'))
2
3
Tuple¶
The tuple is an interesting data type and also best understood when compared to a list. It is like a list, but cannot be modified. We saw that lists are mutable, meaning that it is possible to update, extend, and modify them. Tuples, on the other hand, are immutable, and it is not possible to modify them once they’re created. Also, like lists, it’s possible to access individual elements of tuples.
('cisco', 'juniper', 'HP', 'Dell', 'Huawei', 'cisco')
2
0
juniper
('juniper', 'HP')
('cisco', 'juniper')
class 'tuple'>
Set¶
If you understand lists, you’ll understand sets. Sets are a list of elements, but there can only be one of a given element in a set, and additionally elements cannot be indexed.
deviceslist = ['cisco', 'juniper', 'HP', 'Dell', 'Huawei', 'cisco']
device_set = set (deviceslist)
print (device_set)
{'Huawei', 'HP', 'Dell', 'juniper', 'cisco'}
{'Dell', 'Huawei', 'cisco', 'juniper'}
- The pop() method removes a random item from the set. This method returns the removed item.
TypeError: pop() takes no arguments (1 given)
{'Huawei', 'cisco', 'juniper'}
- ADD \OR UPDATE USING SET
deviceset_1 = {'Huawei', 'Cisco', 'Juniper'}
deviceset_2 = {'Arista', 'Dell'}
deviceset_1.update(deviceset_2)
print (deviceset_1)
{'Arista', 'Juniper', 'Cisco', 'Dell', 'Huawei'}
{'Arista', 'Juniper', 'Cisco', 'Apple', 'Dell', 'Huawei'}
{'r', 'Dell', 'Huawei', 'e', 'a', 'Arista', 'M', 'i', 'k', 'Juniper', 'Cisco', 'Apple'}
Dictionary¶
We’ve now reviewed some of the most common data types, including strings, integers, booleans, and lists, which exist across all programming languages. In this section we take a look at the dictionary, which is a Python-specific data type. In other languages, they are known as associative arrays, maps, or hash maps. Dictionaries are unordered lists and their values are accessed by names, otherwise known as keys, instead of by index (integer). Dictionaries are simply a collection of unordered key-value pairs called items.
dict_keys(['vendor', 'hostname', 'OS'])
dict_values(['cisco', 'router01', 'IOS-XE'])
dict_items([('vendor', 'cisco'), ('hostname', 'router01'), ('OS', 'IOS-XE')])
cisco
{'vendor': 'cisco', 'hostname': 'router01', 'OS': 'IOS-XE'}
File¶
The key function for working with files in Python is the open() function. The open() function takes two parameters; filename and mode.
"r" - Read - Default value. Opens a file for reading, error if the file does not exist
"a" - Append - Opens a file for appending, creates the file if it does not exist
"w" - Write - Opens a file for writing, creates the file if it does not exist
"x" - Create - Creates the specified file, returns an error if the file exists
- EXP-1
test_file = open("testfile.txt", "w")
test_file.write("Bu bir deneme yazısıdır")
test_file.close()
x = open('testfile.txt')
print(x.read())
dosya = open('RT_01.txt', 'x')
dosya.write('conf t\ninterface gigabitethernet0/1\nno shutdown\n')
dosya.close()
x = open('RT_01.txt')
print(x.read())
Conditions in Python¶
-
There are two things to take note of with regard to syntax when you’re working with an if statement. First, all if statements end with a colon (:). Second, the code that gets executed if your condition is true is part of an indented block of code
-
EXP - 1
c is not equal 10
c is not equal "10"
- EXP - 2
number = input('Enter a number: ')
number = int(number)
if 50 <= number <= 100:
print (" your number is between 50 and 100")
elif number <= 50:
print (" Your number is smaller then 50")
else:
print (" Your number is bigger then 100")
- EXP - 3
our_staff_list = ['ahmet', 'ayla', 'bilal', 'berrin']
staff = input ('Please enter your name :')
if staff in our_staff_list:
print ('Hello '+staff+ ' you are welcome')
else :
print ('You are not our staff')
- EXP - 4
version = "CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.3.1, RELEASE"
if '16.3' in version:
print ('Your device is up to date')
Your device is up to date
Loops in Python¶
-
The general premise behind a while loop is that some set of code is executed while some condition is true. The syntax required is similar to what we used when creating if-elif-else statements. The while statement is completed with a colon (:) and the code to be executed is also indented four spaces.
-
EXP - 1
1
2
3
4
5
End of loop
- EXP - 2
counter = 1
while counter <= 5:
if counter % 2 == 0:
print (counter, ' is even number')
counter += 1
else:
print (counter, ' is odd number')
counter += 1
print ('End of loop')
1 is odd number
2 is even number
3 is odd number
4 is even number
5 is odd number
End of loop
- EXP - 3
cisco
juniper
dell
-
EXP - 4
-
find prime number between two numbers
num_1 = 1
num_2 = 15
for num in range (int(num_1),int(num_2)+1):
if num > 1:
for i in range (2,num):
if num % i ==0:
break
else:
print (str(num)+ ' is prime number')
2 is prime number
3 is prime number
5 is prime number
7 is prime number
11 is prime number
13 is prime number
Break / Continue / Pass usage¶
Break
stop the loop
Devices = ['RT01','RT02','RT03','SW01','SW02']
for dev in Devices:
if dev == 'RT03':
break
print (dev)
print ('end of loop')
RT01 RT02 end of loop
Continue
bypass the item but not stop the loop
Devices = ['RT01','RT02','RT03','SW01','SW02']
for dev in Devices:
if dev == 'RT03':
continue
print (dev)
print ('end of loop')
RT01 RT02 SW01 SW02 end of loop
The pass
statement is used as a placeholder for future code. When the pass statement is executed, nothing happens, but you avoid getting an error when empty code is not allowed. Empty code is not allowed in loops, function definitions, class definitions, or in if statements.
Functions¶
If you want to use code block againg and again, you should use function
.
this is first function
Functions insert between codes then continue after execution from this point
print ('this is 1')
print ('this is 2')
firstFunc()
print ('this is 3')
print ('this is 4')
firstFunc()
print ('this is 5')
this is 1 this is 2 this is function this is 3 this is 4 this is function this is 5
You can use parameter
def config_sw_port (interface,VlanID):
cfgstr = f'''
Interface {interface}
Switchport mode access
Switchport access vlan {VlanID}
'''
return cfgstr
print (config_sw_port ('gi0/1/0','10'))
print (config_sw_port ('gi0/1/1','20'))
Interface gi0/1/0 Switchport mode access Switchport access vlan 10
Interface gi0/1/1 Switchport mode access Switchport access vlan 20
PS: You have to use all parameters.
If you want to use parameter as optional:
18 23
For using result of function, there is an option 'return'. Lets test on example
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
25
When first return execute, function will end. Attention!
10
ARG and KWARG Usage¶
If you don't know that how many argument is insert to founction, you should use 'ARGS'
TypeError: sum() takes 2 positional arguments but 3 were given
you should use arg
def sum (Val):
print (type(Val))
sum(14) # type is 'int'
sum ('14') # type is 'str'
sum ({'hostname':'RT01'}) # type is 'dict'
60
If your values are dict, you should use 'kwargs'
def get_pers (**detail):
for data in detail:
print (data)
get_pers(username='cisco',password='Cisco1',port = 22)
username password port
def get_pers (**detail):
for data in detail.keys():
print (data)
get_pers(username='cisco',password='Cisco1',port = 22)
username password port
def get_pers (**detail):
for data in detail.values():
print (data)
get_pers(username='cisco',password='Cisco1',port = 22)
cisco Cisco1 22
def get_pers (**detail):
for data in detail.items():
print (data)
get_pers(username='cisco',password='Cisco1',port = 22)
('username', 'cisco') ('password', 'Cisco1') ('port', 22)
def get_pers (**detail):
for key,val in detail.items():
print (key,val)
get_pers(username='cisco',password='Cisco1',port = 22)
username cisco password Cisco1 port 22
ZIP Function Usage¶
The zip() function returns a zip object, which is an iterator of tuples where the first item in each passed iterator is paired together, and then the second item in each passed iterator are paired together etc.
VlanIDs = [10,20,30]
InterfaceList = ['Gi0/1', 'Gi0/2', 'Gi0/3']
for intcfg in zip (VlanIDs, InterfaceList):
vlan, interface = intcfg [0], intcfg [1]
cfgstr = f'''inter {interface}\nswitchport mode access\nswitchport access vlan {vlan}\n'''
print (cfgstr)
inter Gi0/1 switchport mode access switchport access vlan 10
inter Gi0/2 switchport mode access switchport access vlan 20
inter Gi0/3 switchport mode access switchport access vlan 30
Class Structure¶
Python is an object oriented programming language.Almost everything in Python is an object, with its properties and methods.
Lets compare with class and without class
dev1host = 'RT01'
dev1user = 'admin'
dev1password = 'admin1'
dev2host = 'SW01'
dev2user = 'cisco'
dev2password = 'cisco1'
class device ():
def __init__ (self,devhost,devusr,devpass):
self.host = devhost
self.user = devusr
self.password = devpass
dev1 = device('RT01','admin','admin1')
print (dev1.ad)
dev2 = device ('SW01','cisco','cisco1')
print (dev2.password)
device
class has three parameters: devhost,devusr,devpass. We clone a copy from this class and create an object
which has name dev1
. And we can create dev2
easly.
Some Python Libraries and Examples¶
- EXP - 1 (First netmiko program)
import netmiko
ip = "192.168.81.101"
user = "cisco"
pw = "cisco1"
device_type = "cisco_ios"
port = "22"
net_connect = netmiko.ConnectHandler(ip = ip, device_type = device_type, username = user, password = pw, port = port)
show_version = net_connect.send_command("show ip int brief")
print (show_version)
- Alternative
import netmiko
Cisco_IOSXE = {
"host" : "192.168.81.101",
"username" : "cisco",
"password" : "cisco1",
"device_type" : "cisco_ios"
}
net_connect = netmiko.ConnectHandler(**Cisco_IOSXE)
output = net_connect.send_command("show ip int brief")
print (output)
GigabitEthernet1 192.168.81.112 YES NVRAM up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
- EXP - 2 (While loop usage)
import netmiko
first_3_Octet = "192.168.81."
last_Octet = 101
while last_Octet <= 103 :
ip_ADDR = first_3_Octet + str(last_Octet)
Cisco_IOSXE = {
"ip" : ip_ADDR,
"username" : "cisco",
"password" : "cisco1",
"device_type" : "cisco_ios"
}
net_connect = netmiko.ConnectHandler(**Cisco_IOSXE)
output = net_connect.send_command("show ip int brief")
print (output)
print ("-"*80)
last_Octet += 1
output
----------------------------------- OUTPUT -------------------------------------
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.101 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.102 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.103 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
- EXP - 3 (Define function)
import netmiko
first_Three_Octet = "192.168.81."
last_Octet = 101
username = "cisco"
password = "cisco1"
device_type = "cisco_ios"
def sorgu(ip_Addr):
net_connect = netmiko.ConnectHandler(ip=ip_Addr, username=username, password=password, device_type=device_type)
return net_connect.send_command("show ip int brief")
while last_Octet <= 103:
ip_Addr = first_Three_Octet + str(last_Octet)
ip_Int_Br = sorgu(ip_Addr)
print (ip_Int_Br)
print ("-"*80)
last_Octet += 1
output
----------------------------------- OUTPUT -------------------------------------
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.101 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.102 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.103 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
import netmiko
device_List = ["192.168.81.101", "192.168.81.102", "192.168.81.103"]
for ip in device_List :
Cisco_IOSXE = {
"ip" : ip,
"username" : "cisco",
"password" : "cisco1",
"device_type" : "cisco_ios"
}
net_connect = netmiko.ConnectHandler(**Cisco_IOSXE)
output = net_connect.send_command("show ip int brief")
print (output)
print ("-"*80)
----------------------------------- OUTPUT -------------------------------------
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.101 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.102 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 192.168.81.103 YES manual up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
--------------------------------------------------------------------------------
import netmiko
Cisco_IOSXE = {
"ip" : "192.168.81.101",
"username" : "cisco",
"password" : "cisco1",
"device_type" : "cisco_ios"
}
net_connect = netmiko.ConnectHandler(**Cisco_IOSXE)
output = net_connect.send_command("show ip int brief")
print (output)
# for writing output to .txt file
writing_output = open ("config_file.txt","w")
writing_output.write(output)
writing_output.write("\n")
writing_output.write("-" * 80)
writing_output.write("\n")
writing_output.close()
# add some data to existing file
show_cpu = net_connect.send_command("show process cpu")
add_data = open ("config_file.txt", "a")
add_data.write(show_cpu)
add_data.close