From 7e4e1d6debbeefdc4a5d2957befb1fb449f69ab2 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 3 Jun 2018 15:36:05 +0200 Subject: [PATCH] * Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10 * Previous support did no validation of values. * Validation of types and CLI expansion * Example extended with inclusion of iana-if-type RFC 7224 interface identities --- CHANGELOG.md | 8 + README.md | 3 +- apps/cli/cli_generate.c | 58 +- apps/cli/cli_main.c | 19 +- apps/cli/cli_plugin.c | 22 +- example/Makefile.in | 1 + example/example.yang | 14 + example/example_backend.c | 4 +- example/example_cli.cli | 2 +- example/iana-if-type@2014-05-08.yang | 1506 ++++++++++++++++++++++++++ lib/clixon/clixon_plugin.h | 5 +- lib/clixon/clixon_yang.h | 2 + lib/src/clixon_options.c | 1 + lib/src/clixon_xml_map.c | 80 +- lib/src/clixon_yang.c | 76 +- lib/src/clixon_yang_type.c | 17 +- test/lib.sh | 24 +- test/test_cli.sh | 52 +- test/test_datastore.sh | 60 +- test/test_identity.sh | 188 ++++ test/test_leafref.sh | 22 +- test/test_netconf.sh | 30 +- test/test_restconf.sh | 54 +- test/test_restconf2.sh | 43 +- test/test_startup.sh | 12 +- test/test_type.sh | 16 +- test/test_yang.sh | 8 +- 27 files changed, 2124 insertions(+), 203 deletions(-) create mode 100644 example/iana-if-type@2014-05-08.yang create mode 100755 test/test_identity.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 0480c96c..46c0ee11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,13 @@ ## 3.7.0 (Upcoming) ### Major changes: +* Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10 + * Previous support did no validation of values. + * Validation of types and CLI expansion + * Example extended with inclusion of iana-if-type RFC 7224 interface identities + ### Minor changes: +* Added yang identityref runtime validation * Removed cli callback vector functions. Set COMPAT_COMPAT_CLIV if you need to keep these functions in clixon_custom.h. * Replace functions as follows in CLI SPEC files: * cli_setv --> cli_set @@ -27,7 +33,9 @@ * Added --enable-debug. * Added cligen variable translation. * See FAQ and example + ### Corrected Bugs +* Added cli returna value also for single commands (eg -1) * Fixed JSON unbalanced braces resulting in assert. ## 3.6.1 (29 May 2018) diff --git a/README.md b/README.md index 7b3a05e5..bf4d82c5 100644 --- a/README.md +++ b/README.md @@ -99,8 +99,9 @@ also manages an XML datastore. Clixon mainly follows [YANG 1.0 RFC 6020](https://www.rfc-editor.org/rfc/rfc6020.txt) with some exceptions: - conformance: feature, if-feature, deviation -- identity, base, identityref - list features: min/max-elements, unique +- when, must, action statements +- notifications The aim is also to cover new features in YANG 1.1 [YANG RFC 7950](https://www.rfc-editor.org/rfc/rfc7950.txt) diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index 67fa9cec..d4a2aca9 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -204,20 +204,49 @@ yang2cli_var_sub(clicon_handle h, } type = ytype?ytype->ys_argument:NULL; cvtypestr = cv_type2str(cvtype); + if (strcmp(type, "identityref") == 0) + cprintf(cb, "("); cprintf(cb, "<%s:%s", ys->ys_argument, cvtypestr); /* enumeration special case completion */ - if (type && (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0)){ - cprintf(cb, " choice:"); - i = 0; - while ((yi = yn_each((yang_node*)ytype, yi)) != NULL){ - if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT) - continue; - if (i) - cprintf(cb, "|"); - cprintf(cb, "%s", yi->ys_argument); - i++; + if (type){ + if (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0){ + cprintf(cb, " choice:"); + i = 0; + while ((yi = yn_each((yang_node*)ytype, yi)) != NULL){ + if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT) + continue; + if (i) + cprintf(cb, "|"); + cprintf(cb, "%s", yi->ys_argument); + i++; + } + } + else if (strcmp(type, "identityref") == 0){ + yang_stmt *ybaseref; + yang_stmt *ybaseid; + cg_var *cv = NULL; + char *name; + char *id; + /* Add a wildchar string first -let validate take it for default prefix */ + cprintf(cb, ">"); + if (helptext) + cprintf(cb, "(\"%s\")", helptext); + cprintf(cb, "|<%s:%s choice:", ys->ys_argument, cvtypestr); + if ((ybaseref = yang_find((yang_node*)ytype, Y_BASE, NULL)) != NULL && + (ybaseid = yang_find_identity(ys, ybaseref->ys_argument)) != NULL){ + i = 0; + while ((cv = cvec_each(ybaseid->ys_cvec, cv)) != NULL){ + if (i++) + cprintf(cb, "|"); + name = strdup(cv_name_get(cv)); + if ((id=strchr(name, ':')) != NULL) + *id = '\0'; + cprintf(cb, "%s:%s", name, id+1); + } + } } } + if (options & YANG_OPTIONS_FRACTION_DIGITS) cprintf(cb, " fraction-digits:%u", fraction_digits); if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){ @@ -259,10 +288,12 @@ yang2cli_var_sub(clicon_handle h, } if (options & YANG_OPTIONS_PATTERN) cprintf(cb, " regexp:\"%s\"", pattern); - cprintf(cb, ">"); if (helptext) cprintf(cb, "(\"%s\")", helptext); + if (strcmp(type, "identityref") == 0) + cprintf(cb, ")"); + retval = 0; done: return retval; @@ -385,6 +416,7 @@ yang2cli_var(clicon_handle h, enum cv_type cvtype; int options = 0; int completionp; + char *type; if (yang_type_get(ys, &origtype, &yrestype, &options, &mincv, &maxcv, &pattern, &fraction_digits) < 0) @@ -413,11 +445,11 @@ yang2cli_var(clicon_handle h, cprintf(cb, ")"); } else{ - char *type; type = yrestype?yrestype->ys_argument:NULL; if (type) completionp = clicon_cli_genmodel_completion(h) && - strcmp(type, "enumeration") != 0 && + strcmp(type, "enumeration") != 0 && + strcmp(type, "identityref") != 0 && strcmp(type, "bits") != 0; else completionp = clicon_cli_genmodel_completion(h); diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index f1d9678e..2e269016 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -108,6 +108,8 @@ cli_signal_init (clicon_handle h) /*! Interactive CLI command loop * @param[in] h CLICON handle + * @retval 0 + * @retval -1 * @see cligen_loop */ static int @@ -124,7 +126,6 @@ cli_interactive(clicon_handle h) new_mode = cli_syntax_mode(h); if ((cmd = clicon_cliread(h)) == NULL) { cligen_exiting_set(cli_cligen(h), 1); /* EOF */ - retval = -1; goto done; } if ((res = clicon_parse(h, cmd, &new_mode, &result)) < 0) @@ -229,6 +230,7 @@ usage(char *argv0, clicon_handle h) int main(int argc, char **argv) { + int retval = -1; char c; int once; char *tmp; @@ -476,11 +478,19 @@ main(int argc, char **argv) if (restarg != NULL && strlen(restarg)){ char *mode = cli_syntax_mode(h); int result; - clicon_parse(h, restarg, &mode, &result); + + /* */ + if (clicon_parse(h, restarg, &mode, &result) != 1){ + goto done; + } + if (result < 0) + goto done; } /* Go into event-loop unless -1 command-line */ if (!once) - cli_interactive(h); + retval = cli_interactive(h); + else + retval = 0; done: if (treename) free(treename); @@ -491,6 +501,5 @@ main(int argc, char **argv) clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid()); if (h) cli_terminate(h); - - return 0; + return retval; } diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index 369f1691..193e6df3 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -481,6 +481,7 @@ clicon_eval(clicon_handle h, * @param[out] result -2 On eof (shouldnt happen) * -1 On parse error * >=0 Number of matches + * @retval 0 XXX How does this relate to result??? */ int clicon_parse(clicon_handle h, @@ -490,7 +491,7 @@ clicon_parse(clicon_handle h, { char *modename; char *modename0; - int res = -1; + int retval = -1; int r; cli_syntax_t *stx = NULL; cli_syntaxmode_t *smode; @@ -511,10 +512,11 @@ clicon_parse(clicon_handle h, else { if ((smode = syntax_mode_find(stx, modename, 0)) == NULL) { cli_output(f, "Can't find syntax mode '%s'\n", modename); - return -1; + goto done; } } - while(smode) { + if (smode) + while(1) { modename0 = NULL; if ((pt = cligen_tree_active_get(cli_cligen(h))) != NULL) modename0 = pt->pt_name; @@ -530,24 +532,24 @@ clicon_parse(clicon_handle h, clicon_err(OE_UNIX, errno, "cvec_new"); goto done;; } - res = cliread_parse(cli_cligen(h), cmd, pt, &match_obj, cvv); - if (res != CG_MATCH) + retval = cliread_parse(cli_cligen(h), cmd, pt, &match_obj, cvv); + if (retval != CG_MATCH) pt_expand_cleanup_1(pt); /* XXX change to pt_expand_treeref_cleanup */ if (modename0){ cligen_tree_active_set(cli_cligen(h), modename0); modename0 = NULL; } - switch (res) { + switch (retval) { case CG_EOF: /* eof */ case CG_ERROR: cli_output(f, "CLI parse error: %s\n", cmd); goto done; case CG_NOMATCH: /* no match */ - smode = NULL; /* clicon_err(OE_CFG, 0, "CLI syntax error: \"%s\": %s", cmd, cli_nomatch(h));*/ cli_output(f, "CLI syntax error: \"%s\": %s\n", cmd, cli_nomatch(h)); + goto done; break; case CG_MATCH: if (strcmp(modename, *modenamep)){ /* Command in different mode */ @@ -565,12 +567,12 @@ clicon_parse(clicon_handle h, cli_output(f, "CLI syntax error: \"%s\" is ambiguous\n", cmd); goto done; break; - } - } + } /* switch retval */ + } /* while smode */ done: if (cvv) cvec_free(cvv); - return res; + return retval; } /*! Read command from CLIgen's cliread() using current syntax mode. diff --git a/example/Makefile.in b/example/Makefile.in index 0be6a8aa..ac5f73d6 100644 --- a/example/Makefile.in +++ b/example/Makefile.in @@ -69,6 +69,7 @@ YANGSPECS += ietf-routing@2014-10-26.yang YANGSPECS += ietf-ipv4-unicast-routing@2014-10-26.yang YANGSPECS += ietf-ipv6-unicast-routing@2014-10-26.yang YANGSPECS += ietf-ipsec@2016-03-09.yang +YANGSPECS += iana-if-type@2014-05-08.yang # Backend plugin BE_SRC = $(APPNAME)_backend.c diff --git a/example/example.yang b/example/example.yang index f4921978..fbb1c738 100644 --- a/example/example.yang +++ b/example/example.yang @@ -1,14 +1,28 @@ module example { prefix ex; + import ietf-interfaces { + prefix if; + } import ietf-ip { prefix ip; } import ietf-routing { prefix rt; } + import iana-if-type { + prefix ianaift; + } description "Example code that includes ietf-ip and ietf-routing"; + /* Example interface type for tests, local callbacks, etc */ + identity eth { + base if:interface-type; + } + identity loopback { + base if:interface-type; + } /* Translation function example - See also example_cli */ + list translate{ leaf value{ type string; diff --git a/example/example_backend.c b/example/example_backend.c index 495ad14f..a3dfe832 100644 --- a/example/example_backend.c +++ b/example/example_backend.c @@ -190,7 +190,7 @@ plugin_statedata(clicon_handle h, /* Example of (static) statedata, real code would poll state */ if (xml_parse_string("" "eth0" - "eth" + "ex:eth" "42" "", NULL, &xstate) < 0) goto done; @@ -221,7 +221,7 @@ plugin_reset(clicon_handle h, cxobj *xt = NULL; if (xml_parse_string("" - "lolocal" + "loex:loopback" "", NULL, &xt) < 0) goto done; /* Replace parent w fiorst child */ diff --git a/example/example_cli.cli b/example/example_cli.cli index a941eee2..657f884b 100644 --- a/example/example_cli.cli +++ b/example/example_cli.cli @@ -55,7 +55,7 @@ load("Load configuration from XML file") ("Filename (local file merge("Merge file with existent candidate"), load_config_file("filename", "merge"); } example("This is a comment") ("Just a random number"), mycallback("myarg"); -rpc("fib-route rpc") ("routing instance"), fib_route_rpc("myarg"); +rpc("ex:fib-route rpc") ("routing instance"), fib_route_rpc("myarg"); notify("Get notifications from backend"), cli_notify("ROUTING", "1", "text"); no("Negate") notify("Get notifications from backend"), cli_notify("ROUTING", "0", "xml"); lock,cli_lock("candidate"); diff --git a/example/iana-if-type@2014-05-08.yang b/example/iana-if-type@2014-05-08.yang new file mode 100644 index 00000000..da5b65b7 --- /dev/null +++ b/example/iana-if-type@2014-05-08.yang @@ -0,0 +1,1506 @@ + module iana-if-type { + namespace "urn:ietf:params:xml:ns:yang:iana-if-type"; + prefix ianaift; + + import ietf-interfaces { + prefix if; + } + + organization "IANA"; + contact + " Internet Assigned Numbers Authority + + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1 310 823 9358 + "; + description + "This YANG module defines YANG identities for IANA-registered + interface types. + + This YANG module is maintained by IANA and reflects the + 'ifType definitions' registry. + + The latest revision of this YANG module can be obtained from + the IANA web site. + + Requests for new values should be made to IANA via + email (iana@iana.org). + + Copyright (c) 2014 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + The initial version of this YANG module is part of RFC 7224; + see the RFC itself for full legal notices."; + reference + "IANA 'ifType definitions' registry. + "; + + revision 2014-05-08 { + description + "Initial revision."; + reference + "RFC 7224: IANA Interface Type YANG Module"; + } + + identity iana-interface-type { + base if:interface-type; + description + "This identity is used as a base for all interface types + defined in the 'ifType definitions' registry."; + } + identity other { + base iana-interface-type; + } + identity regular1822 { + base iana-interface-type; + } + identity hdh1822 { + base iana-interface-type; + } + identity ddnX25 { + base iana-interface-type; + } + identity rfc877x25 { + base iana-interface-type; + reference + "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer"; + } + identity ethernetCsmacd { + base iana-interface-type; + description + "For all Ethernet-like interfaces, regardless of speed, + as per RFC 3635."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity iso88023Csmacd { + base iana-interface-type; + status deprecated; + description + "Deprecated via RFC 3635. + Use ethernetCsmacd(6) instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity iso88024TokenBus { + base iana-interface-type; + } + identity iso88025TokenRing { + base iana-interface-type; + } + identity iso88026Man { + base iana-interface-type; + } + identity starLan { + base iana-interface-type; + status deprecated; + description + "Deprecated via RFC 3635. + Use ethernetCsmacd(6) instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity proteon10Mbit { + base iana-interface-type; + } + identity proteon80Mbit { + base iana-interface-type; + } + identity hyperchannel { + base iana-interface-type; + } + identity fddi { + base iana-interface-type; + reference + "RFC 1512 - FDDI Management Information Base"; + } + identity lapb { + base iana-interface-type; + reference + "RFC 1381 - SNMP MIB Extension for X.25 LAPB"; + } + identity sdlc { + base iana-interface-type; + } + identity ds1 { + base iana-interface-type; + description + "DS1-MIB."; + reference + "RFC 4805 - Definitions of Managed Objects for the + DS1, J1, E1, DS2, and E2 Interface Types"; + } + identity e1 { + base iana-interface-type; + status obsolete; + description + "Obsolete; see DS1-MIB."; + reference + "RFC 4805 - Definitions of Managed Objects for the + DS1, J1, E1, DS2, and E2 Interface Types"; + } + identity basicISDN { + base iana-interface-type; + description + "No longer used. See also RFC 2127."; + } + identity primaryISDN { + base iana-interface-type; + description + "No longer used. See also RFC 2127."; + } + identity propPointToPointSerial { + base iana-interface-type; + description + "Proprietary serial."; + } + identity ppp { + base iana-interface-type; + } + identity softwareLoopback { + base iana-interface-type; + } + identity eon { + base iana-interface-type; + description + "CLNP over IP."; + } + identity ethernet3Mbit { + base iana-interface-type; + } + identity nsip { + base iana-interface-type; + description + "XNS over IP."; + } + identity slip { + base iana-interface-type; + description + "Generic SLIP."; + } + identity ultra { + base iana-interface-type; + description + "Ultra Technologies."; + } + identity ds3 { + base iana-interface-type; + description + "DS3-MIB."; + reference + "RFC 3896 - Definitions of Managed Objects for the + DS3/E3 Interface Type"; + } + identity sip { + base iana-interface-type; + description + "SMDS, coffee."; + reference + "RFC 1694 - Definitions of Managed Objects for SMDS + Interfaces using SMIv2"; + } + identity frameRelay { + base iana-interface-type; + description + "DTE only."; + reference + "RFC 2115 - Management Information Base for Frame Relay + DTEs Using SMIv2"; + } + identity rs232 { + base iana-interface-type; + reference + "RFC 1659 - Definitions of Managed Objects for RS-232-like + Hardware Devices using SMIv2"; + } + identity para { + base iana-interface-type; + description + "Parallel-port."; + reference + "RFC 1660 - Definitions of Managed Objects for + Parallel-printer-like Hardware Devices using + SMIv2"; + } + identity arcnet { + base iana-interface-type; + description + "ARCnet."; + } + identity arcnetPlus { + base iana-interface-type; + description + "ARCnet Plus."; + } + identity atm { + base iana-interface-type; + description + "ATM cells."; + } + identity miox25 { + base iana-interface-type; + reference + "RFC 1461 - SNMP MIB extension for Multiprotocol + Interconnect over X.25"; + } + identity sonet { + base iana-interface-type; + description + "SONET or SDH."; + } + identity x25ple { + base iana-interface-type; + reference + "RFC 2127 - ISDN Management Information Base using SMIv2"; + } + identity iso88022llc { + base iana-interface-type; + } + identity localTalk { + base iana-interface-type; + } + identity smdsDxi { + base iana-interface-type; + } + identity frameRelayService { + base iana-interface-type; + description + "FRNETSERV-MIB."; + reference + "RFC 2954 - Definitions of Managed Objects for Frame + Relay Service"; + } + identity v35 { + base iana-interface-type; + } + identity hssi { + base iana-interface-type; + } + identity hippi { + base iana-interface-type; + } + identity modem { + base iana-interface-type; + description + "Generic modem."; + } + identity aal5 { + base iana-interface-type; + description + "AAL5 over ATM."; + } + identity sonetPath { + base iana-interface-type; + } + identity sonetVT { + base iana-interface-type; + } + identity smdsIcip { + base iana-interface-type; + description + "SMDS InterCarrier Interface."; + } + identity propVirtual { + base iana-interface-type; + description + "Proprietary virtual/internal."; + reference + "RFC 2863 - The Interfaces Group MIB"; + } + identity propMultiplexor { + base iana-interface-type; + description + "Proprietary multiplexing."; + reference + "RFC 2863 - The Interfaces Group MIB"; + } + identity ieee80212 { + base iana-interface-type; + description + "100BaseVG."; + } + identity fibreChannel { + base iana-interface-type; + description + "Fibre Channel."; + } + identity hippiInterface { + base iana-interface-type; + description + "HIPPI interfaces."; + } + identity frameRelayInterconnect { + base iana-interface-type; + status obsolete; + description + "Obsolete; use either + frameRelay(32) or frameRelayService(44)."; + } + identity aflane8023 { + base iana-interface-type; + description + "ATM Emulated LAN for 802.3."; + } + identity aflane8025 { + base iana-interface-type; + description + "ATM Emulated LAN for 802.5."; + } + identity cctEmul { + base iana-interface-type; + description + "ATM Emulated circuit."; + } + identity fastEther { + base iana-interface-type; + status deprecated; + description + "Obsoleted via RFC 3635. + ethernetCsmacd(6) should be used instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity isdn { + base iana-interface-type; + description + "ISDN and X.25."; + reference + "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN + in the Packet Mode"; + } + identity v11 { + base iana-interface-type; + description + "CCITT V.11/X.21."; + } + identity v36 { + base iana-interface-type; + description + "CCITT V.36."; + } + identity g703at64k { + base iana-interface-type; + description + "CCITT G703 at 64Kbps."; + } + identity g703at2mb { + base iana-interface-type; + status obsolete; + description + "Obsolete; see DS1-MIB."; + } + identity qllc { + base iana-interface-type; + description + "SNA QLLC."; + } + identity fastEtherFX { + base iana-interface-type; + status deprecated; + description + "Obsoleted via RFC 3635. + ethernetCsmacd(6) should be used instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity channel { + base iana-interface-type; + description + "Channel."; + } + identity ieee80211 { + base iana-interface-type; + description + "Radio spread spectrum."; + } + identity ibm370parChan { + base iana-interface-type; + description + "IBM System 360/370 OEMI Channel."; + } + identity escon { + base iana-interface-type; + description + "IBM Enterprise Systems Connection."; + } + identity dlsw { + base iana-interface-type; + description + "Data Link Switching."; + } + identity isdns { + base iana-interface-type; + description + "ISDN S/T interface."; + } + identity isdnu { + base iana-interface-type; + description + "ISDN U interface."; + } + identity lapd { + base iana-interface-type; + description + "Link Access Protocol D."; + } + identity ipSwitch { + base iana-interface-type; + description + "IP Switching Objects."; + } + identity rsrb { + base iana-interface-type; + description + "Remote Source Route Bridging."; + } + identity atmLogical { + base iana-interface-type; + description + "ATM Logical Port."; + reference + "RFC 3606 - Definitions of Supplemental Managed Objects + for ATM Interface"; + } + identity ds0 { + base iana-interface-type; + description + "Digital Signal Level 0."; + reference + "RFC 2494 - Definitions of Managed Objects for the DS0 + and DS0 Bundle Interface Type"; + } + identity ds0Bundle { + base iana-interface-type; + description + "Group of ds0s on the same ds1."; + reference + "RFC 2494 - Definitions of Managed Objects for the DS0 + and DS0 Bundle Interface Type"; + } + identity bsc { + base iana-interface-type; + description + "Bisynchronous Protocol."; + } + identity async { + base iana-interface-type; + description + "Asynchronous Protocol."; + } + identity cnr { + base iana-interface-type; + description + "Combat Net Radio."; + } + identity iso88025Dtr { + base iana-interface-type; + description + "ISO 802.5r DTR."; + } + identity eplrs { + base iana-interface-type; + description + "Ext Pos Loc Report Sys."; + } + identity arap { + base iana-interface-type; + description + "Appletalk Remote Access Protocol."; + } + identity propCnls { + base iana-interface-type; + description + "Proprietary Connectionless Protocol."; + } + identity hostPad { + base iana-interface-type; + description + "CCITT-ITU X.29 PAD Protocol."; + } + identity termPad { + base iana-interface-type; + description + "CCITT-ITU X.3 PAD Facility."; + } + identity frameRelayMPI { + base iana-interface-type; + description + "Multiproto Interconnect over FR."; + } + identity x213 { + base iana-interface-type; + description + "CCITT-ITU X213."; + } + identity adsl { + base iana-interface-type; + description + "Asymmetric Digital Subscriber Loop."; + } + identity radsl { + base iana-interface-type; + description + "Rate-Adapt. Digital Subscriber Loop."; + } + identity sdsl { + base iana-interface-type; + description + "Symmetric Digital Subscriber Loop."; + } + identity vdsl { + base iana-interface-type; + description + "Very H-Speed Digital Subscrib. Loop."; + } + identity iso88025CRFPInt { + base iana-interface-type; + description + "ISO 802.5 CRFP."; + } + identity myrinet { + base iana-interface-type; + description + "Myricom Myrinet."; + } + identity voiceEM { + base iana-interface-type; + description + "Voice recEive and transMit."; + } + identity voiceFXO { + base iana-interface-type; + description + "Voice Foreign Exchange Office."; + } + identity voiceFXS { + base iana-interface-type; + description + "Voice Foreign Exchange Station."; + } + identity voiceEncap { + base iana-interface-type; + description + "Voice encapsulation."; + } + identity voiceOverIp { + base iana-interface-type; + description + "Voice over IP encapsulation."; + } + identity atmDxi { + base iana-interface-type; + description + "ATM DXI."; + } + identity atmFuni { + base iana-interface-type; + description + "ATM FUNI."; + } + identity atmIma { + base iana-interface-type; + description + "ATM IMA."; + } + identity pppMultilinkBundle { + base iana-interface-type; + description + "PPP Multilink Bundle."; + } + identity ipOverCdlc { + base iana-interface-type; + description + "IBM ipOverCdlc."; + } + identity ipOverClaw { + base iana-interface-type; + description + "IBM Common Link Access to Workstn."; + } + identity stackToStack { + base iana-interface-type; + description + "IBM stackToStack."; + } + identity virtualIpAddress { + base iana-interface-type; + description + "IBM VIPA."; + } + identity mpc { + base iana-interface-type; + description + "IBM multi-protocol channel support."; + } + identity ipOverAtm { + base iana-interface-type; + description + "IBM ipOverAtm."; + reference + "RFC 2320 - Definitions of Managed Objects for Classical IP + and ARP Over ATM Using SMIv2 (IPOA-MIB)"; + } + identity iso88025Fiber { + base iana-interface-type; + description + "ISO 802.5j Fiber Token Ring."; + } + identity tdlc { + base iana-interface-type; + description + "IBM twinaxial data link control."; + } + identity gigabitEthernet { + base iana-interface-type; + status deprecated; + description + "Obsoleted via RFC 3635. + ethernetCsmacd(6) should be used instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity hdlc { + base iana-interface-type; + description + "HDLC."; + } + identity lapf { + base iana-interface-type; + description + "LAP F."; + } + identity v37 { + base iana-interface-type; + description + "V.37."; + } + identity x25mlp { + base iana-interface-type; + description + "Multi-Link Protocol."; + } + identity x25huntGroup { + base iana-interface-type; + description + "X25 Hunt Group."; + } + identity transpHdlc { + base iana-interface-type; + description + "Transp HDLC."; + } + identity interleave { + base iana-interface-type; + description + "Interleave channel."; + } + identity fast { + base iana-interface-type; + description + "Fast channel."; + } + identity ip { + base iana-interface-type; + description + "IP (for APPN HPR in IP networks)."; + } + identity docsCableMaclayer { + base iana-interface-type; + description + "CATV Mac Layer."; + } + identity docsCableDownstream { + base iana-interface-type; + description + "CATV Downstream interface."; + } + identity docsCableUpstream { + base iana-interface-type; + description + "CATV Upstream interface."; + } + identity a12MppSwitch { + base iana-interface-type; + description + "Avalon Parallel Processor."; + } + identity tunnel { + base iana-interface-type; + description + "Encapsulation interface."; + } + identity coffee { + base iana-interface-type; + description + "Coffee pot."; + reference + "RFC 2325 - Coffee MIB"; + } + identity ces { + base iana-interface-type; + description + "Circuit Emulation Service."; + } + identity atmSubInterface { + base iana-interface-type; + description + "ATM Sub Interface."; + } + identity l2vlan { + base iana-interface-type; + description + "Layer 2 Virtual LAN using 802.1Q."; + } + identity l3ipvlan { + base iana-interface-type; + description + "Layer 3 Virtual LAN using IP."; + } + identity l3ipxvlan { + base iana-interface-type; + description + "Layer 3 Virtual LAN using IPX."; + } + identity digitalPowerline { + base iana-interface-type; + description + "IP over Power Lines."; + } + identity mediaMailOverIp { + base iana-interface-type; + description + "Multimedia Mail over IP."; + } + identity dtm { + base iana-interface-type; + description + "Dynamic synchronous Transfer Mode."; + } + identity dcn { + base iana-interface-type; + description + "Data Communications Network."; + } + identity ipForward { + base iana-interface-type; + description + "IP Forwarding Interface."; + } + identity msdsl { + base iana-interface-type; + description + "Multi-rate Symmetric DSL."; + } + identity ieee1394 { + base iana-interface-type; + description + "IEEE1394 High Performance Serial Bus."; + } + identity if-gsn { + base iana-interface-type; + description + "HIPPI-6400."; + } + identity dvbRccMacLayer { + base iana-interface-type; + description + "DVB-RCC MAC Layer."; + } + identity dvbRccDownstream { + base iana-interface-type; + description + "DVB-RCC Downstream Channel."; + } + identity dvbRccUpstream { + base iana-interface-type; + description + "DVB-RCC Upstream Channel."; + } + identity atmVirtual { + base iana-interface-type; + description + "ATM Virtual Interface."; + } + identity mplsTunnel { + base iana-interface-type; + description + "MPLS Tunnel Virtual Interface."; + } + identity srp { + base iana-interface-type; + description + "Spatial Reuse Protocol."; + } + identity voiceOverAtm { + base iana-interface-type; + description + "Voice over ATM."; + } + identity voiceOverFrameRelay { + base iana-interface-type; + description + "Voice Over Frame Relay."; + } + identity idsl { + base iana-interface-type; + description + "Digital Subscriber Loop over ISDN."; + } + identity compositeLink { + base iana-interface-type; + description + "Avici Composite Link Interface."; + } + identity ss7SigLink { + base iana-interface-type; + description + "SS7 Signaling Link."; + } + identity propWirelessP2P { + base iana-interface-type; + description + "Prop. P2P wireless interface."; + } + identity frForward { + base iana-interface-type; + description + "Frame Forward Interface."; + } + identity rfc1483 { + base iana-interface-type; + description + "Multiprotocol over ATM AAL5."; + reference + "RFC 1483 - Multiprotocol Encapsulation over ATM + Adaptation Layer 5"; + } + identity usb { + base iana-interface-type; + description + "USB Interface."; + } + identity ieee8023adLag { + base iana-interface-type; + description + "IEEE 802.3ad Link Aggregate."; + } + identity bgppolicyaccounting { + base iana-interface-type; + description + "BGP Policy Accounting."; + } + identity frf16MfrBundle { + base iana-interface-type; + description + "FRF.16 Multilink Frame Relay."; + } + identity h323Gatekeeper { + base iana-interface-type; + description + "H323 Gatekeeper."; + } + identity h323Proxy { + base iana-interface-type; + description + "H323 Voice and Video Proxy."; + } + identity mpls { + base iana-interface-type; + description + "MPLS."; + } + identity mfSigLink { + base iana-interface-type; + description + "Multi-frequency signaling link."; + } + identity hdsl2 { + base iana-interface-type; + description + "High Bit-Rate DSL - 2nd generation."; + } + identity shdsl { + base iana-interface-type; + description + "Multirate HDSL2."; + } + identity ds1FDL { + base iana-interface-type; + description + "Facility Data Link (4Kbps) on a DS1."; + } + identity pos { + base iana-interface-type; + description + "Packet over SONET/SDH Interface."; + } + identity dvbAsiIn { + base iana-interface-type; + description + "DVB-ASI Input."; + } + identity dvbAsiOut { + base iana-interface-type; + description + "DVB-ASI Output."; + } + identity plc { + base iana-interface-type; + description + "Power Line Communications."; + } + identity nfas { + base iana-interface-type; + description + "Non-Facility Associated Signaling."; + } + identity tr008 { + base iana-interface-type; + description + "TR008."; + } + identity gr303RDT { + base iana-interface-type; + description + "Remote Digital Terminal."; + } + identity gr303IDT { + base iana-interface-type; + description + "Integrated Digital Terminal."; + } + identity isup { + base iana-interface-type; + description + "ISUP."; + } + identity propDocsWirelessMaclayer { + base iana-interface-type; + description + "Cisco proprietary Maclayer."; + } + identity propDocsWirelessDownstream { + base iana-interface-type; + description + "Cisco proprietary Downstream."; + } + identity propDocsWirelessUpstream { + base iana-interface-type; + description + "Cisco proprietary Upstream."; + } + identity hiperlan2 { + base iana-interface-type; + description + "HIPERLAN Type 2 Radio Interface."; + } + identity propBWAp2Mp { + base iana-interface-type; + description + "PropBroadbandWirelessAccesspt2Multipt (use of this value + for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f + is deprecated, and ieee80216WMAN(237) should be used + instead)."; + } + identity sonetOverheadChannel { + base iana-interface-type; + description + "SONET Overhead Channel."; + } + identity digitalWrapperOverheadChannel { + base iana-interface-type; + description + "Digital Wrapper."; + } + identity aal2 { + base iana-interface-type; + description + "ATM adaptation layer 2."; + } + identity radioMAC { + base iana-interface-type; + description + "MAC layer over radio links."; + } + identity atmRadio { + base iana-interface-type; + description + "ATM over radio links."; + } + identity imt { + base iana-interface-type; + description + "Inter-Machine Trunks."; + } + identity mvl { + base iana-interface-type; + description + "Multiple Virtual Lines DSL."; + } + identity reachDSL { + base iana-interface-type; + description + "Long Reach DSL."; + } + identity frDlciEndPt { + base iana-interface-type; + description + "Frame Relay DLCI End Point."; + } + identity atmVciEndPt { + base iana-interface-type; + description + "ATM VCI End Point."; + } + identity opticalChannel { + base iana-interface-type; + description + "Optical Channel."; + } + identity opticalTransport { + base iana-interface-type; + description + "Optical Transport."; + } + identity propAtm { + base iana-interface-type; + description + "Proprietary ATM."; + } + identity voiceOverCable { + base iana-interface-type; + description + "Voice Over Cable Interface."; + } + identity infiniband { + base iana-interface-type; + description + "Infiniband."; + } + identity teLink { + base iana-interface-type; + description + "TE Link."; + } + identity q2931 { + base iana-interface-type; + description + "Q.2931."; + } + identity virtualTg { + base iana-interface-type; + description + "Virtual Trunk Group."; + } + identity sipTg { + base iana-interface-type; + description + "SIP Trunk Group."; + } + identity sipSig { + base iana-interface-type; + description + "SIP Signaling."; + } + identity docsCableUpstreamChannel { + base iana-interface-type; + description + "CATV Upstream Channel."; + } + identity econet { + base iana-interface-type; + description + "Acorn Econet."; + } + identity pon155 { + base iana-interface-type; + description + "FSAN 155Mb Symetrical PON interface."; + } + identity pon622 { + base iana-interface-type; + description + "FSAN 622Mb Symetrical PON interface."; + } + identity bridge { + base iana-interface-type; + description + "Transparent bridge interface."; + } + identity linegroup { + base iana-interface-type; + description + "Interface common to multiple lines."; + } + identity voiceEMFGD { + base iana-interface-type; + description + "Voice E&M Feature Group D."; + } + identity voiceFGDEANA { + base iana-interface-type; + description + "Voice FGD Exchange Access North American."; + } + identity voiceDID { + base iana-interface-type; + description + "Voice Direct Inward Dialing."; + } + identity mpegTransport { + base iana-interface-type; + description + "MPEG transport interface."; + } + identity sixToFour { + base iana-interface-type; + status deprecated; + description + "6to4 interface (DEPRECATED)."; + reference + "RFC 4087 - IP Tunnel MIB"; + } + identity gtp { + base iana-interface-type; + description + "GTP (GPRS Tunneling Protocol)."; + } + identity pdnEtherLoop1 { + base iana-interface-type; + description + "Paradyne EtherLoop 1."; + } + identity pdnEtherLoop2 { + base iana-interface-type; + description + "Paradyne EtherLoop 2."; + } + identity opticalChannelGroup { + base iana-interface-type; + description + "Optical Channel Group."; + } + identity homepna { + base iana-interface-type; + description + "HomePNA ITU-T G.989."; + } + identity gfp { + base iana-interface-type; + description + "Generic Framing Procedure (GFP)."; + } + identity ciscoISLvlan { + base iana-interface-type; + description + "Layer 2 Virtual LAN using Cisco ISL."; + } + identity actelisMetaLOOP { + base iana-interface-type; + description + "Acteleis proprietary MetaLOOP High Speed Link."; + } + identity fcipLink { + base iana-interface-type; + description + "FCIP Link."; + } + identity rpr { + base iana-interface-type; + description + "Resilient Packet Ring Interface Type."; + } + identity qam { + base iana-interface-type; + description + "RF Qam Interface."; + } + identity lmp { + base iana-interface-type; + description + "Link Management Protocol."; + reference + "RFC 4327 - Link Management Protocol (LMP) Management + Information Base (MIB)"; + } + identity cblVectaStar { + base iana-interface-type; + description + "Cambridge Broadband Networks Limited VectaStar."; + } + identity docsCableMCmtsDownstream { + base iana-interface-type; + description + "CATV Modular CMTS Downstream Interface."; + } + identity adsl2 { + base iana-interface-type; + status deprecated; + description + "Asymmetric Digital Subscriber Loop Version 2 + (DEPRECATED/OBSOLETED - please use adsl2plus(238) + instead)."; + reference + "RFC 4706 - Definitions of Managed Objects for Asymmetric + Digital Subscriber Line 2 (ADSL2)"; + } + identity macSecControlledIF { + base iana-interface-type; + description + "MACSecControlled."; + } + identity macSecUncontrolledIF { + base iana-interface-type; + description + "MACSecUncontrolled."; + } + identity aviciOpticalEther { + base iana-interface-type; + description + "Avici Optical Ethernet Aggregate."; + } + identity atmbond { + base iana-interface-type; + description + "atmbond."; + } + identity voiceFGDOS { + base iana-interface-type; + description + "Voice FGD Operator Services."; + } + identity mocaVersion1 { + base iana-interface-type; + description + "MultiMedia over Coax Alliance (MoCA) Interface + as documented in information provided privately to IANA."; + } + identity ieee80216WMAN { + base iana-interface-type; + description + "IEEE 802.16 WMAN interface."; + } + identity adsl2plus { + base iana-interface-type; + description + "Asymmetric Digital Subscriber Loop Version 2 - + Version 2 Plus and all variants."; + } + identity dvbRcsMacLayer { + base iana-interface-type; + description + "DVB-RCS MAC Layer."; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + identity dvbTdm { + base iana-interface-type; + description + "DVB Satellite TDM."; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + identity dvbRcsTdma { + base iana-interface-type; + description + "DVB-RCS TDMA."; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + identity x86Laps { + base iana-interface-type; + description + "LAPS based on ITU-T X.86/Y.1323."; + } + identity wwanPP { + base iana-interface-type; + description + "3GPP WWAN."; + } + identity wwanPP2 { + base iana-interface-type; + description + "3GPP2 WWAN."; + } + identity voiceEBS { + base iana-interface-type; + description + "Voice P-phone EBS physical interface."; + } + identity ifPwType { + base iana-interface-type; + description + "Pseudowire interface type."; + reference + "RFC 5601 - Pseudowire (PW) Management Information Base (MIB)"; + } + identity ilan { + base iana-interface-type; + description + "Internal LAN on a bridge per IEEE 802.1ap."; + } + identity pip { + base iana-interface-type; + description + "Provider Instance Port on a bridge per IEEE 802.1ah PBB."; + } + identity aluELP { + base iana-interface-type; + description + "Alcatel-Lucent Ethernet Link Protection."; + } + identity gpon { + base iana-interface-type; + description + "Gigabit-capable passive optical networks (G-PON) as per + ITU-T G.948."; + } + identity vdsl2 { + base iana-interface-type; + description + "Very high speed digital subscriber line Version 2 + (as per ITU-T Recommendation G.993.2)."; + reference + "RFC 5650 - Definitions of Managed Objects for Very High + Speed Digital Subscriber Line 2 (VDSL2)"; + } + identity capwapDot11Profile { + base iana-interface-type; + description + "WLAN Profile Interface."; + reference + "RFC 5834 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Binding MIB for + IEEE 802.11"; + } + identity capwapDot11Bss { + base iana-interface-type; + description + "WLAN BSS Interface."; + reference + "RFC 5834 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Binding MIB for + IEEE 802.11"; + } + identity capwapWtpVirtualRadio { + base iana-interface-type; + description + "WTP Virtual Radio Interface."; + reference + "RFC 5833 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Base MIB"; + } + identity bits { + base iana-interface-type; + description + "bitsport."; + } + identity docsCableUpstreamRfPort { + base iana-interface-type; + description + "DOCSIS CATV Upstream RF Port."; + } + identity cableDownstreamRfPort { + base iana-interface-type; + description + "CATV downstream RF Port."; + } + identity vmwareVirtualNic { + base iana-interface-type; + description + "VMware Virtual Network Interface."; + } + identity ieee802154 { + base iana-interface-type; + description + "IEEE 802.15.4 WPAN interface."; + reference + "IEEE 802.15.4-2006"; + } + identity otnOdu { + base iana-interface-type; + description + "OTN Optical Data Unit."; + } + identity otnOtu { + base iana-interface-type; + description + "OTN Optical channel Transport Unit."; + } + identity ifVfiType { + base iana-interface-type; + description + "VPLS Forwarding Instance Interface Type."; + } + identity g9981 { + base iana-interface-type; + description + "G.998.1 bonded interface."; + } + identity g9982 { + base iana-interface-type; + description + "G.998.2 bonded interface."; + } + identity g9983 { + base iana-interface-type; + description + "G.998.3 bonded interface."; + } + identity aluEpon { + base iana-interface-type; + description + "Ethernet Passive Optical Networks (E-PON)."; + } + identity aluEponOnu { + base iana-interface-type; + description + "EPON Optical Network Unit."; + } + identity aluEponPhysicalUni { + base iana-interface-type; + description + "EPON physical User to Network interface."; + } + identity aluEponLogicalLink { + base iana-interface-type; + description + "The emulation of a point-to-point link over the EPON + layer."; + } + identity aluGponOnu { + base iana-interface-type; + description + "GPON Optical Network Unit."; + reference + "ITU-T G.984.2"; + } + identity aluGponPhysicalUni { + base iana-interface-type; + description + "GPON physical User to Network interface."; + reference + "ITU-T G.984.2"; + } + identity vmwareNicTeam { + base iana-interface-type; + description + "VMware NIC Team."; + } + } diff --git a/lib/clixon/clixon_plugin.h b/lib/clixon/clixon_plugin.h index f7aa7174..cd340458 100644 --- a/lib/clixon/clixon_plugin.h +++ b/lib/clixon/clixon_plugin.h @@ -91,8 +91,9 @@ typedef int (plgexit_t)(clicon_handle); /* Plugin exit */ /* Plugin authorization. Set username option (or not) * @param[in] Clicon handle * @param[in] void*, eg Fastcgihandle request restconf - * @retval 0 if credentials OK - * @retval -1 credentials not OK + * @retval -1 Fatal error + * @retval 0 Credential not OK + * @retval 1 Credential OK */ typedef int (plgauth_t)(clicon_handle, void *); diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index c77d64aa..806baac7 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -202,6 +202,7 @@ struct yang_stmt{ cvec *ys_cvec; /* List of stmt-specific variables Y_RANGE: range_min, range_max Y_LIST: vector of keys + Y_TYPE & identity: store all derived types */ yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */ }; @@ -252,6 +253,7 @@ yang_stmt *yang_find(yang_node *yn, int keyword, char *argument); yang_stmt *yang_find_datanode(yang_node *yn, char *argument); yang_stmt *yang_find_schemanode(yang_node *yn, char *argument); yang_stmt *yang_find_topnode(yang_spec *ysp, char *name, yang_class class); +char *yang_find_myprefix(yang_stmt *ys); int yang_order(yang_stmt *y); int yang_print(FILE *f, yang_node *yn); int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal); diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index 45c642e0..4f7cc68a 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -186,6 +186,7 @@ clicon_option_readfile_xml(clicon_hash_t *copt, /*! Initialize option values * * Set default options, Read config-file, Check that all values are set. + * Read clixon system config files * @param[in] h clicon handle */ int diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 60ea29a6..6960d6a7 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -226,7 +226,7 @@ xml2cli(FILE *f, return retval; } -/*! Validate an xml node of type leafref, ensure the value is one of that path's reference +/*! Validate xml node of type leafref, ensure the value is one of that path's reference * @param[in] xt XML leaf node of type leafref * @param[in] ytype Yang type statement belonging to the XML node */ @@ -270,6 +270,70 @@ validate_leafref(cxobj *xt, return retval; } +/*! Validate xml node of type identityref, ensure value is a defined identity + * Check if a given node has value derived from base identity. This is + * a run-time check necessary when validating eg netconf. + * Valid values for an identityref are any identities derived from all + * the identityref's base identities. + * Example: + * b0 --> b1 --> b2 (b1 & b2 are derived) + * identityref b2 + * base b0; + * This function does: derived_from(b2, b0); + * @param[in] xt XML leaf node of type identityref + * @param[in] ys Yang spec of leaf + * @param[in] ytype Yang type field of type identityref + * @see ys_populate_identity where the derived types are set + * @see RFC7950 Sec 9.10.2: + + */ +static int +validate_identityref(cxobj *xt, + yang_stmt *ys, + yang_stmt *ytype) +{ + int retval = -1; + char *node; + yang_stmt *ybaseref; /* This is the type's base reference */ + yang_stmt *ybaseid; + char *prefix = NULL; + cbuf *cb = NULL; + + /* Get idref value. Then see if this value is derived from ytype. + * Always add default prefix because derived identifiers are stored with + * prefixes in the base identifiers derived-list. + */ + if ((node = xml_body(xt)) == NULL) + return 0; + if (strchr(node, ':') == NULL){ + prefix = yang_find_myprefix(ys); + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + cprintf(cb, "%s:%s", prefix, node); + node = cbuf_get(cb); + } + /* This is the type's base reference */ + if ((ybaseref = yang_find((yang_node*)ytype, Y_BASE, NULL)) == NULL){ + clicon_err(OE_DB, 0, "Identityref validation failed, no base"); + goto done; + } + /* This is the actual base identity */ + if ((ybaseid = yang_find_identity(ybaseref, ybaseref->ys_argument)) == NULL){ + clicon_err(OE_DB, 0, "Identityref validation failed, no base identity"); + goto done; + } + /* Here check if node is in the derived node list of the base identity */ + if (cvec_find(ybaseid->ys_cvec, node) == NULL){ + clicon_err(OE_DB, 0, "Identityref validation failed, %s not derived from %s", node, ybaseid->ys_argument); + goto done; + } + retval = 0; + done: + return retval; +} + /*! Validate a single XML node with yang specification for added entry * 1. Check if mandatory leafs present as subs. * 2. Check leaf values, eg int ranges and string regexps. @@ -374,10 +438,16 @@ xml_yang_validate_all(cxobj *xt, /* Special case if leaf is leafref, then first check against current xml tree */ - if ((ytype = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL && - strcmp(ytype->ys_argument, "leafref") == 0) - if (validate_leafref(xt, ytype) < 0) - goto done; + if ((ytype = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){ + if (strcmp(ytype->ys_argument, "leafref") == 0){ + if (validate_leafref(xt, ytype) < 0) + goto done; + } + else if (strcmp(ytype->ys_argument, "identityref") == 0){ + if (validate_identityref(xt, ys, ytype) < 0) + goto done; + } + } break; default: break; diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 93074e32..cd9a567d 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -817,8 +817,6 @@ yarg_prefix(yang_stmt *ys) return prefix; } - - /*! Given a yang statement and a prefix, return yang module to that prefix * Note, not the other module but the proxy import statement only * @param[in] ys A yang statement @@ -1168,6 +1166,8 @@ ys_populate_range(yang_stmt *ys, /*! Sanity check yang type statement * XXX: Replace with generic parent/child type-check + * @param[in] ys The yang statement (type) to populate. + * @ */ static int ys_populate_type(yang_stmt *ys, @@ -1199,28 +1199,82 @@ ys_populate_type(yang_stmt *ys, return retval; } -/*! Sanity check yang type statement +/*! Sanity check yang identity statement recursively + * + * Find base identities if any and add this identity to derived list. + * Do this recursively + * @param[in] ys The yang identity to populate. + * @param[in] arg If set contains a derived identifier + * @see validate_identityref which in runtime validates actual valoues */ static int ys_populate_identity(yang_stmt *ys, void *arg) { int retval = -1; - yang_stmt *ybase; + yang_stmt *yc = NULL; + yang_stmt *ybaseid; + cg_var *cv; + char *derid; + char *baseid; + char *prefix = NULL; + cbuf *cb = NULL; + char *idref = (char*)arg; + char *p; - if ((ybase = yang_find((yang_node*)ys, Y_BASE, NULL)) == NULL) - return 0; - if ((yang_find_identity(ys, ybase->ys_argument)) == NULL){ - clicon_err(OE_YANG, 0, "Identity %s not found (base type of %s)", - ybase->ys_argument, ys->ys_argument); - goto done; + if (idref == NULL){ + /* Create derived identity through prefix:id if not recursively called*/ + derid = ys->ys_argument; /* derived id */ + if ((prefix = yarg_prefix(ys)) == NULL){ + if ((p = yang_find_myprefix(ys)) != NULL) + prefix = strdup(yang_find_myprefix(ys)); + } + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + if (prefix) + cprintf(cb, "%s:%s", prefix, derid); + else + cprintf(cb, "%s", derid); + idref = cbuf_get(cb); + } + /* Iterate through all base statements and check the base identity exists + * AND populate the base identity recursively + */ + while ((yc = yn_each((yang_node*)ys, yc)) != NULL) { + if (yc->ys_keyword != Y_BASE) + continue; + baseid = yc->ys_argument; + if (((ybaseid = yang_find_identity(ys, baseid))) == NULL){ + clicon_err(OE_YANG, 0, "No such identity: %s", baseid); + goto done; + } + // continue; /* root identity */ + /* Check if derived id is already in base identifier */ + if (cvec_find(ybaseid->ys_cvec, idref) != NULL) + continue; + /* Add derived id to ybaseid */ + if ((cv = cv_new(CGV_STRING)) == NULL){ + clicon_err(OE_UNIX, errno, "cv_new"); + goto done; + } + /* add prefix */ + cv_name_set(cv, idref); + cvec_append_var(ybaseid->ys_cvec, cv); + /* Transitive to the root */ + if (ys_populate_identity(ybaseid, idref) < 0) + goto done; } retval = 0; done: + if (prefix) + free(prefix); + if (cb) + cbuf_free(cb); return retval; } - /*! Populate with cligen-variables, default values, etc. Sanity checks on complete tree. * * We do this in 2nd pass after complete parsing to be sure to have a complete parse-tree diff --git a/lib/src/clixon_yang_type.c b/lib/src/clixon_yang_type.c index 1d7f57d4..f54af474 100644 --- a/lib/src/clixon_yang_type.c +++ b/lib/src/clixon_yang_type.c @@ -380,7 +380,7 @@ clicon_type2cv(char *origtype, (rmax && (i) > cv_##type##_get(rmax))) -/*! +/*! Validate CLIgen variable * @retval -1 Error (fatal), with errno set to indicate error * @retval 0 Validation not OK, malloced reason is returned. Free reason with free() * @retval 1 Validation OK @@ -764,9 +764,9 @@ ys_typedef_up(yang_stmt *ys) return (yang_stmt*)ys; } -/*! Return yang-stmt of identity +/*! Find identity yang-stmt This is a sanity check of base identity of identity-ref and for identity - statements. + statements when parsing. Return true if node is identityref and is derived from identity_name The derived-from() function returns true if the (first) node (in @@ -779,12 +779,17 @@ ys_typedef_up(yang_stmt *ys) identityref's base identity. 1. (base) identity must exist (be found). This is a sanity check of the specification and also necessary for identity statements. + (This is what is dine here) 2. Check if a given node has value derived from base identity. This is a run-time check necessary when validating eg netconf. + (This is validation) 3. Find all valid derived identities from a identityref base identity. - This is for cli generation. - Så vad är det denna function ska göra? Svar: 1 -*/ + (This is for cli generation) + * @param[in] ys Yang spec of id statement + * @param[in] identity Identity string -check if it exists + * @retval 0 OK + * @see validate_identityref for (2) above + */ yang_stmt * yang_find_identity(yang_stmt *ys, char *identity) diff --git a/test/lib.sh b/test/lib.sh index 061730f6..f82907a0 100755 --- a/test/lib.sh +++ b/test/lib.sh @@ -55,21 +55,28 @@ new2(){ >&2 echo -n "Test$testnr [$1]" } -# clixon tester. First arg is command and second is expected outcome +# clixon command tester. +# Arguments: +# - command, +# - expected command return value (0 if OK) +# - expected stdout outcome, +# - expected2 stdout outcome, expectfn(){ cmd=$1 - expect=$2 + retval=$2 + expect="$3" - if [ $# = 3 ]; then - expect2=$3 + if [ $# = 4 ]; then + expect2=$4 else expect2= fi ret=$($cmd) - -# if [ $? -ne 0 ]; then -# err "wrong args" -# fi + if [ $? -ne $retval ]; then + echo -e "\e[31m\nError in Test$testnr [$testname]:" + echo -e "\e[0m:" + exit -1 + fi # Match if both are empty string if [ -z "$ret" -a -z "$expect" ]; then return @@ -79,7 +86,6 @@ expectfn(){ fi # grep extended grep match=`echo $ret | grep -EZo "$expect"` - if [ -z "$match" ]; then err "$expect" "$ret" fi diff --git a/test/test_cli.sh b/test/test_cli.sh index ec71a707..ee524339 100755 --- a/test/test_cli.sh +++ b/test/test_cli.sh @@ -18,6 +18,7 @@ cat < $cfg $cfg /usr/local/share/$APPNAME/yang $APPNAME + /usr/local/lib/$APPNAME/backend /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/cli $APPNAME @@ -43,74 +44,73 @@ fi new "cli tests" new "cli configure top" -expectfn "$clixon_cli -1 -f $cfg set interfaces" "^$" +expectfn "$clixon_cli -1 -f $cfg set interfaces" 0 "^$" new "cli show configuration top (no presence)" -expectfn "$clixon_cli -1 -f $cfg show conf cli" "^$" +expectfn "$clixon_cli -1 -f $cfg show conf cli" 0 "^$" new "cli configure delete top" -expectfn "$clixon_cli -1 -f $cfg delete interfaces" "^$" +expectfn "$clixon_cli -1 -f $cfg delete interfaces" 0 "^$" new "cli show configuration delete top" -expectfn "$clixon_cli -1 -f $cfg show conf cli" "^$" +expectfn "$clixon_cli -1 -f $cfg show conf cli" 0 "^$" new "cli configure" -expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0" "^$" +expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0" 0 "^$" new "cli show configuration" -expectfn "$clixon_cli -1 -f $cfg show conf cli" "^interfaces interface eth/0/0 enabled true" +expectfn "$clixon_cli -1 -f $cfg show conf cli" 0 "^interfaces interface eth/0/0 enabled true" new "cli configure using encoded chars data <&" -expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description \"foo<&bar\"" "" +expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description \"foo<&bar\"" 0 "" new "cli configure using encoded chars name <&" -expectfn "$clixon_cli -1 -f $cfg set interfaces interface fddi&< type eth" "" +expectfn "$clixon_cli -1 -f $cfg set interfaces interface fddi&< type ianaift:ethernetCsmacd" 0 "" new "cli failed validate" -expectfn "$clixon_cli -1 -f $cfg -l o validate" "Missing mandatory variable" +expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "Missing mandatory variable" new "cli configure more" -expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 ipv4 address 1.2.3.4 prefix-length 24" "^$" -expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description mydesc" "^$" -expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 type bgp" "^$" +expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 ipv4 address 1.2.3.4 prefix-length 24" 0 "^$" +expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description mydesc" 0 "^$" +expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 type ex:eth" 0 "^$" new "cli show xpath description" -expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description" "mydesc" +expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description" 0 "mydesc" new "cli delete description" -expectfn "$clixon_cli -1 -f $cfg -l o delete interfaces interface eth/0/0 description mydesc" +expectfn "$clixon_cli -1 -f $cfg -l o delete interfaces interface eth/0/0 description mydesc" 0 "" new "cli show xpath no description" -expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description" "^$" +expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description" 0 "^$" new "cli copy interface" -expectfn "$clixon_cli -1 -f $cfg copy interface eth/0/0 to eth99" "^$" +expectfn "$clixon_cli -1 -f $cfg copy interface eth/0/0 to eth99" 0 "^$" new "cli success validate" -expectfn "$clixon_cli -1 -f $cfg -l o validate" "^$" +expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$" new "cli commit" -expectfn "$clixon_cli -1 -f $cfg -l o commit" "^$" +expectfn "$clixon_cli -1 -f $cfg -l o commit" 0 "^$" new "cli save" -expectfn "$clixon_cli -1 -f $cfg -l o save /tmp/foo" "^$" +expectfn "$clixon_cli -1 -f $cfg -l o save /tmp/foo" 0 "^$" new "cli delete all" -expectfn "$clixon_cli -1 -f $cfg -l o delete all" "^$" +expectfn "$clixon_cli -1 -f $cfg -l o delete all" 0 "^$" new "cli load" -expectfn "$clixon_cli -1 -f $cfg -l o load /tmp/foo" "^$" +expectfn "$clixon_cli -1 -f $cfg -l o load /tmp/foo" 0 "^$" new "cli check load" -expectfn "$clixon_cli -1 -f $cfg -l o show conf cli" "^interfaces interface name eth/0/0 type bgp -interfaces interface eth/0/0 ipv4 enabled true" +expectfn "$clixon_cli -1 -f $cfg -l o show conf cli" 0 "interfaces interface eth/0/0 ipv4 enabled true" new "cli debug" -expectfn "$clixon_cli -1 -f $cfg -l o debug level 1" "^$" +expectfn "$clixon_cli -1 -f $cfg -l o debug level 1" 0 "^$" # How to test this? -expectfn "$clixon_cli -1 -f $cfg -l o debug level 0" "^$" +expectfn "$clixon_cli -1 -f $cfg -l o debug level 0" 0 "^$" new "cli rpc" -expectfn "$clixon_cli -1 -f $cfg -l o rpc ipv4" "^" +expectfn "$clixon_cli -1 -f $cfg -l o rpc ipv4" 0 "ipv4" "2.3.4.5" new "Kill backend" # Check if still alive diff --git a/test/test_datastore.sh b/test/test_datastore.sh index b0714b4d..d9155b0e 100755 --- a/test/test_datastore.sh +++ b/test/test_datastore.sh @@ -57,99 +57,99 @@ run(){ conf="-d candidate -b $mydir -p ../datastore/$name/$name.so -y $dir -m ietf-ip" new "datastore $name init" - expectfn "$datastore $conf init" "" + expectfn "$datastore $conf init" 0 "" # Whole tree operations new "datastore $name put all replace" - expectfn "$datastore $conf put replace $db" "" + expectfn "$datastore $conf put replace $db" 0 "" new "datastore $name get" - expectfn "$datastore $conf get /" "^$db$" + expectfn "$datastore $conf get /" 0 "^$db$" new "datastore $name put all remove" - expectfn "$datastore $conf put remove " + expectfn "$datastore $conf put remove " 0 "" new "datastore $name get" - expectfn "$datastore $conf get /" "^$" + expectfn "$datastore $conf get /" 0 "^$" new "datastore $name put all merge" - expectfn "$datastore $conf put merge $db" "" + expectfn "$datastore $conf put merge $db" 0 "" new "datastore $name get" - expectfn "$datastore $conf get /" "^$db$" + expectfn "$datastore $conf get /" 0 "^$db$" new "datastore $name put all delete" - expectfn "$datastore $conf put remove " + expectfn "$datastore $conf put remove " 0 "" new "datastore $name get" - expectfn "$datastore $conf get /" "^$" + expectfn "$datastore $conf get /" 0 "^$" new "datastore $name put all create" - expectfn "$datastore $conf put create $db" "" + expectfn "$datastore $conf put create $db" 0 "" new "datastore $name get" - expectfn "$datastore $conf get /" "^$db$" + expectfn "$datastore $conf get /" 0 "^$db$" new "datastore $name put top create" - expectfn "$datastore $conf put create " "" # error + expectfn "$datastore $conf put create " 0 "" # error # Single key operations # leaf new "datastore $name put all delete" - expectfn "$datastore $conf delete" "" + expectfn "$datastore $conf delete" 0 "" new "datastore $name init" - expectfn "$datastore $conf init" "" + expectfn "$datastore $conf init" 0 "" new "datastore $name create leaf" - expectfn "$datastore $conf put create 13newentry" + expectfn "$datastore $conf put create 13newentry" 0 "" new "datastore $name create leaf" - expectfn "$datastore $conf put create 13newentry" + expectfn "$datastore $conf put create 13newentry" 0 "" new "datastore $name delete leaf" - expectfn "$datastore $conf put delete 13" + expectfn "$datastore $conf put delete 13" 0 "" new "datastore $name replace leaf" - expectfn "$datastore $conf put create 13newentry" + expectfn "$datastore $conf put create 13newentry" 0 "" new "datastore $name remove leaf" - expectfn "$datastore $conf put remove " + expectfn "$datastore $conf put remove " 0 "" new "datastore $name remove leaf" - expectfn "$datastore $conf put remove 13" + expectfn "$datastore $conf put remove 13" 0 "" new "datastore $name delete leaf" - expectfn "$datastore $conf put delete " + expectfn "$datastore $conf put delete " 0 "" new "datastore $name merge leaf" - expectfn "$datastore $conf put merge nalle" + expectfn "$datastore $conf put merge nalle" 0 "" new "datastore $name replace leaf" - expectfn "$datastore $conf put replace nalle" + expectfn "$datastore $conf put replace nalle" 0 "" new "datastore $name merge leaf" - expectfn "$datastore $conf put merge 13newentry" + expectfn "$datastore $conf put merge 13newentry" 0 "" new "datastore $name replace leaf" - expectfn "$datastore $conf put replace 13newentry" + expectfn "$datastore $conf put replace 13newentry" 0 "" new "datastore $name create leaf" - expectfn "$datastore $conf put create aaa" + expectfn "$datastore $conf put create aaa" 0 "" new "datastore $name create leaf" - expectfn "$datastore $conf put create 13newentry" + expectfn "$datastore $conf put create 13newentry" 0 "" new "datastore other db init" - expectfn "$datastore -d kalle -b $mydir -p ../datastore/$name/$name.so -y $dir -m ietf-ip init" + expectfn "$datastore -d kalle -b $mydir -p ../datastore/$name/$name.so -y $dir -m ietf-ip init" 0 "" new "datastore other db copy" - expectfn "$datastore $conf copy kalle" "" + expectfn "$datastore $conf copy kalle" 0 "" diff $mydir/kalle_db $mydir/candidate_db new "datastore lock" - expectfn "$datastore $conf lock 756" "" + expectfn "$datastore $conf lock 756" 0 "" #leaf-list diff --git a/test/test_identity.sh b/test/test_identity.sh new file mode 100755 index 00000000..b828fc1f --- /dev/null +++ b/test/test_identity.sh @@ -0,0 +1,188 @@ +#!/bin/bash +# Identity and identityref tests +APPNAME=example +# include err() and new() functions and creates $dir +. ./lib.sh + +cfg=$dir/conf_yang.xml +fyang=$dir/example-my-crypto.yang + +cat < $cfg + + $cfg + $dir + $fyang + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/backend + example_backend.so$ + /usr/local/lib/$APPNAME/netconf + /usr/local/lib/$APPNAME/restconf + /usr/local/lib/$APPNAME/cli + $APPNAME + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + 1 + /usr/local/var/$APPNAME + /usr/local/lib/xmldb/text.so + +EOF + +# Example from RFC7950 Sec 7.18 and 9.10 +# with two changes: the leaf statement is in the original module and +# a transitive dependent identifier (foo) +cat < $dir/example-crypto-base.yang + module example-crypto-base { + yang-version 1.1; + namespace "urn:example:crypto-base"; + prefix "crypto"; + + identity crypto-alg { + description + "Base identity from which all crypto algorithms + are derived."; + } + identity symmetric-key { + description + "Base identity used to identify symmetric-key crypto + algorithms."; + } + identity public-key { + description + "Base identity used to identify public-key crypto + algorithms."; + } + } + +EOF + +cat < $dir/example-des.yang + module example-des { + yang-version 1.1; + namespace "urn:example:des"; + prefix "des"; + import "example-crypto-base" { + prefix "crypto"; + } + identity des { + base "crypto:crypto-alg"; + base "crypto:symmetric-key"; + description "DES crypto algorithm."; + } + identity des3 { + base "crypto:crypto-alg"; + base "crypto:symmetric-key"; + description "Triple DES crypto algorithm."; + } + } +EOF + +cat < $fyang + module example { + yang-version 1.1; + namespace "urn:example:my-crypto"; + prefix mc; + import "example-crypto-base" { + prefix "crypto"; + } + import "example-des" { + prefix "des"; + } + identity aes { + base "crypto:crypto-alg"; + } + identity foo { + description "transitive dependent identifier"; + base "des:des"; + } + leaf crypto { + description "Value can be any transitively derived from crypto-alg"; + type identityref { + base "crypto:crypto-alg"; + } + } + container aes-parameters { + when "../crypto = 'mc:aes'"; + } + } +EOF + +# kill old backend (if any) +new "kill old backend" +sudo clixon_backend -zf $cfg +if [ $? -ne 0 ]; then + err +fi +new "start backend -s init -f $cfg -y $fyang" +# start new backend +sudo clixon_backend -s init -f $cfg -y $fyang # -D 1 +if [ $? -ne 0 ]; then + err +fi + +new "Set crypto to aes" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "aes]]>]]>" "^]]>]]>$" + +new "netconf validate " +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" + +new "Set crypto to mc:aes" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "mc:aes]]>]]>" "^]]>]]>$" + +new "netconf validate" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" + +new "Set crypto to des:des3" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "des:des3]]>]]>" "^]]>]]>$" + +new "netconf validate" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" + +new "Set crypto to mc:foo" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "mc:foo]]>]]>" "^]]>]]>$" + +new "netconf validate" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" + +#new "Set crypto to x:des3" +#expecteof "$clixon_netconf -qf $cfg -y $fyang" "x:des3]]>]]>" "^]]>]]>$" + +new "netconf validate" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" + +new "Set crypto to foo:bar" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "foo:bar]]>]]>" "^]]>]]>$" + +new "netconf validate" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^operation-failedapplicationerrorIdentityref validation failed, foo:bar not derived from crypto-alg]]>]]>$" + +new "cli set crypto to mc:aes" +expectfn "$clixon_cli -1 -f $cfg -l o set crypto mc:aes" 0 "^$" + +new "cli validate" +expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$" + +new "cli set crypto to aes" +expectfn "$clixon_cli -1 -f $cfg -l o set crypto aes" 0 "^$" + +new "cli validate" +expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$" + +new "cli set crypto to des:des3" +expectfn "$clixon_cli -1 -f $cfg -l o set crypto des:des3" 0 "^$" + +new "cli validate" +expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$" + +new "Kill backend" +# Check if still alive +pid=`pgrep clixon_backend` +if [ -z "$pid" ]; then + err "backend already dead" +fi +# kill backend +sudo clixon_backend -zf $cfg +if [ $? -ne 0 ]; then + err "kill backend" +fi + +rm -rf $dir diff --git a/test/test_leafref.sh b/test/test_leafref.sh index 1b7c2990..f18263d4 100755 --- a/test/test_leafref.sh +++ b/test/test_leafref.sh @@ -24,9 +24,19 @@ EOF cat < $fyang module example{ + prefix ex; + import ietf-interfaces { + prefix if; + } import ietf-ip { prefix ip; } + identity eth { + base if:interface-type; + } + identity lo { + base if:interface-type; + } container default-address { leaf absname { type leafref { @@ -75,8 +85,8 @@ fi new "leafref base config" expecteof "$clixon_netconf -qf $cfg -y $fyang" " -eth0 eth
192.0.2.1
192.0.2.2
-lolo
127.0.0.1
+eth0ex:eth
192.0.2.1
192.0.2.2
+loex:lo
127.0.0.1
]]>]]>" "^]]>]]>$" new "leafref get config" @@ -115,16 +125,16 @@ new "leafref discard-changes" expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" new "cli leafref lo" -expectfn "$clixon_cli -1f $cfg -y $fyang -l o set default-address absname lo" "^$" +expectfn "$clixon_cli -1f $cfg -y $fyang -l o set default-address absname lo" 0 "^$" new "cli leafref validate" -expectfn "$clixon_cli -1f $cfg -y $fyang -l o validate" "^$" +expectfn "$clixon_cli -1f $cfg -y $fyang -l o validate" 0 "^$" new "cli sender" -expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender a" "^$" +expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender a" 0 "^$" new "cli sender template" -expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender b template a" "^$" +expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender b template a" 0 "^$" new "Kill backend" # Check if still alive diff --git a/test/test_netconf.sh b/test/test_netconf.sh index b6fc58ac..800dcdcb 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -30,6 +30,9 @@ EOF cat < $fyang module example{ prefix ex; + import ietf-interfaces { + prefix if; + } import ietf-ip { prefix ip; } @@ -42,6 +45,9 @@ module example{ } rpc empty { } + identity eth { + base if:interface-type; + } rpc client-rpc { description "Example local client-side RPC that is processed by the the netconf/restconf and not sent to the backend. @@ -84,22 +90,22 @@ new "Check nothing added" expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' '^]]>]]>$' new "Add subtree eth/0/0 using none and create which should add eth/0/0" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ethnone ]]>]]>' "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ex:ethnone ]]>]]>' "^]]>]]>$" new "Check eth/0/0 added using xpath" -expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' "^eth/0/0ethtrue]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' "^eth/0/0ex:ethtrue]]>]]>$" new "Re-create same eth/0/0 which should generate error" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ethnone ]]>]]>' "^" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ex:ethnone ]]>]]>' "^" new "Delete eth/0/0 using none config" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ethnone ]]>]]>' "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ex:ethnone ]]>]]>' "^]]>]]>$" new "Check deleted eth/0/0 (non-presence container)" expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' '^]]>]]>$' new "Re-Delete eth/0/0 using none should generate error" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ethnone ]]>]]>' "^" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ex:ethnone ]]>]]>' "^" new "netconf edit config" expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth/0/0eth1true
9.2.3.424
]]>]]>" "^]]>]]>$" @@ -126,7 +132,7 @@ new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf edit config eth1" -expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth1eth]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth1ex:eth]]>]]>" "^]]>]]>$" new "netconf validate" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" @@ -135,26 +141,26 @@ new "netconf commit" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf edit config merge" -expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth2ethmerge]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth2ex:ethmerge]]>]]>" "^]]>]]>$" new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'" expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth& t< > ]]>]]>" "^]]>]]>$" new "netconf get replaced config" -expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth& t< > trueeth1ethtrueeth2ethtrue]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth& t< > trueeth1ex:ethtrueeth2ex:ethtrue]]>]]>$" new "cli show configuration eth& - encoding tests" -expectfn "$clixon_cli -1 -f $cfg -y $fyang show conf cli" "interfaces interface eth& type t<> +expectfn "$clixon_cli -1 -f $cfg -y $fyang show conf cli" 0 "interfaces interface eth& type t<> interfaces interface eth& enabled true" new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf edit state operation should fail" -expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth1eth]]>]]>" "^invalid-value" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth1ex:eth]]>]]>" "^invalid-value" new "netconf get state operation" -expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth0eth42]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth0ex:eth42]]>]]>$" new "netconf lock/unlock" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>]]>]]>" "^]]>]]>]]>]]>$" @@ -175,7 +181,7 @@ new "copy startup" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf get startup" -expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth1ethtrue]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth1ex:ethtrue]]>]]>$" new "netconf delete startup" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 344b521f..d1ff4ade 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -31,6 +31,9 @@ EOF cat < $fyang module example{ prefix ex; + import ietf-interfaces { + prefix if; + } import ietf-ip { prefix ip; } @@ -41,6 +44,9 @@ module example{ prefix "inet"; revision-date "2013-07-15"; } + identity eth { + base if:interface-type; + } rpc empty { } rpc input { @@ -68,7 +74,7 @@ module example{ EOF # This is a fixed 'state' implemented in routing_backend. It is assumed to be always there -state='{"interfaces-state": {"interface": \[{"name": "eth0","type": "eth","if-index": 42}\]}}' +state='{"interfaces-state": {"interface": \[{"name": "eth0","type": "ex:eth","if-index": 42}\]}}' # kill old backend (if any) new "kill old backend" @@ -130,113 +136,113 @@ if [ -z "$match" ]; then fi new "restconf options. RFC 8040 4.1" -expectfn "curl -i -s -X OPTIONS http://localhost/restconf/data" "Allow: OPTIONS,HEAD,GET,POST,PUT,DELETE" +expectfn "curl -i -s -X OPTIONS http://localhost/restconf/data" 0 "Allow: OPTIONS,HEAD,GET,POST,PUT,DELETE" new "restconf head. RFC 8040 4.2" -expectfn "curl -s -I http://localhost/restconf/data" "HTTP/1.1 200 OK" +expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK" #Content-Type: application/yang-data+json" new2 "restconf empty rpc" expecteq "$(curl -s -X POST -d {\"input\":{\"name\":\"\"}} http://localhost/restconf/operations/ex:empty)" "" new2 "restconf get empty config + state json" -expecteq "$(curl -sSG http://localhost/restconf/data)" '{"data": {"interfaces-state": {"interface": [{"name": "eth0","type": "eth","if-index": 42}]}}} +expecteq "$(curl -sSG http://localhost/restconf/data)" '{"data": {"interfaces-state": {"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]}}} ' new "restconf get empty config + state xml" ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data) -expect="eth0eth42" +expect="eth0ex:eth42" match=`echo $ret | grep -EZo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new2 "restconf get data/interfaces-state/interface=eth0 json" -expecteq "$(curl -s -G http://localhost/restconf/data/interfaces-state/interface=eth0)" '{"interface": [{"name": "eth0","type": "eth","if-index": 42}]} +expecteq "$(curl -s -G http://localhost/restconf/data/interfaces-state/interface=eth0)" '{"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]} ' new "restconf get state operation eth0 xml" # Cant get shell macros to work, inline matching from lib.sh ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/interfaces-state/interface=eth0) -expect="eth0eth42" +expect="eth0ex:eth42" match=`echo $ret | grep -EZo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new2 "restconf get state operation eth0 type json" -expecteq "$(curl -s -G http://localhost/restconf/data/interfaces-state/interface=eth0/type)" '{"type": "eth"} +expecteq "$(curl -s -G http://localhost/restconf/data/interfaces-state/interface=eth0/type)" '{"type": "ex:eth"} ' new "restconf get state operation eth0 type xml" # Cant get shell macros to work, inline matching from lib.sh ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/interfaces-state/interface=eth0/type) -expect="eth" +expect="ex:eth" match=`echo $ret | grep -EZo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new2 "restconf GET datastore" -expecteq "$(curl -s -X GET http://localhost/restconf/data)" '{"data": {"interfaces-state": {"interface": [{"name": "eth0","type": "eth","if-index": 42}]}}} +expecteq "$(curl -s -X GET http://localhost/restconf/data)" '{"data": {"interfaces-state": {"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]}}} ' # Exact match new "restconf Add subtree to datastore using POST" -expectfn 'curl -s -i -X POST -H "Accept: application/yang-data+json" -d {"interfaces":{"interface":{"name":"eth/0/0","type":"eth","enabled":true}}} http://localhost/restconf/data' 'HTTP/1.1 200 OK' +expectfn 'curl -s -i -X POST -H "Accept: application/yang-data+json" -d {"interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 'HTTP/1.1 200 OK' new "restconf Re-add subtree which should give error" -expectfn 'curl -s -X POST -d {"interfaces":{"interface":{"name":"eth/0/0","type":"eth","enabled":true}}} http://localhost/restconf/data' '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}' +expectfn 'curl -s -X POST -d {"interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}' # XXX Cant get this to work -#expecteq "$(curl -s -X POST -d {\"interfaces\":{\"interface\":{\"name\":\"eth/0/0\",\"type\":\"eth\",\"enabled\":true}}} http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}' +#expecteq "$(curl -s -X POST -d {\"interfaces\":{\"interface\":{\"name\":\"eth/0/0\",\"type\":\"ex:eth\",\"enabled\":true}}} http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}' new "restconf Check interfaces eth/0/0 added" -expectfn "curl -s -G http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth/0/0","type": "eth","enabled": true}\]},"interfaces-state": {"interface": \[{"name": "eth0","type": "eth","if-index": 42}\]}} +expectfn "curl -s -G http://localhost/restconf/data" 0 '{"interfaces": {"interface": \[{"name": "eth/0/0","type": "ex:eth","enabled": true}\]},"interfaces-state": {"interface": \[{"name": "eth0","type": "ex:eth","if-index": 42}\]}} ' new2 "restconf delete interfaces" expecteq $(curl -s -X DELETE http://localhost/restconf/data/interfaces) "" new "restconf Check empty config" -expectfn "curl -sG http://localhost/restconf/data" "$state" +expectfn "curl -sG http://localhost/restconf/data" 0 "$state" new "restconf Add interfaces subtree eth/0/0 using POST" -expectfn 'curl -s -X POST -d {"interface":{"name":"eth/0/0","type":"eth","enabled":true}} http://localhost/restconf/data/interfaces' "" +expectfn 'curl -s -X POST -d {"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}} http://localhost/restconf/data/interfaces' 0 "" # XXX cant get this to work -#expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type\":"eth","enabled":true}}' http://localhost/restconf/data/interfaces)" "" +#expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type\":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces)" "" new2 "restconf Check eth/0/0 added" -expecteq "$(curl -s -G http://localhost/restconf/data)" '{"data": {"interfaces": {"interface": [{"name": "eth/0/0","type": "eth","enabled": true}]},"interfaces-state": {"interface": [{"name": "eth0","type": "eth","if-index": 42}]}}} +expecteq "$(curl -s -G http://localhost/restconf/data)" '{"data": {"interfaces": {"interface": [{"name": "eth/0/0","type": "ex:eth","enabled": true}]},"interfaces-state": {"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]}}} ' new2 "restconf Re-post eth/0/0 which should generate error" -expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type":"eth","enabled":true}}' http://localhost/restconf/data/interfaces)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}} ' +expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}} ' new "Add leaf description using POST" expecteq "$(curl -s -X POST -d '{"description":"The-first-interface"}' http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" "" new "Add nothing using POST" -expectfn 'curl -s -X POST http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0' '"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "malformed-message","error-type": "rpc","error-severity": "error","error-message": " on line 1: syntax error at or before:' +expectfn 'curl -s -X POST http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0' 0 '"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "malformed-message","error-type": "rpc","error-severity": "error","error-message": " on line 1: syntax error at or before:' new2 "restconf Check description added" -expecteq "$(curl -s -G http://localhost/restconf/data)" '{"data": {"interfaces": {"interface": [{"name": "eth/0/0","description": "The-first-interface","type": "eth","enabled": true}]},"interfaces-state": {"interface": [{"name": "eth0","type": "eth","if-index": 42}]}}} +expecteq "$(curl -s -G http://localhost/restconf/data)" '{"data": {"interfaces": {"interface": [{"name": "eth/0/0","description": "The-first-interface","type": "ex:eth","enabled": true}]},"interfaces-state": {"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]}}} ' new "restconf delete eth/0/0" expecteq "$(curl -s -X DELETE http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" "" new "Check deleted eth/0/0" -expectfn 'curl -s -G http://localhost/restconf/data' $state +expectfn 'curl -s -G http://localhost/restconf/data' 0 $state new2 "restconf Re-Delete eth/0/0 using none should generate error" expecteq "$(curl -s -X DELETE http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-missing","error-type": "application","error-severity": "error","error-message": "Data does not exist; cannot delete resource"}}} ' new "restconf Add subtree eth/0/0 using PUT" -expecteq "$(curl -s -X PUT -d '{"interface":{"name":"eth/0/0","type":"eth","enabled":true}}' http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" "" +expecteq "$(curl -s -X PUT -d '{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" "" new2 "restconf get subtree" -expecteq "$(curl -s -G http://localhost/restconf/data)" '{"data": {"interfaces": {"interface": [{"name": "eth/0/0","type": "eth","enabled": true}]},"interfaces-state": {"interface": [{"name": "eth0","type": "eth","if-index": 42}]}}} +expecteq "$(curl -s -G http://localhost/restconf/data)" '{"data": {"interfaces": {"interface": [{"name": "eth/0/0","type": "ex:eth","enabled": true}]},"interfaces-state": {"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]}}} ' new2 "restconf rpc using POST json" diff --git a/test/test_restconf2.sh b/test/test_restconf2.sh index df401e24..26cf56d7 100755 --- a/test/test_restconf2.sh +++ b/test/test_restconf2.sh @@ -66,22 +66,22 @@ sleep 1 new "restconf tests" new "restconf POST initial tree" -expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' "" +expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 "" new "restconf GET datastore" -expectfn "curl -s -X GET http://localhost/restconf/data" '{"data": {"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}}' +expectfn "curl -s -X GET http://localhost/restconf/data" 0 '{"data": {"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}}' new "restconf GET interface" -expectfn "curl -s -X GET http://localhost/restconf/data/cont1/interface=local0" '{"interface": \[{"name": "local0","type": "regular"}\]}' +expectfn "curl -s -X GET http://localhost/restconf/data/cont1/interface=local0" 0 '{"interface": \[{"name": "local0","type": "regular"}\]}' new "restconf GET if-type" -expectfn "curl -s -X GET http://localhost/restconf/data/cont1/interface=local0/type" '{"type": "regular"}' +expectfn "curl -s -X GET http://localhost/restconf/data/cont1/interface=local0/type" 0 '{"type": "regular"}' new "restconf POST interface without mandatory type" -expectfn 'curl -s -X POST -d {"interface":{"name":"TEST"}} http://localhost/restconf/data/cont1' '"error-message": "Missing mandatory variable: type"' +expectfn 'curl -s -X POST -d {"interface":{"name":"TEST"}} http://localhost/restconf/data/cont1' 0 '"error-message": "Missing mandatory variable: type"' new "restconf POST interface" -expectfn 'curl -s -X POST -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/cont1' "" +expectfn 'curl -s -X POST -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/cont1' 0 "" new2 "restconf POST again" expecteq "$(curl -s -X POST -d '{"interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/cont1)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}} ' @@ -90,51 +90,50 @@ new2 "restconf POST from top" expecteq "$(curl -s -X POST -d '{"cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}} ' new "restconf DELETE" -expectfn 'curl -s -X DELETE http://localhost/restconf/data/cont1' "" +expectfn 'curl -s -X DELETE http://localhost/restconf/data/cont1' 0 "" new "restconf GET null datastore" -expectfn "curl -s -X GET http://localhost/restconf/data" '{"data": null}' +expectfn "curl -s -X GET http://localhost/restconf/data" 0 '{"data": null}' new "restconf POST initial tree" -expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' "" +expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 "" new "restconf GET initial tree" -expectfn "curl -s -X GET http://localhost/restconf/data" '{"data": {"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}}' +expectfn "curl -s -X GET http://localhost/restconf/data" 0 '{"data": {"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}}' new "restconf DELETE whole datastore" -expectfn 'curl -s -X DELETE http://localhost/restconf/data' "" +expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 "" new "restconf GET null datastore" -expectfn "curl -s -X GET http://localhost/restconf/data" '{"data": null}' +expectfn "curl -s -X GET http://localhost/restconf/data" 0 '{"data": null}' new "restconf PUT initial datastore" -expectfn 'curl -s -X PUT -d {"data":{"cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' "" +expectfn 'curl -s -X PUT -d {"data":{"cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 "" new "restconf GET datastore" -expectfn "curl -s -X GET http://localhost/restconf/data" '{"data": {"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}}' +expectfn "curl -s -X GET http://localhost/restconf/data" 0 '{"data": {"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}}' new "restconf PUT replace datastore" -expectfn 'curl -s -X PUT -d {"data":{"cont2":{"name":"foo"}}} http://localhost/restconf/data' "" +expectfn 'curl -s -X PUT -d {"data":{"cont2":{"name":"foo"}}} http://localhost/restconf/data' 0 "" new "restconf GET replaced datastore" -expectfn "curl -s -X GET http://localhost/restconf/data" '{"data": {"cont2": {"name": "foo"}}}' - +expectfn "curl -s -X GET http://localhost/restconf/data" 0 '{"data": {"cont2": {"name": "foo"}}}' new "restconf PUT initial datastore again" -expectfn 'curl -s -X PUT -d {"data":{"cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' "" +expectfn 'curl -s -X PUT -d {"data":{"cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 "" new "restconf PUT change interface" -expectfn 'curl -s -X PUT -d {"interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/cont1/interface=local0' "" +expectfn 'curl -s -X PUT -d {"interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/cont1/interface=local0' 0 "" new "restconf GET datastore atm" -expectfn "curl -s -X GET http://localhost/restconf/data" '{"data": {"cont1": {"interface": \[{"name": "local0","type": "atm0"}\]}}}' +expectfn "curl -s -X GET http://localhost/restconf/data" 0 '{"data": {"cont1": {"interface": \[{"name": "local0","type": "atm0"}\]}}}' new "restconf PUT add interface" -expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/cont1/interface=TEST' "" +expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/cont1/interface=TEST' 0 "" new "restconf PUT change key error" -expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/cont1/interface=TEST' '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "api-path keys do not match data keys"}}}}' +expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "api-path keys do not match data keys"}}}}' new "Kill restconf daemon" sudo pkill -u www-data clixon_restconf diff --git a/test/test_startup.sh b/test/test_startup.sh index d7b5d6a8..7c3208f0 100755 --- a/test/test_startup.sh +++ b/test/test_startup.sh @@ -43,7 +43,7 @@ run(){ run - eth + ex:eth
@@ -55,7 +55,7 @@ EOF startup - eth + ex:eth
@@ -67,7 +67,7 @@ EOF extra - eth + ex:eth
@@ -103,8 +103,8 @@ EOF } run init '' -run none 'runethtrue' -run running 'extraethtruelolocaltruerunethtrue' -run startup 'extraethtruelolocaltruestartupethtrue' +run none 'runex:ethtrue' +run running 'extraex:ethtrueloex:loopbacktruerunex:ethtrue' +run startup 'extraex:ethtrueloex:loopbacktruestartupex:ethtrue' rm -rf $dir diff --git a/test/test_type.sh b/test/test_type.sh index 7788ee02..cae1227a 100755 --- a/test/test_type.sh +++ b/test/test_type.sh @@ -139,25 +139,25 @@ if [ $? -ne 0 ]; then fi new "cli set ab" -expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.a.b" "^$" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.a.b" 0 "^$" new "cli set cd" -expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list c.d.c.d" "^$" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list c.d.c.d" 0 "^$" new "cli set ef" -expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list e.f.e.f" "^$" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list e.f.e.f" 0 "^$" new "cli set ab fail" -expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a&b&a&b" "^CLI syntax error" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a&b&a&b" 255 "^CLI syntax error" new "cli set ad fail" -expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.c.d" "^CLI syntax error" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.c.d" 255 "^CLI syntax error" new "cli validate" -expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o validate" "^$" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o validate" 0 "^$" new "cli commit" -expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o commit" "^$" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o commit" 0 "^$" new "netconf validate ok" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" @@ -175,7 +175,7 @@ new "netconf commit" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "cli enum value" -expectfn "$clixon_cli -1f $cfg -l o -y $fyang set status down" "^$" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set status down" 0 "^$" new "Kill backend" # Check if still alive diff --git a/test/test_yang.sh b/test/test_yang.sh index 52d4a70f..86c56b3b 100755 --- a/test/test_yang.sh +++ b/test/test_yang.sh @@ -111,11 +111,11 @@ if [ $? -ne 0 ]; then fi new "cli defined extension" -expectfn "$clixon_cli -1f $cfg -y $fyang show version" "3." +expectfn "$clixon_cli -1f $cfg -y $fyang show version" 0 "3." new "cli not defined extension" # This text yields an error, but the test cannot detect the error message yet -#expectfn "$clixon_cli -1f $cfg -y $fyangerr show version" "Yang error: Extension ex:not-defined not found" +#expectfn "$clixon_cli -1f $cfg -y $fyangerr show version" 0 "Yang error: Extension ex:not-defined not found" new "netconf edit config" expecteof "$clixon_netconf -qf $cfg -y $fyang" "125one]]>]]>" "^]]>]]>$" @@ -143,10 +143,10 @@ new "netconf get (should be some)" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^125one]]>]]>$" new "cli set leaf-list" -expectfn "$clixon_cli -1f $cfg -y $fyang set x f e foo" "" +expectfn "$clixon_cli -1f $cfg -y $fyang set x f e foo" 0 "" new "cli show leaf-list" -expectfn "$clixon_cli -1f $cfg -y $fyang show xpath /x/f/e" "foo" +expectfn "$clixon_cli -1f $cfg -y $fyang show xpath /x/f/e" 0 "foo" new "netconf set state data (not allowed)" expecteof "$clixon_netconf -qf $cfg -y $fyang" "42]]>]]>" "^invalid-value"