[PYTHON] Try setting SSH (Exscript) from the software to the router

This is a 12/2 minute post of NetOpsCoding AdventCalender.

This time, while making network automation software, I will try to automate the router settings that will be the demon gate.

As for what is the demon gate, as of 2015, there are some APIs that are not provided for setting / controlling routers, and even if they are provided, they are often vendor-specific APIs, and it is a multi-vendor environment. In this network, it is easy to implement an automation program for each router model / OS.

Under such circumstances, specifications for industry standard APIs such as NETCONF / YANG / RESTCONF / Telemetry are being developed. However, at present, there are still issues to be solved when using it in a multi-vendor environment, such as those with manufacturer differences in the description contents that can be set, those that only work with the latest OS, and those that support limited functions. I will.

Therefore, this time, I will implement the flow of inputting the router settings from the software using SSH, which is the most versatile method, without using the provided API at all. In other words, the software replaces the sequence in which the network operator actually logs in to the router using SSH and inputs the settings using the CLI.

The method of automating using the SSH and Telnet packages provided for each programming language is much more versatile than using NETCONF etc. (anything that can be CLI-configured by a person is OK). On the other hand, software needs to analyze the output results and error messages of display commands that are originally visually confirmed by humans. In particular, it is not recommended because unknown error messages may appear or the software may be modified each time the display result changes due to the version upgrade of the router OS, but at the moment it is not recommended to use Telnet / SSH. There are many cases where it cannot be set, so it is a good idea to remember it as one of the means.

Execution environment

--Target router OS

Use the package Exscript to get information and set up the router by SSH. Expect is famous as an SSH package, but Exscript supports IOS, IOS-XR, JunOS, etc. in addition to Linux / Unix. Therefore, when receiving the output result from the router, it is very convenient because there is no need to perform analysis processing dedicated to the router.

This time, we will create an SSH setting program using the JUNOS router as an example, but if SSH / Telnet can be used, it can be set in the same flow with routers of other manufacturers.

Advance preparation

Make sure that you can SSH login to the router from the target server using the user account and password. No special settings other than SSH are required.

Program that executes the show command

First, let's write a program that executes a command that displays the contents set in the interface by ssh login to the router.

show_junos.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

from Exscript.protocols import SSH2
from Exscript.Account import Account

username = 'user1'
password = 'pass1'
ipv4 = '192.168.0.1'

#Establishing an SSH session
session = SSH2()
session.connect(ipv4)

#Log in to the router
session.login(Account(name=username, password=password))

#Send a command to the router and get the output result
print '='*40
print 'Step 1. run show command'
print '='*40
session.execute('show configuration interfaces xe-0/0/0 | no-more')
print session.response


#Disconnecting ssh session
if session:
    session.send('exit\r')
    session.close()
else:
    raise AttributeError('Cannot find a livied session')

When the program is executed, the contents set in the interface of the JUNOS router are output.

$ python show_junos.py

========================================
Step 1. run show command
========================================
show configuration interfaces xe-0/0/0 | no-more
disable;

user1@router>

Here you can see that only "disable" is set for interface xe- / 0/0/0.

Program to input interface settings

By devising the argument of the "session.execute ()" function of the above program, the settings will be input to the router.

Here, save the config you want to input in advance as a text file, and load the config file when the program is executed.

junos_config.txt


delete interfaces xe-0/0/0 disable
set interfaces xe-0/0/0 unit 0 family inet address 10.0.0.1/30

JUNOS provides several ways to load the config into your router.

  1. How to set using the set command from the CLI of the router
  2. How to transfer and place the config file on the router and load it with the load command

Here, as a general-purpose method that can be executed on a Cisco router, etc., set in "1. Setting using the set command from the CLI of the router".

The created program is as follows.

set_junos.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from Exscript.protocols import SSH2
from Exscript.Account import Account

username = 'user1'
password = 'pass1'
ipv4 = '192.168.0.1'

session = SSH2()
session.connect(ipv4)
session.login(Account(name=username, password=password))


print '='*40
print 'Step 1. run show command'
print '='*40
session.execute('show configuration interfaces xe-0/0/0 | no-more')
print session.response


print '='*40
print 'Step 2. read config file'
print '='*40
config_filename = sys.argv[1]
with open(config_filename, 'r') as config_file :
    config_lines = config_file.readlines()
    print config_filename
    print config_lines


print '='*40
print 'Step 3. run configure command'
print '='*40
session.execute('configure')
for config_line in config_lines :
    session.execute(config_line)
    print session.response


print '='*40
print 'Step 4. commit check'
print '='*40
session.execute('show | compare')
print session.response
session.execute('commi check')
print session.response


print '='*40
print 'Step 5. commit'
print '='*40
print 'Do you commit? y/n'
choice = raw_input().lower()
if choice == 'y':
    session.execute('commit')
    print session.response
else:
    session.execute('rollback')
    print session.response
session.execute('exit')
print session.response


