7 RESTCONF
This section describes how to use RESTCONF with the Clixon controller.
Please also consult the RESTCONF section in the Clixon user manual.
Clixon provides two separate compile-time setups for RESTCONF:
FCGI / FastCGI: This solution uses a web reverse proxy such as NGINX. The reverse proxy configures all HTTP configuration.
Native: which combines a HTTP and Restconf server including openssl and nghttp2.
7.1 Fcgi setup
If you use native mode, this section can be skipped.
7.1.1 NGINX
Install NGINX. Edit the location as for example as the following minimal config:
location / {
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
include fastcgi_params;
}
On many NGINX installations this can be made in /etc/nginx/sites-available/default.
Restart NGINX:
sudo systemctl restart nginx.service
7.1.2 Configure
You need to configure clixon for FCGI:
./configure --with-restconf=fcgi
NGINX typically creates a www-data user. The following must be done prior to running:
Create a directory for example at
/www-datawith the following permissions:drwxr-xr-x 2 www-data www-data 4096 apr 1 20:14 www-data
Add the
www-datauser to theclicongroup
Ensure your controller.xml configuration file has the following entries:
<CLICON_FEATURE>clixon-restconf:allow-auth-none</CLICON_FEATURE>
<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>
<CLICON_RESTCONF_DIR>/usr/local/lib/controller/restconf</CLICON_RESTCONF_DIR>
7.1.3 Example config
Next step is to setup RESTCONF in the datastore. FCGI configuration may look as follows:
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>none</auth-type>
<fcgi-socket>/www-data/fastcgi_restconf.sock</fcgi-socket>
<pretty>false</pretty>
<debug>0</debug>
<log-destination>syslog</log-destination>
</restconf>
Auth is set as none. If you want to use basic auth, you need to add
support for authentication using the ca_auth plugin callback.
You should modify the configuration above to suit you needs, thereafter install it in the Clixon datastore using one of the methods described in the next section.
7.1.4 Fcgi install
You install the RESTCONF configuration by adding it to the datastore in one of the following methods.
7.1.5 Install using CLI
Enter the CLI and edit the RESTCONF configuration and commit it:
# clixon_cli
cli> configure
cli# set restconf enable true
cli# set restconf auth-type none
cli# set restconf fcgi-socket /www-data/fastcgi_restconf.sock
cli# commit local
cli#
The commit command should (re)start the RESTCONF daemon with the new configuration. To verify that the RESTCONF is running, see Section Verify the configuration.
7.1.6 Install in datastore
If you use a startup-db or running-db you can directly edit the datastore by adding the restconf config and restart the clixon_backend.
Add the restconf config to the datastore, such as /usr/local/var/controller/startup.d/0.xml as follows:
<config>
...
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>none</auth-type>
<fcgi-socket>/www-data/fastcgi_restconf.sock</fcgi-socket>
</restconf>
</config>
Then restart clixon_backend, typically using systemd:
sudo systemctl restart clixon-controller.service
7.1.7 Install using NETCONF
Send a NETCONF edit-config message to modify the restconf configuration, and then commit it:
<?xml version="1.0" encoding="UTF-8"?>
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
</capabilities>
</hello>]]>]]>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="42">
<target>
<candidate/>
</target>
<config>
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
...
</restconf>
</config>
</rpc>]]>]]>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="42">
<commit/>
</rpc>]]>]]>
The RESTCONF daemon should be restarted automatically with the new configuration.
7.1.8 Verify the configuration
Verify that the daemon is running using the CLI:
cli> processes restconf status
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<active xmlns="http://clicon.org/lib">true</active>
<status xmlns="http://clicon.org/lib">running</status> <---
</rpc-reply>
You can also verify it via RESTCONF (fields are simplified):
POST /restconf/operations/clixon-lib:process-control HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-lib:input": {
"name":"restconf",
"operation":"status"
}
}
A reply with a successful start is:
HTTP/1.1 200
{
"clixon-lib:output": {
"active": true,
"description": "Clixon RESTCONF process",
"status": "running"
}
}
7.2 Native setup
Native mode is more complex to setup and provides many different configurations for RESTCONF. The controller supports the following:
Native TLS and http in the RESTCONF daemon. No reverse proxy is needed.
HTTP/1.1 and HTTP/2
Basic and TLS/SSL client cert authentication
Datastore configuration, not in configuration file
7.2.1 Configuration
You need to configure clixon for native:
./configure --with-restconf=native
7.2.2 Example config
A typical RESTCONF native configuration may look as follows:
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>client-certificate</auth-type>
<server-cert-path>/etc/pki/tls/certs/clixon-server-crt.pem</server-cert-path>
<server-key-path>/etc/pki/tls/private/clixon-server-key.pem</server-key-path>
<server-ca-cert-path>/etc/pki/tls/CA/clixon-ca-crt.pem</server-ca-cert-path>
<socket>
<namespace>default</namespace>
<address>192.168.32.1</address>
<port>443</port>
<ssl>true</ssl>
</socket>
</restconf>
In the config where a TLS on port 443 on 192.168.32.1 is configured using client-certs placed in the etc/pki/tls directory.
Alternatively, you may use basic auth, but then you need to add
support for authentication using the ca_auth plugin callback.
For testing purposes, none can be used as auth-type.
7.3 Setup
You setup the connection to one or several devices by editing the device connection data
For setup a device with IP address 172.17.0.3 and user admin via SSH:
POST /restconf/data/clixon-controller:devices HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:device": {
"name":"test",
"enabled":"true",
"conn-type":"NETCONF_SSH",
"user":"admin",
"addr":"172.17.0.3"
}
}
You can also configure device-groups and device-profiles as described in the CLI tutotial, for example.
7.4 Transactions
Many of the controller’s RPCs return a transaction-id that indicates that the result of the RPC is not immediately available. Instead, it indicates that a new transaction has been created.
Note
RPCs returning a transaction-id are asynchronous
Transactions can be monitored in one of the following ways:
Register and wait for a notification, as described in Section notifications.
Sleep/Poll and read the status of the resulting action, such as the connection status, see Section verify connection.
Sleep/Poll and read the status of the transaction using GET.
To get the status of transaction “6” using GET send the following request:
POST /restconf/data/clixon-controller:transactions/transaction=6 HTTP/1.1
Accept: application/yang-data+json
A typical reply:
HTTP/1.1 200
{
"clixon-controller:transaction": [
{
"tid": "6",
"result": "SUCCESS", <---
...
}
]
}
Controller RPCs that create transactions are:
config-pullcontroller-commitconnection-changedevice-template-apply(of type RPC)
Transactions are described in more detail in the Transaction section.
7.5 Connect
If you have setup the configuration for your devices and installed the
SSH keys, you can start connecting to them. For this, you need to invoke
the connection-change RPC which starts a device connect transaction.
Note
You need to install SSH keys before connection establishment
The connection-change RPC takes a device or device-group as input and an operation. Example:
POST /restconf/operations/clixon-controller:connection-change HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"device":"*",
"operation":"OPEN"
}
}
With the following reply containing a transaction-id:
HTTP/1.1 200
{
"clixon-controller:output":{
"tid":"4"
}
}
7.5.1 Verify connection
One way to verify a connection (apart from monitoring the transaction itself) is to wait and check the status of the connection using GET, as follows:
GET /restconf/data/clixon-controller:devices/device=openconfig1/conn-state HTTP/1.1
Accept: application/yang-data+json
HTTP/1.1 200
{
"clixon-controller:conn-state":"OPEN"
}
7.5.2 Select devices
You can select devices in the connect RPCs as follows:
All devices:
device: *Individual device:
device: openconfig1Device pattern:
device: openconfig*Device-groups:
device-group: mygroupDevice-group pattern:
device-group: my*
7.5.3 Connect operations
The operation in the initial example is OPEN. The operations are:
Establish connections to a set of devices:
OPENClose connections:
CLOSEClose and the re-open connections:
RECONNECT
Example, reconnect to all devices in device-groups starting with “my*”:
POST /restconf/operations/clixon-controller:connection-change HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"device-group": "my*",
"operation": "RECONNECT"
}
}
7.6 Accessing device config
When devices are open, you can get, put and push device configuration.
7.6.1 GET device config
You can GET configuration from a single device as follows:
GET /restconf/data/clixon-controller:devices/device=openconfig1/config HTTP/1.1
Accept: application/yang-data+json
HTTP/1.1 200
{
"clixon-controller:config": {
"openconfig-interfaces:interfaces": {
"interface": [
{
"name": "x",
...
You can also get more specific config:
GET /restconf/data/clixon-controller:devices/device=openconfig1/\
config//openconfig-interfaces:interfaces/interface=x/config/type HTTP/1.1
Accept: application/yang-data+json
HTTP/1.1 200
{
"openconfig-interfaces:type": "iana-if-type:ethernetCsmacd"
}
7.6.2 PUT device config
To edit device configuration, use PUT, POST or PATCH and then push the changes to devices.
With RESTCONF, modifications are written to the running datastore in the controller (local commit). Thereafter, the changes are pushed to the devices using the controller-commit RPC.
For example, change the description of an interface using PUT:
PUT /restconf/data/clixon-controller:devices/device=openconfig1/config/\
openconfig-interfaces:interfaces/interface=x/config HTTP/1.1
Content-Type: application/yang-data+json
{
"openconfig-interfaces:config": {
"name": "x",
"type": "iana-if-type:ethernetCsmacd",
"description": "My description"
}
}
HTTP/1.1 204
7.6.3 PUSH device config
Thereafter, push the changes to a device using the controller-commit RPC:
POST /restconf/operations/clixon-controller:controller-commit HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"device": "openconfig1",
"push": "COMMIT",
}
}
This may generate a reply as follows:
HTTP/1.1 200
{
"clixon-controller:output":{
"tid":"3"
}
}
Again, this starts an asynchronous transaction which can be monitored with methods described in Section transactions.
7.6.4 PULL device config
To synchronize, that is to pull the device config to the controller, use config-pull:
POST /restconf/operations/clixon-controller:config-pull HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"device": "openconfig1",
}
}
7.7 Notifications
The controller uses notifications to get asynchronous notifications and event streams.
Note
Notifications are not fully functional in FCGI mode
For example, connection establishment as described in Section connect and commit described in Section push device config create transactions. If you want to wait for such a transaction to complete, you can register for that event stream as follows:
GET /streams/controller-transaction HTTP/1.1
Accept: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
The data notification is an “SSE” / long poll event, which means that the call blocks and waits for notifications to be received:
HTTP/2 201
content-type: text/event-stream
data: <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
<eventTime>2025-03-06T15:30:16.710209Z</eventTime>
<controller-transaction xmlns="http://clicon.org/controller">
<tid>4</tid>
<username>clicon</username>
<result>SUCCESS</result>
</controller-transaction>
</notification>
This means that a programmer needs to create a separate session apart from the original RPC: One which waits for a notification, and one which creates the transaction using an operation.
7.8 Services
You may wish to read the the service tutotial before reading this section.
You can initate a service typically implemented in Python(PyAPI) by editing a service configuration and then applying the service using the controller-commit RPC.
With CLI or NETCONF it is possible to edit a service in the candidate datastore and then only trigger the services that have changed. This is not possible in RESTCONF, since it does not use the candidate datastore. Instead you need to explicitly set which service has changed (or all)
7.8.1 Edit a service config
First, edit a service. You can skip this part of you just want to trigger a service unconditionally.
In the following example, edit the bar instance of the testA service in module myyang (ie instance testA[a_name='bar'].
POST /restconf/restconf/data/clixon-controller:services HTTP/1.1
Content-Type: application/yang-data+json
{
"myyang:testA": [
{
"a_name": "bar",
"params": [
"AA"
]
}
]
}
This changes the service config in the running datastore of the controller. But it does not trigger a service.
7.8.2 Getting service diff
To get the configuration that are going to be implemented on the devices, you need to send two RPCs
to the controller. The first one is a controller-commit and the second one is a datastore-diff
The operation is:
POST /restconf/operations/clixon-controller:controller-commit HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"push": "NONE",
"actions": "FORCE",
"source": "ds:candidate"
"service-instance":"testA[a_name='bar']"
}
}
and then the diff can be seen by running:
POST /restconf/operations/clixon-controller:datastore-diff HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"device": "*",
"config-type1": "RUNNING",
"config-type2": "ACTIONS"
}
}
This should be done before the service code is triggered.
7.8.3 Trigger service code
To trigger a service, you need to send a controller-commit RPC to
the controller. You can do this either after editing a service, or
unconditionally, such as in a periodic process.
In the following example, you trigger the service as follows:
It applies for all devices:
device:*.You push and commit the service result to the devices:
push:COMMIT. You could also justVALIDATEthe service in the devicesThe service is unconditionally run:
actions:FORCE. This is the only option for RESTCONF.The datastore to work with is
source:candidate. This is also necessary for RESTCONF.Trigger the service for a specific instance:
service-instance:testA[a_name='bar']. You may also skip this field to trigger all services.
The corresponding operation is:
POST /restconf/operations/clixon-controller:controller-commit HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"push": "COMMIT",
"actions": "FORCE",
"source": "ds:candidate"
"service-instance":"testA[a_name='bar']"
}
}
Where a transaction id is returned:
HTTP/1.1 200
{
"clixon-controller:output":{
"tid":23
}
}
7.8.4 Delete service
To remove a service using RESTCONF you have to do it in two steps.
First, similar to in Section Trigger service code but instead of sending actions:FORCE, you send actions:DELETE to remove device configuration created by the service.
Then remove the service definition in a second step.
The operation to remove the device configuration created by a service:
POST /restconf/operations/clixon-controller:controller-commit HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"push": "COMMIT",
"actions": "DELETE",
"source": "ds:candidate"
"service-instance":"testA[a_name='bar']"
}
}
And then remove the service definition itself:
DELETE /restconf/data/myyang:testA=a_name='bar' HTTP/1.1
7.9 Device RPCs
You can send an RPC to devices via the controller using the device-rpc RPC, and get the result with device-rpc-result.
7.9.1 Send RPC
Example of sending the RPC using JSON:
POST /restconf/operations/clixon-controller:device-rpc HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"device": "openconfig*",
"config": {
"clixon-lib:stats": {
"modules": "true"
}
}
}
}
Where a transaction id is returned:
HTTP/1.1 200
{
"clixon-controller:output":{
"tid":"5"
}
}
7.9.2 Check transaction state
A transaction has been created and the client needs to wait for results via a notification (see Section notifications) or poll for completion of the transaction:
GET /restconf/data/clixon-controller:transactions/transaction=5 HTTP/1.1
Accept: application/yang-data+json
The reply could be:
HTTP/1.1 200
{
"clixon-controller:transaction": [
{
"tid": "6",
"username": "clicon",
"result": "SUCCESS",
...
7.9.3 Read result
If the transaction has completed successfuly, you can read the results via the rpc-device-result RPC:
POST /restconf/operations/clixon-controller:device-rpc-result HTTP/1.1
Content-Type: application/yang-data+json
Accept: application/yang-data+json
{
"clixon-controller:input": {
"tid":"11",
}
}
Example reply:
HTTP/1.1 200
{
"clixon-controller:output": {
"tid": "11",
"devices": {
"devdata": [
{
"name": "openconfig1",
"data": {
"global": {
"xmlnr": "1570",
"yangnr": "166357"
...
Note the devdata field which returns the reply from the RPC. That is, the reply for the stats RPC to openconfig1 is:
"data": {
"global": {
"xmlnr": "1570",
"yangnr": "166357"
The devdata field may contain replies from multiple devices.
7.9.4 Send using XML
Instead of using JSON in the rpc-template body, you can also use XML:
POST /restconf/operations/clixon-controller:device-rpc HTTP/1.1
Content-Type: application/yang-data+xml
<input xmlns="http://clicon.org/controller">
<device>openconfig*</device>
<config>
<ping xmlns="http://clicon.org/lib"/>
</config>
</input>
7.10 Get device state
You can get state data from device by using a device RPC as a workaround for not supplying it with a top-level GET.
7.10.1 Device state using XML
Example, get the ssh state of all openconfig devices:
POST /restconf/operations/clixon-controller:device-rpc HTTP/1.1
Content-Type: application/yang-data+xml
<input xmlns="urn:example:clixon-controller">
<device>openconfig*</device>
<config>
<get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<filter type="xpath" select="/oc-sys:system/oc-sys:ssh-server"
xmlns:oc-sys="http://openconfig.net/yang/system" />
</get>
</config>
</input>
HTTP/1.1 200
{
"clixon-controller:output":{
"tid":"6"
}
}
where the filter statement selects the system/ssh-server state.
Polling for successful result:
GET /restconf/data/clixon-controller:transactions/transaction=6 HTTP/1.1
Accept: application/yang-data+json
A reply could be:
HTTP/2 200
content-type: application/yang-data+json
{
"clixon-controller:transaction": [
{
"tid": "8",
"username": "anonymous",
"result": "SUCCESS",
...
Get the result:
POST /restconf/operations/clixon-controller:device-rpc-result HTTP/1.1
Content-Type: application/yang-data+json
Accept: application/yang-data+json
{
"clixon-controller:input": {
"tid":"8",
}
}
The state result reply:
HTTP/1.1 200
{
"clixon-controller:output": {
"tid": "8",
"devices": {
"devdata": [
{
"name": "openconfig1",
"data": {
"data": {
"system": {
"ssh-server": {
"state": {
"enable": "true",
"protocol-version": "V2"
}
}
}
}
}
},
...
where the result of the first matchong device (openconfig1) is shown.
7.10.2 Device state using JSON
At this time it is not possible to get a subset of subset of state data for JSON, ie an XPath selection, the whole state data is returned.
Note
You cannot get individual elements via JSON, just ALL device state
Example, get all state of all “openconfig*” devices:
POST /restconf/operations/clixon-controller:device-rpc HTTP/1.1
Content-Type: application/yang-data+json
{
"clixon-controller:input": {
"device":"openconfig*",
"config": {
"ietf-netconf:get":null
}
}
}
HTTP/1.1 200
{
"clixon-controller:output":{
"tid":"6"
}
}
Polling for result:
GET /restconf/data/clixon-controller:transactions/transaction=6 HTTP/1.1
Accept: application/yang-data+json
where the result would be the complete state of all matching devices.