* Restconf RFC 8040 increased feature compliance
* Cache-Control: no-cache added in HTTP responses (RFC Section 5.5)
* Restconf monitoring capabilities (RFC Section 9.1)
* Added support for Yang extensions
* New plugin callback: ca_extension
* Main backend example includes example code on how to implement a Yang extension in a plugin.
* JSON changes
* Non-pretty-print output removed all extra spaces.
* Example: `{"nacm-example:x": 42}` --> {"nacm-example:x":42}`
* Empty JSON container changed from `null` to `{}`.
* Empty list and leafs remain as `null`
* Removed unnecessary configure dependencies
* libnsl, libcrypt, libm, if_vlan,...
* pseudo-plugin added, to enable callbacks also for main programs. Useful for extensions
* Yang Unique statements with multiple schema identifiers did not work on some platforms due to memory error.
364 lines
11 KiB
Bash
Executable file
364 lines
11 KiB
Bash
Executable file
#!/bin/bash
|
|
# Restconf RFC8040 Appendix A and B "jukebox" example
|
|
|
|
# Magic line must be first in script (see README.md)
|
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
|
|
|
APPNAME=example
|
|
|
|
cfg=$dir/conf.xml
|
|
fyang=$dir/restconf.yang
|
|
fxml=$dir/initial.xml
|
|
|
|
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
|
|
cat <<EOF > $cfg
|
|
<clixon-config xmlns="http://clicon.org/config">
|
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
|
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
|
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
|
|
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
|
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
|
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
|
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
|
<CLICON_BACKEND_PIDFILE>$dir/restconf.pidfile</CLICON_BACKEND_PIDFILE>
|
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
|
<CLICON_STREAM_DISCOVERY_RFC8040>true</CLICON_STREAM_DISCOVERY_RFC8040>
|
|
</clixon-config>
|
|
EOF
|
|
|
|
cat <<EOF > $fyang
|
|
module example-jukebox {
|
|
|
|
namespace "http://example.com/ns/example-jukebox";
|
|
prefix "jbox";
|
|
|
|
organization "Example, Inc.";
|
|
contact "support at example.com";
|
|
description "Example Jukebox Data Model Module.";
|
|
revision "2016-08-15" {
|
|
description "Initial version.";
|
|
reference "example.com document 1-4673.";
|
|
}
|
|
|
|
identity genre {
|
|
description
|
|
"Base for all genre types.";
|
|
}
|
|
|
|
// abbreviated list of genre classifications
|
|
identity alternative {
|
|
base genre;
|
|
description
|
|
"Alternative music.";
|
|
}
|
|
identity blues {
|
|
base genre;
|
|
description
|
|
"Blues music.";
|
|
}
|
|
identity country {
|
|
base genre;
|
|
description
|
|
"Country music.";
|
|
}
|
|
identity jazz {
|
|
base genre;
|
|
description
|
|
"Jazz music.";
|
|
}
|
|
identity pop {
|
|
base genre;
|
|
description
|
|
"Pop music.";
|
|
}
|
|
identity rock {
|
|
base genre;
|
|
description
|
|
"Rock music.";
|
|
}
|
|
|
|
container jukebox {
|
|
presence
|
|
"An empty container indicates that the jukebox
|
|
service is available.";
|
|
|
|
description
|
|
"Represents a 'jukebox' resource, with a library, playlists,
|
|
and a 'play' operation.";
|
|
|
|
container library {
|
|
|
|
description
|
|
"Represents the 'jukebox' library resource.";
|
|
|
|
list artist {
|
|
key name;
|
|
description
|
|
"Represents one 'artist' resource within the
|
|
'jukebox' library resource.";
|
|
|
|
leaf name {
|
|
type string {
|
|
length "1 .. max";
|
|
}
|
|
description
|
|
"The name of the artist.";
|
|
}
|
|
|
|
list album {
|
|
key name;
|
|
description
|
|
"Represents one 'album' resource within one
|
|
'artist' resource, within the jukebox library.";
|
|
|
|
leaf name {
|
|
type string {
|
|
length "1 .. max";
|
|
}
|
|
description
|
|
"The name of the album.";
|
|
}
|
|
|
|
leaf genre {
|
|
type identityref { base genre; }
|
|
description
|
|
"The genre identifying the type of music on
|
|
the album.";
|
|
}
|
|
|
|
leaf year {
|
|
type uint16 {
|
|
range "1900 .. max";
|
|
}
|
|
description
|
|
"The year the album was released.";
|
|
}
|
|
|
|
container admin {
|
|
description
|
|
"Administrative information for the album.";
|
|
|
|
leaf label {
|
|
type string;
|
|
description
|
|
"The label that released the album.";
|
|
}
|
|
leaf catalogue-number {
|
|
type string;
|
|
description
|
|
"The album's catalogue number.";
|
|
}
|
|
}
|
|
|
|
list song {
|
|
key name;
|
|
description
|
|
"Represents one 'song' resource within one
|
|
'album' resource, within the jukebox library.";
|
|
|
|
leaf name {
|
|
type string {
|
|
length "1 .. max";
|
|
}
|
|
description
|
|
"The name of the song.";
|
|
}
|
|
|
|
leaf location {
|
|
type string;
|
|
mandatory true;
|
|
description
|
|
"The file location string of the
|
|
media file for the song.";
|
|
}
|
|
leaf format {
|
|
type string;
|
|
description
|
|
"An identifier string for the media type
|
|
for the file associated with the
|
|
'location' leaf for this entry.";
|
|
}
|
|
leaf length {
|
|
type uint32;
|
|
units "seconds";
|
|
description
|
|
"The duration of this song in seconds.";
|
|
}
|
|
} // end list 'song'
|
|
} // end list 'album'
|
|
} // end list 'artist'
|
|
|
|
leaf artist-count {
|
|
type uint32;
|
|
units "artists";
|
|
config false;
|
|
description
|
|
"Number of artists in the library.";
|
|
}
|
|
leaf album-count {
|
|
type uint32;
|
|
units "albums";
|
|
config false;
|
|
description
|
|
"Number of albums in the library.";
|
|
}
|
|
leaf song-count {
|
|
type uint32;
|
|
units "songs";
|
|
config false;
|
|
description
|
|
"Number of songs in the library.";
|
|
}
|
|
} // end library
|
|
|
|
list playlist {
|
|
key name;
|
|
description
|
|
"Example configuration data resource.";
|
|
|
|
leaf name {
|
|
type string;
|
|
description
|
|
"The name of the playlist.";
|
|
}
|
|
leaf description {
|
|
type string;
|
|
description
|
|
"A comment describing the playlist.";
|
|
}
|
|
list song {
|
|
key index;
|
|
ordered-by user;
|
|
|
|
description
|
|
"Example nested configuration data resource.";
|
|
|
|
leaf index { // not really needed
|
|
type uint32;
|
|
description
|
|
"An arbitrary integer index for this playlist song.";
|
|
}
|
|
leaf id {
|
|
type instance-identifier;
|
|
mandatory true;
|
|
description
|
|
"Song identifier. Must identify an instance of
|
|
/jukebox/library/artist/album/song/name.";
|
|
}
|
|
}
|
|
}
|
|
|
|
container player {
|
|
description
|
|
"Represents the jukebox player resource.";
|
|
|
|
leaf gap {
|
|
type decimal64 {
|
|
fraction-digits 1;
|
|
range "0.0 .. 2.0";
|
|
}
|
|
units "tenths of seconds";
|
|
description
|
|
"Time gap between each song.";
|
|
}
|
|
}
|
|
}
|
|
|
|
rpc play {
|
|
description
|
|
"Control function for the jukebox player.";
|
|
input {
|
|
leaf playlist {
|
|
type string;
|
|
mandatory true;
|
|
description
|
|
"The playlist name.";
|
|
}
|
|
leaf song-number {
|
|
type uint32;
|
|
mandatory true;
|
|
description
|
|
"Song number in playlist to play.";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
|
|
new "test params: -f $cfg"
|
|
|
|
if [ $BE -ne 0 ]; then
|
|
new "kill old backend"
|
|
sudo clixon_backend -zf $cfg
|
|
if [ $? -ne 0 ]; then
|
|
err
|
|
fi
|
|
sudo pkill clixon_backend # to be sure
|
|
new "start backend -s init -f $cfg"
|
|
start_backend -s init -f $cfg
|
|
fi
|
|
|
|
new "kill old restconf daemon"
|
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
|
|
|
new "start restconf daemon"
|
|
start_restconf -f $cfg
|
|
|
|
new "waiting"
|
|
wait_backend
|
|
wait_restconf
|
|
|
|
new "B.1.1. Retrieve the Top-Level API Resource root"
|
|
expectpart "$(curl -s -i -X GET -H 'Accept: application/xrd+xml' http://localhost/.well-known/host-meta)" 0 "HTTP/1.1 200 OK" "Content-Type: application/xrd+xml" "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
|
|
|
d='{"ietf-restconf:restconf":{"data":{},"operations":{},"yang-library-version":"2016-06-21"}}'
|
|
new "B.1.1. Retrieve the Top-Level API Resource /restconf json"
|
|
expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" "$d"
|
|
|
|
new "B.1.1. Retrieve the Top-Level API Resource /restconf xml (not in RFC)"
|
|
expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+xml" '<restconf xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><data/><operations/><yang-library-version>2016-06-21</yang-library-version></restconf>'
|
|
|
|
# This just catches the header and the jukebox module, the RFC has foo and bar which
|
|
# seems wrong to recreate
|
|
new "B.1.2. Retrieve the Server Module Information"
|
|
expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":' '"module":\[{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"}'
|
|
|
|
new "B.1.3. Retrieve the Server Capability Information"
|
|
expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' '<capabilities xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability></capabilities>'
|
|
|
|
if false; then # NYI
|
|
new "B.2.1. Create New Data Resources"
|
|
expectpart "$(curl -s -i -X POST -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/library -d '{"example-jukebox:artist":[{"name":"Foo Fighters"}]}')" 0 "HTTP/1.1 201 Created" "Location:" # etc
|
|
|
|
new "B.2.2. Detect Datastore Resource Entity-Tag Change"
|
|
new "B.2.3. Edit a Datastore Resource"
|
|
new "B.2.4. Replace a Datastore Resource"
|
|
new "B.2.5. Edit a Data Resource"
|
|
new 'B.3.1. "content" Parameter'
|
|
new 'B.3.2. "depth" Parameter'
|
|
new 'B.3.3. "fields" Parameter'
|
|
new 'B.3.4. "insert" Parameter'
|
|
new 'B.3.5. "point" Parameter'
|
|
new 'B.3.6. "filter" Parameter'
|
|
new 'B.3.7. "start-time" Parameter'
|
|
new 'B.3.8. "stop-time" Parameter'
|
|
new 'B.3.9. "with-defaults" Parameter'
|
|
fi
|
|
|
|
new "Kill restconf daemon"
|
|
stop_restconf
|
|
|
|
if [ $BE -eq 0 ]; then
|
|
exit # BE
|
|
fi
|
|
|
|
new "Kill backend"
|
|
# Check if premature kill
|
|
pid=`pgrep -u root -f clixon_backend`
|
|
if [ -z "$pid" ]; then
|
|
err "backend already dead"
|
|
fi
|
|
# kill backend
|
|
stop_backend -f $cfg
|
|
|
|
rm -rf $dir
|