Hello my friend,
In the previous blogpost we’ve started the discussion about the instructions, which yo need to know in order to create a Python’s code. Namely, we you have learned how to create and use for loops for the Python’s lists and dictionaries. Today you will learn how to create conditionals.
Network automation training – boost your career
Don’t wait to be kicked out of IT business. Join our network automation training to secure your job in future. Come to NetDevOps side.
How does the training differ from this blog post series? Here you get the basics and learn some programming concepts in general, whereas in the training you get comprehensive set of knowledge with the detailed examples how to use Python for the network and IT automation. You need both.
What are we going to do today?
Together with the the loops, the conditionals create a basis of almost each and every script. You would use them, when you need to make a decision about an action you code should execute, when there are multiple actions available and they are dependent in some facts. Therefore, you will learn:
- How to create a conditional instruction using if .. elif .. else .. framework.
- Why and how to use that framework partially (e.g. use only if .. or if .. elif ..).
- How to use if .. conditional together with for loop for creation of a meaningful code for the network function’s config generation.
In addition to that you will learn how to use if .. conditional with the multiple statements for a more sophisticated checks, which are very common in the network automation environment.
If you want to know how to install Python 3.8, check the corresponding blogpost.
Why does it matter?
Every day you need to make decision, what to dress or where to go. So your network functions make decisions:
- To pass or drop the packets based on the access-list rules
- To modify or not the route updates based on the match criteria in the route policies
- To clean the MAC address tables based on the ageing timer
- And many more
That’s why you can find the conditionals absolutely everywhere. That’s why the Python’s code will have it anyway. From the perspective of the network automation coding, here are some insights for you:
- Set the interface to shutdown / no shutdown state based on the key in the interface’s dictionary
- Set the interface to routed or switched state based on the presence or absence of the IP address’s key
- Configure the routing protocol details based on the provided key/value pairs or leave the default, if nothing is provided
The provided list is very tiny, but even it provides you ideas, where and how the if .. else .. conditionals could be used in your Python’s code to make it really production grade.
How are we doing that?
Following the approach, we have started earlier, we create a new directory in our GitHub Python’s lessons:
1
2
3
4 $ cd CEX
$ mkdir 08
$ cd 08
$
Inside the directory we create a new file called conditionals.py, which we will use during this class:
1
2
3 $ touch conditionals.py && chmod a+x conditionals.py
$ cat conditionals.py
#!/usr/local/bin/python3.8
If you have a question to chmod command or to the path to the Python interpreter, take a look on the corresponding class .
Before we kick off with the Python’s script development, let’s take a look on the syntax. Generally, it looks as
1
2
3
4
5
6 if condition1:
action1
elif condition[2..N]:
action[2..N]
else:
actionX
- The if instruction starts the conditional check
- In case the condition1 is True, then the action1 associated with this statement is performed and the script’s execution continues further outside the conditional (i.e. no more checks).
- In case the condition1 was False and there are no more conditionals defined, the script’s execution continues further outside the conditional (i.e. no more checks) without any actions done out of the original condition.
- In case the condition1 was False and the there are more statements (elif or else), the check is going to the next one in the sequence they are defined.
- The elif works in the same was as if, meaning to run the defined actions[2..N] the associated condition[2..N] must be True.
- The else statement works in case there were no previous matches (no conditions were True) and it always comes as the last stamens in the conditional instruction. So the actionX is executed.
Now you know the process how it works and you are equipped with the knowledge to transform them in your Python skills.
#1. Preparing the test input
Following the previous discussion about Python’s list and Python’s dictionary, we will create a joint variable, which will use as an input to the for loop:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 $ cat conditional.py
#!/usr/local/bin/python3.8
interfaces = [
{'name': 'Ethernet1', 'enabled': True, 'ipv4': '192.168.100.1/24'},
{'name': 'Ethernet2', 'enabled': False, 'vlan': 'tagged'}
]
config_lines = []
for iface_entry in interfaces:
config_lines.append('interface {}'.format(iface_entry['name']))
config_lines.append('!')
for line in config_lines:
print(line)
In a nutshell, we create a list interfaces, which contain two dictionaries, each having various variables’ types. We also create list config_lines, which will be populated with the configuration commands during the for loop execution. And it is starting getting populated with the append() function.
If you have questions to what is explained above, refer to the corresponding CEX blogposts.
#2. Conditional for the Boolean logic
The simplest form is an if .. else .. instruction, where the actions associated with one of the two conditional statements will be executed anyway. This works perfectly, when you have variable of the Boolean type, which only has values True or False:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 $ cat conditional.py
#!/usr/local/bin/python3.8
interfaces = [
{'name': 'Ethernet1', 'enabled': True, 'ipv4': '192.168.100.1/24'},
{'name': 'Ethernet2', 'enabled': False, 'vlan': 'tagged'}
]
config_lines = []
for iface_entry in interfaces:
config_lines.append('interface {}'.format(iface_entry['name']))
if iface_entry['enabled']:
config_lines.append(' no shutdown')
else:
config_lines.append(' shutdown')
config_lines.append('!')
for line in config_lines:
print(line)
The key enabled from the elements of the list interfaces has a Boolean type. Therefore, we create an if .. else .. conditional, which adds the element to the resulting list config_lines using the append() function. In case the enabled key is True, you add ‘ no shutdown’ string; otherwise, ‘ shutdown’ is added.
Once you execute the script, you can see the following output:
1
2
3
4
5
6
7 $ ./conditional.py
interface Ethernet1
no shutdown
!
interface Ethernet2
shutdown
!
#3. Checking if the key exists and multiple conditional in one statement
Another very popular case in the network automation world with the Python is to check, if a specific key exist in the Python’s dictionary or in the Python’s list (the check is the same) and to act upon that.
If you carefully take a loon on the original interfaces list, you will see that one element has a key ipv4, whereas another doesn’t. The Python’s code deal with that will be the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 $ cat conditional.py
#!/usr/local/bin/python3.8
interfaces = [
{'name': 'Ethernet1', 'enabled': True, 'ipv4': '192.168.100.1/24'},
{'name': 'Ethernet2', 'enabled': False, 'vlan': 'tagged'}
]
config_lines = []
for iface_entry in interfaces:
config_lines.append('interface {}'.format(iface_entry['name']))
if iface_entry['enabled']:
config_lines.append(' no shutdown')
else:
config_lines.append(' shutdown')
if 'ipv4' in iface_entry or 'ipv6' in iface_entry:
config_lines.append(' no switchport')
else:
config_lines.append(' switchport')
config_lines.append('!')
for line in config_lines:
print(line)
In this snippet we are checking the presence the key ipv4 or ipv6 in the dictionary iface_entry. If it was the list, then such a check would look for an element with the value ipv4 or ipv6. You also see a conjunction “or“, which means that at the associated actions are taken in case ANY of these checks is True.
If you want to execute the action if BOTH checks are true, use “and” conjunction.
Here is the Boolean logic summary for you:
Condition 1 | Condition 2 | Conjunction | Result |
True | True | and | True |
True | False | and | False |
False | True | and | False |
False | False | and | False |
True | True | or | True |
True | False | or | True |
False | True | or | True |
False | False | or | False |
The execution of this Python’s script provide the following result for you:
1
2
3
4
5
6
7
8
9 $ ./conditional.py
interface Ethernet1
no shutdown
no switchport
!
interface Ethernet2
shutdown
switchport
!
#4. Nested conditionals and if .. without else ..
If your logic requires multiple levels of conditionals, you can nest them as deep as you like. That would allow you to create quite a flexible decision-making.
Before you will see how this is achieved, there is one more point you might consider during designing your Python script. It might be, that you need to make some option on a condition, which does not include any action to happen in case the conditional check is False. That is easy, as the only mandatory part of the if .. conditional is the if .. itself; both elif .. and else .. are optional. The following example shows how you can achieve in the Python script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 $ cat conditional.py
#!/usr/local/bin/python3.8
interfaces = [
{'name': 'Ethernet1', 'enabled': True, 'ipv4': '192.168.100.1/24'},
{'name': 'Ethernet2', 'enabled': False, 'vlan': 'tagged'}
]
config_lines = []
for iface_entry in interfaces:
config_lines.append('interface {}'.format(iface_entry['name']))
if iface_entry['enabled']:
config_lines.append(' no shutdown')
else:
config_lines.append(' shutdown')
if 'ipv4' in iface_entry or 'ipv6' in iface_entry:
config_lines.append(' no switchport')
if 'ipv4' in iface_entry:
config_lines.append(' ipv4 address {}'.format(iface_entry['ipv4']))
if 'ipv6' in iface_entry:
config_lines.append(' ipv6 address {}'.format(iface_entry['ipv6']))
else:
config_lines.append(' switchport')
if iface_entry['vlan'] == 'tagged':
config_lines.append(' switchport mode trunk')
elif iface_entry['vlan'] == 'untagged':
config_lines.append(' switchport mode access')
config_lines.append('!')
for line in config_lines:
print(line)
You can see that if ‘ipv4’ in iface_entry doesn’t have any else statement, which is perfectly fine.
Besides that, in the snippet above you can also find the conditional check, where you compare the value of a certain key to a string value. If there is a full match then condition is true: iface_entry[‘vlan’] == ‘untagged’.
The result of this Python script execution gives you the following result:
1
2
3
4
5
6
7
8
9
10
11 $ ./conditional.py
interface Ethernet1
no shutdown
no switchport
ipv4 address 192.168.100.1/24
!
interface Ethernet2
shutdown
switchport
switchport mode trunk
!
#5. Grouping multiple checks.
The last point we’ll cover in this blogpost today is the grouping of the checks. You have already seen the usage of the or and and conjunction. If you have a sophisticated condition, where multiple different checks are to be done, you can also use round brackets “(” and “)” to group the certain blocs together. That allows you to group the checks together and take their joint result for the further comparison per the Boolean logic shared above.
Let’s modify the previous code by adding stricter conditional for checking the IP address and VLAN presence to avoid the situation that the interface’s Python dictionary has both. We also add a new element into interfaces list to test that :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 $ cat conditional.py
#!/usr/local/bin/python3.8
interfaces = [
{'name': 'Ethernet1', 'enabled': True, 'ipv4': '192.168.100.1/24'},
{'name': 'Ethernet2', 'enabled': False, 'vlan': 'tagged'},
{'name': 'Ethernet3', 'enabled': True, 'ipv4': '192.168.101.1/24', 'vlan': 'tagged'}
]
config_lines = []
for iface_entry in interfaces:
config_lines.append('interface {}'.format(iface_entry['name']))
if iface_entry['enabled']:
config_lines.append(' no shutdown')
else:
config_lines.append(' shutdown')
if ('ipv4' in iface_entry or 'ipv6' in iface_entry) and 'vlan' not in iface_entry:
config_lines.append(' no switchport')
if 'ipv4' in iface_entry:
config_lines.append(' ipv4 address {}'.format(iface_entry['ipv4']))
if 'ipv6' in iface_entry:
config_lines.append(' ipv6 address {}'.format(iface_entry['ipv6']))
elif 'vlan' in iface_entry and not ('ipv4' in iface_entry or 'ipv6' in iface_entry):
config_lines.append(' switchport')
if iface_entry['vlan'] == 'tagged':
config_lines.append(' switchport mode trunk')
elif iface_entry['vlan'] == 'untagged':
config_lines.append(' switchport mode access')
else:
config_lines.pop(-1)
config_lines.append(' descriontion THERE IS SOME MESS WITH VARS')
config_lines.append(' shutdown')
config_lines.append('!')
for line in config_lines:
print(line)
The newly added element in the list interfaces contains both the ‘ipv4‘ and ‘vlan‘ keys, what should not be the case per our logic. Therefore, we create the following conditions:
- if key ‘ipv4‘ or ‘ipv6‘ exists and no key ‘vlan‘ exists, then we add the ipv4 configuration.
- if key ‘vlan’ exists and there are no keys ‘ipv4’ or ‘ipv6’, then we add the VLAN configuration
- Otherwise, we put interface to the shutdown state by deleting the shutdown / no shutdown command generated by the ‘enabled‘ key and adding explicit ‘shutdown’. Also we add the description that there is something weird with the keys.
And here is how it works:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 $ ./conditional.py
interface Ethernet1
no shutdown
no switchport
ipv4 address 192.168.100.1/24
!
interface Ethernet2
shutdown
switchport
switchport mode trunk
!
interface Ethernet3
descriontion THERE IS SOME MESS WITH VARS
shutdown
!
#6. List of the most widely used conditional checks in the network automation
There are multiple other possible checks, which you might need to have in your code. We tried to summarise the vast majority of them for you:
Conditional statement | Description |
sting_var == ‘text’ | The value of the sting_var is compared with the string ‘text’. True if it matches exactly. |
sting_var != ‘text’ | The value of the sting_var is compared with the string ‘text’. True if it does NOT match exactly. |
‘text’ in sting_var | The substring ‘text’ must present inside the sting_var value. True if it presents. |
int_var == 10 | The value of the int_var is compared with the number. True if that they are equal. |
int_var [<, >, <=, >=, !=] 10 | The value of the int_var is compared with the number. True if that it is [less, greater, less or equal, greater or equal, don’t equal] than value. |
‘text’ in dictionary | The key with the name ‘text’ is looked for into the dictionary. True if it exists. |
‘text’ in list | The element with the value ‘text’ is looked for into the list. True if it exists. |
var_name | Checks the element value and depends on the variable type: – digit: True if not 0 – string: True if not ” (empty string) – Boolean: True if True |
If any of these checks are prepended by “not” keyword, than their result are inverted.
If you prefer video
If you prefer watching the video instead of reading blogpost, that is also wonderful. We value your time and want to create for you the best experience possible. Therefore, for all the blogposts associated with CEX series, we will record the video and post it on our YouTube channel.
And here is the video for this blogpost:
What else shall you try?
Programming is all around testing, trying, breaking and fixing the things. Try to do the following things to collect some more experience:
- Create a Python list or a Python dictionary with the sample configuration of the routing protocol you use (e.g. OSPF or ISIS).
- Generate the config lines in the lines based on the conditional you might have depending on your topology.
- Use all the concepts explained in this blogpost.
Lessons in GitHub
You can find the final working versions of the files from this blog at our GitHub page.
Conclusion
The for loop and the if conditional is a foundation of almost all the Python’s script. Having master them, you can start developing some logic, which could help you to solve some basic tasks. But this basics tasks might be taking quite a huge amount of your time. Take care and goodbye!
Support us
P.S.
If you have further questions or you need help with your networks, I’m happy to assist you, just send me message. Also don’t forget to share the article on your social media, if you like it.
BR,
Anton Karneliuk