1# Clixon main example
2
3  * [Content](#content)
4  * [Compile and run](#compile)
5  * [Using the CLI](#using-the-cli)
6  * [Using netconf](#using-netconf)
7  * [Streams](#streams)
8  * [RPC Operations](#rpc-operations)
9  * [State data](#state-data)
10  * [Extensions](#extension)
11  * [Authentication and NACM](#authentication-and-nacm)
12  * [Systemd](#systemd)
13  * [Docker](#docker)
14  * [Plugins](#plugins)
15
16## Content
17
18This directory contains a Clixon example used primarily as a part of the Clixon test suites. It can be used as a basis for making new Clixon applications. But please consider also the minimal [hello](../hello) example as well. It contains the following files:
19* `example.xml`       The configuration file. See [yang/clixon-config@<date>.yang](../../yang/clixon-config@2019-03-05.yang) for the documentation of all available fields.
20* `clixon-example@2019-01-13.yang`      The yang spec of the example.
21* `example_cli.cli`   CLIgen specification.
22* `example_cli.c`     CLI callback plugin containing functions called in the cli file above: a generic callback (`mycallback`) and an example RPC call (`example_client_rpc`).
23* `example_backend.c` Backend callback plugin including example of:
24  * transaction callbacks (validate/commit),
25  * notification,
26  * rpc handler
27  * state-data handler, ie non-config data
28* `example_backend_nacm.c` Secondary backend plugin. Plugins are loaded alphabetically.
29* `example_restconf.c` Restconf callback plugin containing an HTTP basic authentication callback
30* `example_netconf.c` Netconf callback plugin
31* `Makefile.in`       Example makefile where plugins are built and installed
32
33## Compile and run
34
35Before you start,
36* You must configure with: `--enable-optyangs` to run the main example.
37* Make [group setup](../../doc/FAQ.md#do-i-need-to-setup-anything-important)
38* Setup [restconf](../../doc/FAQ.md#how-do-i-use-restconf)
39
40
41```
42    cd example
43    make && sudo make install
44```
45Start backend:
46```
47    sudo clixon_backend -f /usr/local/etc/example.xml -s init
48```
49Edit cli:
50```
51    clixon_cli -f /usr/local/etc/example.xml
52```
53Send netconf command:
54```
55    clixon_netconf -f /usr/local/etc/example.xml
56```
57Start clixon restconf daemon
58```
59    sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
60```
61Send restconf command
62```
63    curl -G http://127.0.0.1/restconf/data
64```
65
66## Using the CLI
67
68The example CLI allows you to modify and view the data model using `set`, `delete` and `show` via generated code.
69There are also many other commands available as examples. View the source file (example_cli.cli)[example_cli.cli] for more details.
70
71The following example shows how to add an interface in candidate, validate and commit it to running, then look at it (as xml) and finally delete it.
72```
73clixon_cli -f /usr/local/etc/example.xml
74cli> set interfaces interface eth9 ?
75 description               enabled                   ipv4
76 ipv6                      link-up-down-trap-enable  type
77cli> set interfaces interface eth9 type ex:eth
78cli> validate
79cli> commit
80cli> show configuration xml
81<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
82   <interface>
83      <name>eth9</name>
84      <type>ex:eth</type>
85      <enabled>true</enabled>
86   </interface>
87</interfaces>
88cli> delete interfaces interface eth9
89```
90
91## Using Netconf
92
93The following example shows how to set data using netconf:
94```
95<rpc><edit-config><target><candidate/></target><config>
96      <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
97         <interface>
98            <name>eth1</name>
99            <enabled>true</enabled>
100            <ipv4>
101               <address>
102                  <ip>9.2.3.4</ip>
103                  <prefix-length>24</prefix-length>
104               </address>
105            </ipv4>
106         </interface>
107      </interfaces>
108</config></edit-config></rpc>]]>]]>
109```
110
111### Getting data using netconf
112```
113<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>
114<rpc><get-config><source><candidate/></source><filter/></get-config></rpc>]]>]]>
115<rpc><get-config><source><candidate/></source><filter type="xpath"/></get-config></rpc>]]>]]>
116<rpc><get-config><source><candidate/></source><filter type="subtree"><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth9</name><type>ex:eth</type></interface></interfaces></data></filter></get-config></rpc>]]>]]>
117<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface"/></get-config></rpc>]]>]]>
118<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>
119```
120## Restconf
121
122Setup a web/reverse-proxy server.
123For example, using nginx, install, and edit config file: /etc/nginx/sites-available/default:
124```
125server {
126        ...
127	location / {
128	    root /usr/share/nginx/html/restconf;
129	    fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
130	    include fastcgi_params;
131        }
132	location /restconf {
133	    fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
134	    include fastcgi_params;
135        }
136	location /streams {
137	    fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
138	    include fastcgi_params;
139 	    proxy_http_version 1.1;
140	    proxy_set_header Connection "";
141        }
142}
143```
144Start nginx daemon
145```
146   sudo /etc/init.d/nginx start
147   sudo systemctl start nginx.service # alternative using systemd
148```
149Start the clixon restconf daemon
150```
151   sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
152```
153then access using curl or wget:
154```
155   curl -X GET http://127.0.0.1/restconf/data/ietf-interfaces:interfaces/interface=eth1/type
156```
157
158More info: (restconf)[../../apps/restconf/README.md].
159
160## Streams
161
162The example has an EXAMPLE stream notification triggering every 5s. To start a notification
163stream in the session using netconf, create a subscription:
164```
165<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>
166<rpc-reply><ok/></rpc-reply>]]>]]>
167<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2019-01-02T10:20:05.929272</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>]]>]]>
168...
169```
170This can also be triggered via the CLI:
171```
172clixon_cli -f /usr/local/etc/example.xml
173cli> notify
174cli> event-class fault;
175reportingEntity {
176    card Ethernet0;
177}
178severity major;
179...
180cli> no notify
181cli>
182```
183
184Restconf support is also supported, see (restconf)[../../apps/restconf/README.md].
185
186
187## RPC Operations
188
189Clixon implements Yang RPC operations by a mechanism that enables you
190to add application-specific operations.  It works by adding
191user-defined callbacks for added netconf operations. It is possible to
192use the extension mechanism independent of the yang rpc construct, but
193not recommended . The example includes an example:
194
195Example using CLI:
196```
197clixon_cli -f /usr/local/etc/example.xml
198cli> rpc ipv4
199<rpc-reply><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>
200```
201Example using Netconf:
202```
203clixon_netconf -qf /usr/local/etc/example.xml
204<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>ipv4</x></example></rpc>]]>]]>
205<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>
206```
207Restconf (assuming nginx started):
208```
209sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data&
210curl -X POST  http://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"ipv4"}}'
211{
212  "clixon-example:output": {
213    "x": "ipv4",
214    "y": "42"
215  }
216}
217```
218
219### Details
220
221The example works by defining an RPC in clixon-example.yang:
222```
223    rpc example {
224	description "Some example input/output for testing RFC7950 7.14.
225                     RPC simply echoes the input for debugging.";
226    	input {
227	    leaf x {
228        ...
229```
230
231In the CLI a netconf rpc call is constructed and sent to the backend: See `example_client_rpc()` in [example_cli.c] CLI plugin.
232
233The clixon backend  plugin [example_backend.c] reveives the netconf call and replies. This is made byregistering a callback handling handling the RPC:
234```
235static int
236example_rpc(clicon_handle h,
237	    cxobj        *xe,           /* Request: <rpc><xn></rpc> */
238	    cbuf         *cbret,        /* Reply eg <rpc-reply>... */
239	    void         *arg,          /* Client session */
240	    void         *regarg)       /* Argument given at register */
241{
242    /* code that echoes the request */
243    return 0;
244}
245int
246clixon_plugin_init(clicon_handle h)
247{
248...
249   rpc_callback_register(h, example_rpc, NULL, "example");
250...
251}
252```
253
254## State data
255
256Netconf <get> and restconf GET also returns state data(not only configuration data).
257
258In YANG state data is specified with `config false;`. In the example,
259`state` is state data, see (example.yang)[example.yang]
260
261To return state data, you need to write a backend state data callback
262with the name "plugin_statedata" where you return an XML tree with
263state. This is then merged with config data by the system.
264
265A static example of returning state data is in the example. Note that
266a real example would poll or get the interface counters via a system
267call, as well as use the "xpath" argument to identify the requested
268state data.
269
270The state data is enabled by starting the backend with: `-- -s`.
271
272## Authentication and NACM
273The example contains some stubs for authorization according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341):
274* A basic auth HTTP callback, see: example_restconf_credentials() containing three example users: andy, wilma, and guest, according to the examples in Appendix A in [RFC8341](https://tools.ietf.org/html/rfc8341).
275* A NACM backend plugin reporting the mandatory NACM state variables.
276
277## Extensions
278
279Clixon supports Yang extensions by writing plugin callback code.
280The example backend implements an "example:e4" Yang extension, as follows:
281```
282    extension e4 {
283       description
284	   "The first child of the ex:e4 (unknown) statement is inserted into
285	    the module as a regular data statement. This means that 'uses bar;'
286	    in the ex:e4 statement below is a valid data node";
287       argument arg;
288    }
289    ex:e4 arg1{
290      uses bar;
291    }
292```
293
294The backend plugin code registers an extension callback in the init struct:
295```
296    .ca_extension=example_extension,        /* yang extensions */
297```
298
299The callback then receives a callback on all "unknown" Yang statements
300during yang parsing. If the extension matches "example:e4", it applies
301the extension. In the example, it copies the child of the "ex:e4" statement and
302inserts in as a proper yang statement in the example module.
303
304## Systemd
305
306Example systemd files for backend and restconf daemons are found under the systemd directory. Install them under /etc/systemd/system for example.
307
308## Docker
309
310See [../../docker/system] for instructions on how to build this example
311as a docker container.
312
313## Plugins
314
315The example includes a restonf, netconf, CLI and two backend plugins.
316Each plugin is initiated with an API struct followed by a plugin init function.
317The content of the API struct is different depending on what kind of plugin it is.
318The plugin init function may also include registering RPC functions, see below is for a backend.
319```
320static clixon_plugin_api api = {
321    "example",          /* name */
322    clixon_plugin_init,
323    plugin_start,
324    plugin_exit,
325    .ca_reset=plugin_reset,/* reset for extra XML at startup*/
326    .ca_statedata=plugin_statedata, /* statedata */
327    .ca_upgrade=example_upgrade,            /* upgrade configuration */
328    .ca_trans_begin=NULL, /* trans begin */
329    .ca_trans_validate=transaction_validate,/* trans validate */
330    .ca_trans_complete=NULL,                /* trans complete */
331    .ca_trans_commit=transaction_commit,    /* trans commit */
332    .ca_trans_end=NULL,                     /* trans end */
333    .ca_trans_abort=NULL                    /* trans abort */
334};
335
336clixon_plugin_api *
337clixon_plugin_init(clicon_handle h)
338{
339    /* Optional callback registration for RPC calls */
340    rpc_callback_register(h, example_rpc, NULL, "example");
341    /* Return plugin API */
342    return &api; /* Return NULL on error */
343}
344```
345
346Here is a corresponding example for a CLI plugin:
347```
348static clixon_plugin_api api = {
349    "example",          /* name */
350    clixon_plugin_init, /* init */
351    NULL,               /* start */
352    NULL,               /* exit */
353    .ca_prompt=NULL,    /* cli_prompthook_t */
354    .ca_suspend=NULL,   /* cligen_susp_cb_t */
355    .ca_interrupt=NULL, /* cligen_interrupt_cb_t */
356};
357```
358