Example: Specify the Session Protocol for a Connection within Scripts
The following example demonstrates how to specify the session protocol within a Junos automation script when creating a connection with a remote device. Specifically, the example op script establishes a NETCONF session with a remote device running Junos OS, retrieves and prints the NETCONF server capabilities, and then updates and commits the configuration on that device.
Requirements
Routing, switching, or security device running Junos OS Release 11.4 or later.
Client application can log in to the device where the NETCONF server resides.
NETCONF service over SSH is enabled on the device where the NETCONF server resides.
Overview and Script
The jcs:open()
extension function
includes the option to create a session either with the Junos XML
protocol server on devices running Junos OS or with the NETCONF server
on devices where NETCONF service over SSH is enabled. In the following
example, the script creates a connection and establishes a NETCONF
session with a remote device running Junos OS. If the connection and
session are successfully established, the script updates the configuration
on the remote device to add the ftp
statement to the [edit system services]
hierarchy level. The script also retrieves
and prints the session protocol and the capabilities of the NETCONF
server.
The script takes one argument, remote-host
, which is the IP address or hostname of the remote device. The arguments
variable is declared at the global level
of the script so that the argument name and description are visible
in the command-line interface (CLI) when a user requires context-sensitive help.
The variable netconf
is a node-set
that specifies the session protocol and the connection parameters
for the remote device. The value of the <method>
element is set to “netconf” to establish a session with
the NETCONF server over an SSHv2 connection. The <username>
element specifies the username for the connection. If you do not
specify a username and it is required for the connection, the script
uses the local name of the user executing the script. In this example,
the passphrase and port are not specified. If a passphrase is required
for authentication, the remote device should prompt for one during
script execution. The script establishes the session using the default
NETCONF port 830.
If the connection and establishment of the NETCONF session are
successful, the script executes remote procedure calls (RPCs). The
RPCs contain the tag elements <lock>
, <edit-config>
, <commit>
, and <unlock>
, which are NETCONF operations
to lock, edit, commit, and unlock the candidate configuration. The script stores the RPC for each
task in a separate variable. The results for each RPC are also stored
separately and parsed for errors. The script only executes each subsequent
step if the previous step is successful. For example, if the script
cannot lock the configuration, it does not execute the RPCs to edit,
commit, or unlock the configuration.
The variable rpc-edit-config
contains
the tag element <edit-config>
, which
is a NETCONF operation to modify a configuration. The child element, <config>
, includes the modified portion of the configuration
that is merged with the candidate configuration on the device. If
errors are encountered, the script calls the copy-of
statement to copy the result tree fragment variable to the results
tree so that the error message prints to the CLI during script execution.
SLAX Syntax
version 1.0; ns junos = "http://xml.juniper.net/junos/*/junos"; ns xnm = "http://xml.juniper.net/xnm/1.1/xnm"; ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0"; ns ext = "http://xmlsoft.org/XSLT/namespace"; var $arguments = { <argument> { <name> "remote-host"; <description> "device hostname or IP address to which to connect"; } } param $remote-host; match / { <op-script-results> { var $netconf := { <method> "netconf"; <username> "bsmith"; } var $rpc-lock-config = { <lock> { <target> { <candidate>; } } } var $rpc-unlock-config = { <unlock> { <target> { <candidate>; } } } var $rpc-commit = { <commit>; } var $rpc-edit-config = { <edit-config> { <target> { <candidate>; } <default-operation> "merge"; <config> { <configuration> { <system> { <services> { <ftp>; } } } } } } if ($remote-host = '') { <xnm:error> { <message> "missing mandatory argument 'remote-host'"; } } else { var $connection = jcs:open($remote-host, $netconf); if ($connection) { /* request protocol and capabilities */ var $protocol = jcs:get-protocol($connection); var $capabilities = jcs:get-hello($connection); <output> "\nSession protocol: " _ $protocol _ "\n"; copy-of $capabilities; /* execute rpcs to lock, edit, commit, and unlock config */ var $lock-reply = jcs:execute($connection, $rpc-lock-config); if ($lock-reply/..//rpc-error) { copy-of $lock-reply; } else { var $edit-config-reply = jcs:execute($connection, $rpc-edit-config); if ($edit-config-reply/..//rpc-error) { <output>"Configuration error: "_ $edit-config-reply/..//error-message/. _ "\nConfiguration not committed.\n" ; copy-of $edit-config-reply; } else { var $commit-reply = jcs:execute($connection, $rpc-commit); if ($commit-reply/..//rpc-error) { <output>"Commit error or warning: " _ $commit-reply/..//error-message/.; copy-of $commit-reply; } } var $unlock-reply = jcs:execute($connection, $rpc-unlock-config); } expr jcs:close($connection); } else { <output>"\nNo connection - exiting script"; } } } }
XSLT Syntax
<?xml version="1.0" standalone="yes"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:junos="http://xml.juniper.net/junos/*/junos" xmlns:xnm="http://xml.juniper.net/xnm/1.1/xnm" xmlns:jcs="http://xml.juniper.net/junos/commit-scripts/1.0" xmlns:ext="http://xmlsoft.org/XSLT/namespace" version="1.0"> <xsl:variable name="arguments"> <argument> <name>remote-host</name> <description>device hostname or IP address to which to connect</description> </argument> </xsl:variable> <xsl:param name="remote-host"/> <xsl:template match="/"> <op-script-results> <xsl:variable name="netconf-temp-1"> <method>netconf</method> <username>bsmith</username> </xsl:variable> <xsl:variable xmlns:ext="http://xmlsoft.org/XSLT/namespace" name="netconf" select="ext:node-set($netconf-temp-1)"/> <xsl:variable name="rpc-lock-config"> <lock> <target> <candidate/> </target> </lock> </xsl:variable> <xsl:variable name="rpc-unlock-config"> <unlock> <target> <candidate/> </target> </unlock> </xsl:variable> <xsl:variable name="rpc-commit"> <commit/> </xsl:variable> <xsl:variable name="rpc-edit-config"> <edit-config> <target> <candidate/> </target> <default-operation>merge</default-operation> <config> <configuration> <system> <services> <ftp/> </services> </system> </configuration> </config> </edit-config> </xsl:variable> <xsl:choose> <xsl:when test="$remote-host = ''"> <xnm:error> <message>missing mandatory argument 'remote-host'</message> </xnm:error> </xsl:when> <xsl:otherwise> <xsl:variable name="connection" select="jcs:open($remote-host, $netconf)"/> <xsl:choose> <xsl:when test="$connection"> <!-- request protocol and capabilities --> <xsl:variable name="protocol" select="jcs:get-protocol($connection)"/> <xsl:variable name="capabilities" select="jcs:get-hello($connection)"/> <output> <xsl:value-of select="concat(' Session protocol: ', $protocol, ' ')"/> </output> <xsl:copy-of select="$capabilities"/> <!-- execute rpcs --> <xsl:variable name="lock-reply" select="jcs:execute($connection, $rpc-lock-config)"/> <xsl:choose> <xsl:when test="$lock-reply/..//rpc-error"> <xsl:copy-of select="$lock-reply"/> </xsl:when> <xsl:otherwise> <xsl:variable name="edit-config-reply" select="jcs:execute($connection, $rpc-edit-config)"/> <xsl:choose> <xsl:when test="$edit-config-reply/..//rpc-error"> <output> <xsl:value-of select="concat('Configuration error: ', $edit-config-reply/..//error-message/., ' Configuration not committed. ')"/> </output> <xsl:copy-of select="$edit-config-reply"/> </xsl:when> <xsl:otherwise> <xsl:variable name="commit-reply" select="jcs:execute($connection, $rpc-commit)"/> <xsl:if test="$commit-reply/..//rpc-error"> <output> <xsl:value-of select="concat('Commit error or warning: ', $commit-reply/..//error-message/.)"/> </output> <xsl:copy-of select="$commit-reply"/> </xsl:if> </xsl:otherwise> </xsl:choose> <xsl:variable name="unlock-reply" select="jcs:execute($connection, $rpc-unlock-config)"/> </xsl:otherwise> </xsl:choose> <xsl:value-of select="jcs:close($connection)"/> </xsl:when> <xsl:otherwise> <output>No connection - exiting script</output> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </op-script-results> </xsl:template> </xsl:stylesheet>
Configuration
Procedure
Step-by-Step Procedure
To download, enable, and test the script:
Copy the XSLT or SLAX script into a text file, name the file netconf-session.xsl or netconf-session.slax as appropriate, and copy it to the /var/db/scripts/op/ directory on the device.
In configuration mode, include the
file
statement at the[edit system scripts op]
hierarchy level and netconf-session.xsl or netconf-session.slax as appropriate.[edit system scripts op] bsmith@local-host# set file netconf-session.(slax | xsl)
Issue the
commit and-quit
command.[edit] bsmith@local-host# commit and-quit
Execute the op script on the local device by issuing the
op netconf-session
operational mode command and include any necessary arguments.In this example, the user, bsmith, is connecting to the remote device, fivestar. The remote device has dual routing engines, so the
commit
operation returns a warning that thecommit synchronize
command should be used to commit the new candidate configuration to both routing engines.bsmith@local-host> op netconf-session remote-host fivestar bsmith@fivestar's password: Session protocol: netconf Commit error or warning: graceful-switchover is enabled, commit synchronize should be used
Verification
Confirm that the device is working properly.
Verifying Op Script Execution
Purpose
Verify that the script behaves as expected.
Action
Review the script output in the CLI and in the op script
log file. Take particular note of any errors that occurred during
execution. The default op script log file is /var/log/op-script.log. If the log file is significantly lengthy, limit the display by
appending the | last number-of-lines
option to the show log
command and specify the number
of lines to print to the CLI. The output within the <op-script-results>
element is relevant to the script execution.
bsmith@local-host> show log op-script.log | last 100 ...output omitted for brevity... <op-script-results xmlns:junos="http://xml.juniper.net/junos/*/junos" xmlns:xnm="http://xml.juniper.net/xnm/1.1/xnm" xmlns:jcs="http://xml.juniper.net/junos/commit-scripts/1.0" xmlns:ext="http://xmlsoft.org/XSLT/namespace"> <output> Session protocol: netconf </output> <hello> <capabilities> <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1.0 </capability> <capability>urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0 </capability> <capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability> <capability> urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file </capability> <capability>http://xml.juniper.net/netconf/junos/1.0</capability> <capability>http://xml.juniper.net/dmi/system/1.0</capability> </capabilities> <session-id>29087</session-id> </hello> <output>Commit error or warning: graceful-switchover is enabled, commit synchronize should be used </output> <rpc-error> <error-severity>warning</error-severity> <error-message> graceful-switchover is enabled, commit synchronize should be used </error-message> </rpc-error> <ok/> </op-script-results>
You can also obtain more descriptive script output on
a device running Junos OS by including the | display xml
option when you execute an op script.
bsmith@local-host> op netconf-session remote-host fivestar | display xml <rpc-reply xmlns:junos="http://xml.juniper.net/junos/11.4D0/junos"> <output> Session protocol: netconf </output> <hello> <capabilities> <capability> urn:ietf:params:xml:ns:netconf:base:1.0 </capability> <capability> urn:ietf:params:xml:ns:netconf:capability:candidate:1.0 </capability> <capability> urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0 </capability> <capability> urn:ietf:params:xml:ns:netconf:capability:validate:1.0 </capability> <capability> urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file </capability> <capability> http://xml.juniper.net/netconf/junos/1.0 </capability> <capability> http://xml.juniper.net/dmi/system/1.0 </capability> </capabilities> <session-id> 29087 </session-id> </hello> <output> Commit error or warning: graceful-switchover is enabled, commit synchronize should be used </output> <rpc-error> <error-severity> warning </error-severity> <error-message> graceful-switchover is enabled, commit synchronize should be used </error-message> </rpc-error> <ok/> </op-script-results> <cli> <banner></banner> </cli> </rpc-reply>
Meaning
This example creates a NETCONF session on a remote
device running Junos OS. The capabilities of the NETCONF server include
both standard NETCONF operations and Juniper Networks proprietary
extensions, which are defined in http://xml.juniper.net/netconf/junos/1.0
and http://xml.juniper.net/dmi/system/1.0
. The RPC results for the commit
operation include
one warning, but the commit operation is still successful.
Verifying the Configuration Changes
Purpose
Verify that the commit was successful by viewing the configuration change and the commit log on the remote device.
Action
On the remote device, execute the show configuration
system services
operational mode command to view the [edit
system services]
hierarchy level of the configuration. If the
script is successful, the configuration includes the ftp
statement.
bsmith@fivestar> show configuration system services ftp; netconf { ssh; }
Additionally, you can review the commit log. On the
remote device, execute the show system commit
operational
mode command to view the commit log. In this example, the log confirms
that bsmith committed the candidate configuration in a NETCONF session
at the given date and time.
bsmith@fivestar> show system commit 0 2011-07-11 12:04:01 PDT by bsmith via netconf 1 2011-07-08 15:16:33 PDT by root via cli
Troubleshooting
- Troubleshooting Connection Errors
- Troubleshooting Configuration Lock Errors
- Troubleshooting Configuration Syntax Errors
Troubleshooting Connection Errors
Problem
The script generates the following error message:
hello packet:1:(0) Document is empty hello packet:1:(0) Start tag expected, '<' not found error: netconf: could not read hello error: did not receive hello packet from server error: Error in creating the session with "fivestar" server No connection - exiting script
Potential causes for the connection error include:
The device or interface to which you are connecting is down or unavailable.
The script argument for the IP address or DNS name of the remote device is incorrect.
The connection timeout value was exceeded before establishing the connection.
The user authentication for the remote device is not valid or is entered incorrectly.
You are trying to establish a NETCONF session, and NETCONF over SSH is not enabled on the device where the NETCONF server resides, or it is enabled on a different port.
Solution
Ensure that the remote device is up and running and that the user has access to the device. Also verify that you supplied the correct argument for the IP address or DNS name of the remote device when executing the script.
For NETCONF sessions, ensure that you have enabled NETCONF over SSH on the device where the NETCONF server resides. Since the example program does not specify a specific port number for the NETCONF session, the session is established on the default NETCONF-over-SSH port, 830. To verify whether NETCONF over SSH is enabled on the default port for a device running Junos OS, enter the following operational mode command on the remote device:
bsmith@fivestar> show configuration system services netconf { ssh; }
If the netconf
configuration hierarchy is absent
on the remote device, issue the following statements in configuration
mode to enable NETCONF over SSH on the default port:
[edit] bsmith@fivestar# set system services netconf ssh bsmith@fivestar# commit
If the netconf
configuration hierarchy specifies
a port other than the default port, include the port number in the
XML node-set that you pass to the jcs:open()
function. For example, the following device is configured for NETCONF
over SSH on port 12345:
bsmith@fivestar> show configuration system services netconf { ssh { port 12345; } }
To create a NETCONF session on the alternate port, include the new port number in the XML node-set.
var $netconf := { <method> "netconf"; <username> "bsmith"; <port> "12345"; } var $connection = jcs:open($remote-host, $netconf); ...
Troubleshooting Configuration Lock Errors
Problem
The script generates one of the following error messages:
configuration database locked by: root terminal p0 (pid 24113) on since 2011-07-11 11:48:06 PDT, idle 00:07:59
Users currently editing the configuration: root terminal p1 (pid 24279) on since 2011-07-11 12:28:30 PDT {master}[edit]
configuration database modified
Solution
Another user currently has a lock on the candidate configuration or has modified the candidate configuration but has not yet committed the configuration. Wait until the lock is released, and then execute the program.
Troubleshooting Configuration Syntax Errors
Problem
The following error message prints to the CLI:
Configuration error: syntax error Configuration not committed.
Examine the result tree for additional information. In this case, the result tree shows the following error message:
<rpc-error> <error-severity> error </error-severity> <error-info> <bad-element> ftp2 </bad-element> </error-info> <error-message> syntax error </error-message> </rpc-error>
Solution
The <bad-element>
tag
element indicates that the configuration statement is not valid. Correct
the configuration hierarchy and run the script. In this example error,
the user entered the tag <ftp2>
instead
of <ftp>
. Since that is not an acceptable
element in the configuration, the NETCONF server returns an error.