Example: Specify the Session Protocol for a Connection within Scripts
This example demonstrates how to specify the session protocol when establishing a a connection with a remote device within a Junos automation script. 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
Device running Junos OS or device running Junos OS Evolved.
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 Junos devices or with the NETCONF server on devices
that enable the NETCONF service over SSH. The example script creates a connection and
establishes a NETCONF session with a remote device running Junos OS. If the script
successfully establishes the connection and NETCONF session, the script then performs
several operations on the remote device. The script retrieves and prints the session
protocol and the capabilities of the NETCONF server. The script also updates the remote
device's configuration to add the ftp statement at the [edit system
services] hierarchy level.
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 CLI when a
user requests context-sensitive help.
The variable netconf is a node-set that specifies the session protocol and the
connection parameters for the remote device. The <method> element is
set to “netconf” to establish a NETCONF session with the remote device. 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 script successfully establishes the NETCONF session, the script executes several 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 script stores the results for each RPC separately and
parses them 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 rpc-edit-config variable references the <edit-config>
element, which is a NETCONF operation to modify a configuration. The
<config> element includes the modified portion of the configuration
that is merged with the candidate configuration on the device. If the operation encounters
errors, 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> "admin";
}
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>admin</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
filestatement at the[edit system scripts op]hierarchy level and netconf-session.xsl or netconf-session.slax as appropriate.[edit system scripts op] admin@local-host# set file netconf-session.(slax | xsl)
Commit the configuration.
[edit] admin@local-host# commit and-quit
Execute the op script on the local device by issuing the
op netconf-sessionoperational mode command and include any necessary arguments.In this example, the user, admin, is connecting to the remote device, router1. The remote device has dual Routing Engines, so the
commitoperation returns a warning that thecommit synchronizecommand should be used to commit the new candidate configuration to both routing engines.admin@local-host> op netconf-session remote-host router1 admin@router1'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.
Verify 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. The output within the
<op-script-results> element is relevant to the script
execution.
admin@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 by including the | display
xml option when you execute an op script.
admin@local-host> op netconf-session remote-host router1 | 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
successful.
Verify 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. If the script is successful, the configuration includes the
ftp statement.
admin@router1> show configuration system services
ftp;
netconf {
ssh;
}On the remote device, execute the show system commit operational mode command to
view the commit log. In this example, the log confirms that user admin committed the
candidate configuration in a NETCONF session at the given date and time.
admin@router1> show system commit 0 2025-07-11 12:04:01 PDT by admin via netconf 1 2025-07-08 15:16:33 PDT by root via cli
Troubleshooting
- Troubleshoot Connection Errors
- Troubleshoot Configuration Lock Errors
- Troubleshoot Configuration Syntax Errors
Troubleshoot 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 "router1" 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 hostname 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.
You are trying to establish a NETCONF session, but the remote device does not have NETCONF over SSH enabled, 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 hostname of the remote device when executing the script.
For NETCONF sessions, ensure that you enable NETCONF over SSH on the remote device. The example program does not specify a specific port number for the NETCONF session. As a result, the script establishes the NETCONF session on the default NETCONF port, 830. To verify whether NETCONF over SSH is enabled on the default port for a device running Junos OS, issue the following operational mode command on the remote device:
admin@router1> show configuration system services
netconf {
ssh;
}If the netconf configuration hierarchy is absent on the remote device, enable
NETCONF over SSH on the default port:
[edit] admin@router1# set system services netconf ssh admin@router1# 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 establishes
NETCONF sessions on port 12345:
admin@router1> show configuration system services
netconf {
ssh {
port 12345;
}
}To create a NETCONF session on the alternate port, include the port number in the XML node-set.
var $netconf := {
<method> "netconf";
<username> "admin";
<port> "12345";
}
var $connection = jcs:open($remote-host, $netconf);
...
Troubleshoot Configuration Lock Errors
Problem
The script generates one of the following error messages:
configuration database locked by: root terminal p0 (pid 24113) on since 2025-07-11 11:48:06 PDT, idle 00:07:59
Users currently editing the configuration:
root terminal p1 (pid 24279) on since 2025-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.
Troubleshoot Configuration Syntax Errors
Problem
The script generates the following error message:
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.