Connect to Devices Running Junos OS Using Junos PyEZ
Junos PyEZ is a microframework for Python that
enables you to manage devices running Junos OS. Junos PyEZ models
each device as an instance of the jnpr.junos.device.Device class. The Device
class enables you to connect to a device running Junos OS using
a serial console connection, telnet, or by establishing a NETCONF
session over SSH. In addition, Junos PyEZ also supports connecting
to the device through a telnet or SSH connection to a console server.
A console server, also known as a terminal server, is a specialized
device that provides a network connection to a device’s out-of-band
management console port.
This topic provides an overview of the connection methods supported by Junos PyEZ and explains how to use the different methods to connect to a device running Junos OS. The Junos PyEZ examples use various authentication methods, but for detailed information about authenticating a user, see Authenticate Junos PyEZ Users.
Connection Methods Overview
Junos PyEZ enables you to connect to devices running Junos OS using a serial console connection, telnet, or a NETCONF session over SSH. You must use a serial console connection when you are physically connected to the CONSOLE port on a device. You can use telnet or SSH to connect to the device’s management interface or to a console server that is connected to the device’s CONSOLE port. In addition, Junos PyEZ supports outbound SSH connections, in which the device running Junos OS initiates the connection with the client management application.
New or zeroized devices that have factory default configurations require access through a console connection. Thus, you can use Junos PyEZ to initially configure a device that is not yet configured for remote access by using either a serial console connection when you are directly connected to the device or by using telnet or SSH through a console server that is connected to the device.
By default, Junos PyEZ uses SSH to connect to a device . To
specify a different connection type, you must include the mode
parameter in the Device
argument list. To telnet to a device, include the mode='telnet'
argument. To connect to a device using a serial console connection,
include the mode='serial'
argument. Table 1 summarizes the Junos
PyEZ connection methods, their default values for certain parameters,
any required Junos OS configuration, and the Junos PyEZ release in
which support for that connection method was first introduced.
Connection Mode |
Value of |
Default Port |
Required Junos OS Configuration |
First Supported Junos PyEZ Release |
---|---|---|---|---|
NETCONF over SSH (default) |
– |
830 |
[edit system services] netconf { ssh; } |
1.0.0 |
Serial console connection |
serial |
/dev/ttyUSB0 |
– |
2.0.0 (*nix) 2.4.0 (Windows) |
Telnet to device running Junos OS |
telnet |
23 |
[edit system services] telnet; |
2.0.0 |
Telnet through a console server |
telnet |
23 |
– |
2.0.0 |
SSH through a console server |
– |
22 |
– |
2.2.0 |
Outbound SSH |
– |
– |
[edit system services] outbound-ssh { ... } |
2.2.0 |
Before you can access a device’s management interface
using telnet or NETCONF over SSH, you must first enable the appropriate
service at the [edit system services]
hierarchy level.
For more information, see Set Up Junos
PyEZ Managed Nodes. Because telnet uses clear-text passwords
(therefore creating a potential security vulnerability), we recommend
that you use SSH.
It is the user's responsibility to obtain the username and password authentication credentials in a secure manner appropriate for their environment. It is best practice to prompt for these authentication credentials during each invocation of the script, rather than storing the credentials in an unencrypted format.
Junos PyEZ supports using context managers (with
... as
syntax) for all connection
methods. When you use a context manager, Junos PyEZ automatically
calls the open()
and close()
methods to connect to and disconnect from the device. If you do
not use a context manager, you must explicitly call the open()
and close()
methods
in your application. We recommend that you use a context manager for
console connections, because the context manager automatically handles
closing the connection, and failure to close the connection can lead
to unpredictable results.
Understanding Junos PyEZ Connection Properties
When you connect to a device running Junos OS, Junos PyEZ stores
information about the current connection as properties of the Device
instance. Table 2 outlines the available connection properties.
Property |
Description |
---|---|
|
Boolean specifying the current state of the connection.
Returns |
|
String specifying the hostname of the device to which the application is connected. |
|
Boolean returning |
|
Integer or string specifying the port used for the connection. |
|
String specifying the Routing Engine name to which the application is connected. |
|
Integer specifying the RPC timeout value in seconds. |
|
Integer representing the number of seconds since the current Routing Engine was booted. This property is available starting in Junos PyEZ Release 2.1.5. |
|
String specifying the user accessing the device running Junos OS. |
For example, after connecting to a device, you can query the connected
property to return the current state of the
connection. A SessionListener
monitors
the session and responds to transport errors by raising a TransportError
exception and setting the Device.connected
property to False
.
The following sample code prints the value of the connected
property after connecting to a device running
Junos OS and again after closing the session.
from jnpr.junos import Device dev = Device(host='router.example.net') dev.open() print (dev.connected) dev.close() print (dev.connected)
When you execute the program, the connected
property returns True
while the application
is connected to the device and returns False
after the connection is closed.
user@host:~$ python connect.py True False
Connect to a Device Using SSH
The Junos PyEZ Device
class supports
using SSH to connect to a device running Junos OS. You can establish
a NETCONF session over SSH with the device’s management interface
or you can establish an SSH connection with a console server that
is directly connected to the device’s CONSOLE port. The SSH server must be able to authenticate the user using
standard SSH authentication mechanisms, as described in Authenticate Junos PyEZ Users. To establish
a NETCONF session over SSH, you must also satisfy the requirements
outlined in Set Up Junos PyEZ Managed
Nodes.
Junos PyEZ automatically queries the default SSH configuration file at ~/.ssh/config, if one exists. When using SSH to connect to a device running Junos OS or to a console server connected to the device, Junos PyEZ first attempts SSH public key-based authentication and then tries password-based authentication. When password-based authentication is used, the supplied password is used as the device password. When SSH keys are in use, the supplied password is used as the passphrase for unlocking the private key. If the SSH private key has an empty passphrase, then a password is not required. However, SSH private keys with empty passphrases are not recommended.
To establish a NETCONF session over SSH with a device running Junos OS and print the device facts in a Junos PyEZ application using Python 3:
The sample program in its entirety is presented here:
import sys from getpass import getpass from jnpr.junos import Device from jnpr.junos.exception import ConnectError hostname = input("Device hostname: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS or SSH key password: ") dev = Device(host=hostname, user=junos_username, passwd=junos_password) try: dev.open() except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) sys.exit(1) except Exception as err: print (err) sys.exit(1) print (dev.facts) dev.close()
Alternatively, you can use a context manager when connecting
to the device, which automatically calls the open()
and close()
methods. For example:
import sys from getpass import getpass from jnpr.junos import Device from jnpr.junos.exception import ConnectError hostname = input("Device hostname: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS or SSH key password: ") try: with Device(host=hostname, user=junos_username, passwd=junos_password) as dev: print (dev.facts) except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) sys.exit(1) except Exception as err: print (err) sys.exit(1)
Junos PyEZ also enables a client to connect to a device running
Junos OS through an SSH connection to a console server. In this case,
you must specify the login credentials for the console server by including
the cs_user
and cs_passwd
arguments in the Device
argument list.
When SSH keys are in use, set the cs_passwd
argument to the variable containing the passphrase for the private
key.
The console server connects to the device running Junos OS through
a serial connection, which can be slow. Junos PyEZ connections through
a console server have a default connection timeout value of 0.5 seconds.
As a result, you might need to increase the connection timeout interval
by including the Device
timeout=seconds
argument to allow sufficient time
for the client application to establish the connection.
The following Python 3 example authenticates with the console server and then the device running Junos OS. The connection timeout is set to six seconds so that the client has sufficient time to establish the connection.
import sys from getpass import getpass from jnpr.junos import Device from jnpr.junos.exception import ConnectError hostname = input("Console server hostname: ") cs_username = input("Console server username: ") cs_password = getpass("Console server or SSH key password: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS password: ") try: with Device(host=hostname, user=junos_username, passwd=junos_password, cs_user=cs_username, cs_passwd=cs_password, timeout=6) as dev: print (dev.facts) except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) sys.exit(1) except Exception as err: print (err) sys.exit(1)
Junos PyEZ automatically queries the default SSH configuration
file at ~/.ssh/config, if one exists.
However, starting with Junos PyEZ Release 1.2, you can specify a different
SSH configuration file when you create the device instance by including
the ssh_config
parameter in the Device
argument list. For example:
ssh_config_file = "~/.ssh/config_dc" dev = Device(host='198.51.100.1', ssh_config=ssh_config_file)
Also, starting in Junos PyEZ Release 1.2, Junos PyEZ provides support for ProxyCommand, which enables you to access a target device through an intermediary host that supports netcat. This is useful when you can only log in to the target device through the intermediate host.
To configure ProxyCommand, add the appropriate information to the SSH configuration file. For example:
[user1@server ~]$ cat ~/.ssh/config Host 198.51.100.1 User user1 ProxyCommand ssh -l user1 198.51.100.2 nc %h 22 2>/dev/null
Connect to a Device Using Outbound SSH
You can configure a device running Junos OS to initiate a TCP/IP
connection with a client management application that would be blocked
if the client attempted to initiate the connection (for example, if
the device is behind a firewall). The outbound-ssh
configuration
instructs the device to create a TCP/IP connection with the client
management application and to forward the identity of the device.
Once the connection is established, the management application acts
as the client and initiates the SSH sequence, and the device acts
as the server and authenticates the client.
There is no initiation command with outbound SSH. Once outbound SSH is configured and committed, the device begins to initiate an outbound SSH connection based on the committed configuration. The device repeatedly attempts to create this connection until successful. If the connection between the device and the client management application is dropped, the device again attempts to create a new outbound SSH connection until successful. This connection is maintained until the outbound SSH stanza is removed from the configuration.
To configure the device running Junos OS for outbound SSH connections,
include the outbound-ssh
statement at the [edit system
services]
hierarchy level. In the following example, the device
running Junos OS attempts to initiate a connection with the host at
198.51.100.101 on port 2200:
user@router1> show configuration system services outbound-ssh client outbound-ssh { device-id router1; secret "$9$h1/ceWbs4UDkGD/Cpu1I-Vb"; ## SECRET-DATA services netconf; 198.51.100.101 port 2200; }
To establish a connection with the device running Junos OS using
outbound SSH, the Junos PyEZ application sets the sock_fd
argument in the Device
constructor equal
to the file descriptor of an existing socket and either omits the host
argument or sets it to None
.
The following Junos PyEZ example listens on the configured
TCP port for incoming SSH sessions from devices running Junos OS.
The application accepts an incoming connection and retrieves the socket’s
file descriptor for that connection, which is used for the value of
the sock_fd
argument. The client application
establishes the SSH connection with the device, collects and prints
the device facts, disconnects from the device, and waits for more
connections.
import socket from jnpr.junos import Device from jnpr.junos.exception import ConnectError from getpass import getpass from pprint import pprint """ Listen on TCP port 2200 for incoming SSH session with a device running Junos OS. Upon connecting, collect and print the devices facts, then disconnect from that device and wait for more connections. """ def launch_junos_proxy(client, addr): val = { 'MSG-ID': None, 'MSG-VER': None, 'DEVICE-ID': None } msg = '' count = 3 while len(msg) < 100 and count > 0: c = client.recv(1) if c == '\r': continue if c == '\n': count -= 1 if msg.find(':'): (key, value) = msg.split(': ') val[key] = value msg = '' else: msg += str(c) print('MSG %s %s %s' % (val['MSG-ID'], val['MSG-VER'], val['DEVICE-ID'])) return client.fileno() def main(): PORT = 2200 junos_username = input('Junos OS username: ') junos_password = getpass('Junos OS password: ') s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('', PORT)) s.listen(5) print('\nListening on port %d for incoming sessions ...' % (PORT)) sock_fd = 0 while True: client, addr = s.accept() print('\nGot a connection from %s:%d' % (addr[0], addr[1])) sock_fd = launch_junos_proxy(client, addr) print('Logging in ...') try: with Device(host=None, sock_fd=sock_fd, user=junos_username, passwd=junos_password) as dev: pprint(dev.facts) except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) if __name__ == "__main__": main()
user@server:~$ python3 junos-pyez-outbound-ssh.py Junos OS username: user Junos OS password: Listening on port 2200 for incoming sessions ... Got a connection from 10.10.0.5:57881 MSG DEVICE-CONN-INFO V1 router1 Logging in ... {'2RE': True, 'HOME': '/var/home/user', 'RE0': {'last_reboot_reason': 'Router rebooted after a normal shutdown.', 'mastership_state': 'master', 'model': 'RE-MX-104', 'status': 'OK', 'up_time': '2 days, 6 hours, 22 minutes, 22 seconds'}, 'RE1': {'last_reboot_reason': 'Router rebooted after a normal shutdown.', 'mastership_state': 'backup', 'model': 'RE-MX-104', 'status': 'OK', 'up_time': '2 days, 6 hours, 22 minutes, 12 seconds'}, 'RE_hw_mi': False, 'current_re': ['re0', 'master', 'node', 'fwdd', 'member', 'pfem'], 'domain': 'example.com', 'fqdn': 'router1.example.com', 'hostname': 'router1', ...
For detailed information about configuring outbound SSH on devices running Junos OS, see Configuring Outbound SSH Service.
Connect to a Device Using Telnet
The Junos PyEZ Device
class supports
connecting to a device running Junos OS using telnet, which provides
unencrypted access to the network device. You can telnet to the device’s
management interface or to a console server that is directly connected
to the device’s CONSOLE port. You must
configure the Telnet service at the [edit system services]
hierarchy level on all devices that require access to the management
interface. Accessing the device through a console server enables you
to initially configure a new or zeroized device that is not yet configured
for remote access.
To use Junos PyEZ to telnet to a device running Junos OS, you
must include mode='telnet'
in the Device
argument list, and optionally include the port
parameter to specify a port. When you specify mode='telnet'
but omit the port
parameter, the value for port
defaults
to 23. When the application connects through a console server, specify
the port through which the console server connects to the device running
Junos OS.
To use Junos PyEZ to telnet to a device running Junos OS and print the device facts in a Junos PyEZ application using Python 3:
The sample program in its entirety is presented here:
import sys from getpass import getpass from jnpr.junos import Device hostname = input("Device hostname: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS password: ") dev = Device(host=hostname, user=junos_username, passwd=junos_password, mode='telnet', port='23') try: dev.open() except Exception as err: print (err) sys.exit(1) print (dev.facts) dev.close()
Alternatively, you can use a context manager when connecting to the device, which handles opening and closing the connection. For example:
import sys from getpass import getpass from jnpr.junos import Device hostname = input("Device hostname: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS password: ") try: with Device(host=hostname, user=junos_username, passwd=junos_password, mode='telnet', port='23') as dev: print (dev.facts) except Exception as err: print (err) sys.exit(1)
In some cases, when you connect to a console server that emits a banner message, you might be required to press Enter after the message to reach the login prompt. If a Junos PyEZ application opens a Telnet session with a console server that requires the user to press Enter after a banner message, the application might fail to receive the login prompt, which can cause the connection to hang.
Starting in Junos PyEZ Release 2.1.0, a Junos PyEZ application
can include the console_has_banner=True
argument in the Device
argument list
to telnet to a console server that emits a banner message.
dev = Device(host=hostname, user=username, passwd=password, mode='telnet', console_has_banner=True)
When you include the console_has_banner=True
argument and the application does not receive a login prompt upon
initial connection, the application waits for 5 seconds and then emits
a newline (\n
) character so that the console
server issues the login prompt. If you omit the argument and the connection
hangs, the application instead emits the <close-session/>
RPC to terminate the connection.
Connect to a Device Using a Serial Console Connection
The Junos PyEZ Device
class enables
you to connect to a device running Junos OS using a serial console
connection, which is useful when you must initially configure a new
or zeroized device that is not yet configured for remote access. To
use this connection method, you must be physically connected to the
device through the CONSOLE port. For detailed
instructions about connecting to the CONSOLE port
on your device, see the hardware documentation for your specific device.
Junos PyEZ supports using context managers for serial console connections. We recommend that you use a context manager for console connections, because the context manager automatically handles opening and closing the connection. Failure to close the connection can lead to unpredictable results.
To use Junos PyEZ to connect to a device running Junos OS through
a serial console connection, you must include mode='serial'
in the Device
argument list, and optionally
include the port
parameter to specify a
port. When you specify mode='serial'
but
omit the port
parameter, the value for port
defaults to /dev/ttyUSB0
.
To connect to a device running Junos OS using a serial console connection and also load and commit a configuration on the device in a Junos PyEZ application using Python 3:
The sample program in its entirety is presented here:
import sys from getpass import getpass from jnpr.junos import Device from jnpr.junos.utils.config import Config junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS password: ") try: with Device(mode='serial', port='port', user=junos_username, passwd=junos_password) as dev: print (dev.facts) cu = Config(dev) cu.lock() cu.load(path='/tmp/config_mx.conf') cu.commit() cu.unlock() except Exception as err: print (err) sys.exit(1)