print '='*40
print 'Step 6. run show command(again)'
print '='*40
session.execute('show configuration interfaces xe-0/0/0 | no-more')
print session.response


if session:
    session.send('exit\r')
    session.close()
else:

In the above, to make it easier to follow the flow, I wrote it without worrying about details such as devising the display, error handling, checking the return value from the router, etc. Actually, it is necessary to write error handling and timeout handling according to the character string returned by the router. As the number of error handling statements increases, it becomes difficult to see, so it is recommended to make it a function as needed.

And here is the result of running the program.

python set_junos.py junos_config.txt

========================================
Step 1. run show command
========================================
show configuration interfaces xe-0/0/0 | no-more
disable;

user1@router>
========================================
Step 2. read config file
========================================
junos_config.txt
['delete interfaces xe-0/0/0 disable\n', 'set interfaces xe-0/0/0 unit 0 family inet address 10.0.0.1/30\n']
========================================
Step 3. run configure command
========================================
delete interfaces xe-0/0/0 disable

[edit]
user1@router#

[edit]
user1@router#
set interfaces xe-0/0/0 unit 0 family inet address 10.0.0.1/30

[edit]
user1@router#

[edit]
user1@router#
========================================
Step 4. commit check
========================================
show | compare
[edit interfaces xe-0/0/0]
-   disable;
[edit interfaces xe-0/0/0]
+    unit 0 {
+        family inet {
+            address 10.0.0.1/30;
+        }
+    }

[edit]
user1@router#
commit check
configuration check succeeds

[edit]
user1@router#
========================================
Step 5. commit
========================================
Do you commit? y/n
y
commit
commit complete

[edit]
user1@router#
exit
Exiting configuration mode

user1@router>
========================================
Step 6. run show command(again)
========================================
show configuration interfaces xe-0/0/0 | no-more
unit 0 {
    family inet {
        address 10.0.0.1/30;
    }
}

user1@router>

In this way, you can write a program to configure the router from the software using SSH.

This is not the goal.

As mentioned in the middle, when actually entering the settings in the router, "processing when the configuration is incorrect", "processing when the router returns an error", "processing when the SSH session cannot be established" It is necessary to implement it as a program.

Furthermore, this time, the program is created on the premise that "people judge" "confirm the show command" and "whether commit can be executed", but from the viewpoint of automation,

The program itself
(1)Check the result of show command and error output,
(2)Input the config
(3)After judging that there is no problem,
(4)Commit and
(5)Test that the network settings are as expected

Process is required.

If you try to implement the above process, you will need to analyze the output with the show command, which will inevitably result in a complicated program.

In order to reduce the complexity of such programming, easy mechanisms for software such as NETCONF and Telemetry are being prepared. However, NETCONF and RESTCONF only make it easier to set up the router and acquire information, and the other processes still need to be implemented by the developer himself, so there are still some challenges in automation. I have.

Finally

There is no end to the issues, but the trend toward network operation automation is to make things that move steadily little by little through trial and error, and to further evolve the program while reducing our man-hours. I feel that it is a shortcut. First of all, let's do our best together step by step because we can do it ourselves. And if you take it one step further, brag about it on blogs and NetOps Coding events. What you are in trouble is that everyone is in trouble. We look forward to your pride.

Recommended Posts

Try setting SSH (Exscript) from the software to the router
Try setting NETCONF (ncclient) from software to the router
Setting to specify the IP allowed for SSH connection
[Postgresql] SSH connection to the external DB server from the client
[Python] Try to graph from the image of Ring Fit [OCR]
Try to introduce the theme to Pelican
Ssh connect to GCP from Windows
Cython to try in the shortest
The fastest way to try EfficientNet
From "drawing" to "writing" the configuration diagram: Try drawing the AWS configuration diagram with Diagrams
The easiest way to try PyQtGraph
Try using the Python web framework Django (1)-From installation to server startup
Try to face the integration by parts
How to operate Linux from the console
Python amateurs try to summarize the list ①
How to access the Datastore from the outside
Try to write code from 1 using the machine learning framework chainer (mnist edition)
SSH login to the target server from Windows with a click of a shortcut
Let's try TensorFlow music generation project "Magenta" from development environment setting to song generation.
Try to solve the fizzbuzz problem with Keras
Log in to the remote server with SSH
Try adding fisheye lens distortion to the image
Try to decompose the daimyo procession into Tucker
Try to solve the Python class inheritance problem
Setting to output the log of cron execution
Try to solve the man-machine chart with Python
How to try the friends-of-friends algorithm with pyfof
Change the decimal point of logging from, to.
How to operate Linux from the outside Procedure
POST images from ESP32-CAM (MicroPython) to the server
How to measure line speed from the terminal
From the introduction of pyethapp to the execution of contract
Try accessing the YQL API directly from Python 3
Try to simulate the movement of the solar system
The story of moving from Pipenv to Poetry
Try posting to Qiita for the first time
Try to create a battle record table with matplotlib from the data of "Schedule-kun"
Give latitude and longitude point sequence data and try to identify the road from OpenStreetMap data