tests for restconf backend configure
rm client-cert-ca
This commit is contained in:
parent
c31b1c471b
commit
6ecb0d5232
11 changed files with 368 additions and 515 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -53,8 +53,12 @@ build-root/rpmbuild
|
||||||
util/clixon_util_datastore
|
util/clixon_util_datastore
|
||||||
util/clixon_util_insert
|
util/clixon_util_insert
|
||||||
util/clixon_util_json
|
util/clixon_util_json
|
||||||
|
util/clixon_util_path
|
||||||
|
util/clixon_util_regexp
|
||||||
|
util/clixon_util_socket
|
||||||
util/clixon_util_stream
|
util/clixon_util_stream
|
||||||
util/clixon_util_xml
|
util/clixon_util_xml
|
||||||
|
util/clixon_util_xml_mod
|
||||||
util/clixon_util_xpath
|
util/clixon_util_xpath
|
||||||
util/clixon_util_yang
|
util/clixon_util_yang
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -772,6 +772,7 @@ cx_evhtp_socket(clicon_handle h,
|
||||||
* @param[in] xconfig XML config
|
* @param[in] xconfig XML config
|
||||||
* @param[in] nsc Namespace context
|
* @param[in] nsc Namespace context
|
||||||
* @param[in] eh Evhtp handle
|
* @param[in] eh Evhtp handle
|
||||||
|
* @note only if CLICON_RESTCONF_CONFIG is true (-b)
|
||||||
* @note only one socket allowed in this implementation
|
* @note only one socket allowed in this implementation
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -782,7 +783,7 @@ cx_evhtp_init(clicon_handle h,
|
||||||
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int auth_type_client_certifificate = 0;
|
int auth_type_client_certificate = 0;
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
cxobj *xrestconf;
|
cxobj *xrestconf;
|
||||||
cxobj **vec = NULL;
|
cxobj **vec = NULL;
|
||||||
|
|
@ -806,15 +807,13 @@ cx_evhtp_init(clicon_handle h,
|
||||||
if ((x = xpath_first(xrestconf, nsc, "auth-type")) != NULL) /* XXX: leaf-list? */
|
if ((x = xpath_first(xrestconf, nsc, "auth-type")) != NULL) /* XXX: leaf-list? */
|
||||||
auth_type = xml_body(x);
|
auth_type = xml_body(x);
|
||||||
if (auth_type && strcmp(auth_type, "client-certificate") == 0)
|
if (auth_type && strcmp(auth_type, "client-certificate") == 0)
|
||||||
auth_type_client_certifificate = 1;
|
auth_type_client_certificate = 1;
|
||||||
if ((x = xpath_first(xrestconf, nsc, "server-cert-path")) != NULL)
|
if ((x = xpath_first(xrestconf, nsc, "server-cert-path")) != NULL)
|
||||||
server_cert_path = xml_body(x);
|
server_cert_path = xml_body(x);
|
||||||
if ((x = xpath_first(xrestconf, nsc, "server-key-path")) != NULL)
|
if ((x = xpath_first(xrestconf, nsc, "server-key-path")) != NULL)
|
||||||
server_key_path = xml_body(x);
|
server_key_path = xml_body(x);
|
||||||
if ((x = xpath_first(xrestconf, nsc, "server-ca-cert-path")) != NULL)
|
if ((x = xpath_first(xrestconf, nsc, "server-ca-cert-path")) != NULL)
|
||||||
server_ca_cert_path = xml_body(x);
|
server_ca_cert_path = xml_body(x);
|
||||||
// XXX if ((x = xpath_first(xrestconf, nsc, "client-cert-ca")) != NULL)
|
|
||||||
// XXX client_cert_ca = xml_body(x);
|
|
||||||
/* get the list of socket config-data */
|
/* get the list of socket config-data */
|
||||||
if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0)
|
if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -830,7 +829,7 @@ cx_evhtp_init(clicon_handle h,
|
||||||
clicon_err(OE_XML, EINVAL, "Enabled SSL server requires server_cert_path and server_key_path");
|
clicon_err(OE_XML, EINVAL, "Enabled SSL server requires server_cert_path and server_key_path");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (auth_type_client_certifificate){
|
if (auth_type_client_certificate){
|
||||||
if (!use_ssl_server){
|
if (!use_ssl_server){
|
||||||
clicon_err(OE_XML, EINVAL, "Client certificate authentication type requires SSL");
|
clicon_err(OE_XML, EINVAL, "Client certificate authentication type requires SSL");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -863,11 +862,11 @@ cx_evhtp_init(clicon_handle h,
|
||||||
server_key_path,
|
server_key_path,
|
||||||
eh->eh_ssl_config) < 0)
|
eh->eh_ssl_config) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (auth_type_client_certifificate)
|
if (auth_type_client_certificate)
|
||||||
if (cx_get_ssl_client_certs(h, server_ca_cert_path, eh->eh_ssl_config) < 0)
|
if (cx_get_ssl_client_certs(h, server_ca_cert_path, eh->eh_ssl_config) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
eh->eh_ssl_config->x509_verify_cb = cx_verify_certs; /* Is extra verification necessary? */
|
eh->eh_ssl_config->x509_verify_cb = cx_verify_certs; /* Is extra verification necessary? */
|
||||||
if (auth_type_client_certifificate){
|
if (auth_type_client_certificate){
|
||||||
eh->eh_ssl_config->verify_peer = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
eh->eh_ssl_config->verify_peer = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
||||||
eh->eh_ssl_config->x509_verify_cb = cx_verify_certs;
|
eh->eh_ssl_config->x509_verify_cb = cx_verify_certs;
|
||||||
eh->eh_ssl_config->verify_depth = 2;
|
eh->eh_ssl_config->verify_depth = 2;
|
||||||
|
|
@ -949,120 +948,6 @@ restconf_config_backend(clicon_handle h,
|
||||||
uint32_t id = 0; /* Session id, to poll backend up */
|
uint32_t id = 0; /* Session id, to poll backend up */
|
||||||
cx_evhtp_handle *eh = NULL;
|
cx_evhtp_handle *eh = NULL;
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* In the startup, logs to stderr & debug flag set later */
|
|
||||||
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
|
|
||||||
|
|
||||||
/* Create handle */
|
|
||||||
if ((h = restconf_handle_init()) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
_CLICON_HANDLE = h; /* for termination handling */
|
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, RESTCONF_OPTS)) != -1)
|
|
||||||
switch (c) {
|
|
||||||
case 'h':
|
|
||||||
usage(h, argv0);
|
|
||||||
break;
|
|
||||||
case 'D' : /* debug */
|
|
||||||
if (sscanf(optarg, "%d", &dbg) != 1)
|
|
||||||
usage(h, argv0);
|
|
||||||
break;
|
|
||||||
case 'f': /* override config file */
|
|
||||||
if (!strlen(optarg))
|
|
||||||
usage(h, argv0);
|
|
||||||
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
|
|
||||||
break;
|
|
||||||
case 'E': /* extra config directory */
|
|
||||||
if (!strlen(optarg))
|
|
||||||
usage(h, argv[0]);
|
|
||||||
clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg);
|
|
||||||
break;
|
|
||||||
case 'l': /* Log destination: s|e|o */
|
|
||||||
if ((logdst = clicon_log_opt(optarg[0])) < 0)
|
|
||||||
usage(h, argv0);
|
|
||||||
if (logdst == CLICON_LOG_FILE &&
|
|
||||||
strlen(optarg)>1 &&
|
|
||||||
clicon_log_file(optarg+1) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
} /* switch getopt */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Logs, error and debug to stderr or syslog, set debug level
|
|
||||||
*/
|
|
||||||
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
|
|
||||||
|
|
||||||
clicon_debug_init(dbg, NULL);
|
|
||||||
clicon_log(LOG_NOTICE, "%s: %u Started", __PROGRAM__, getpid());
|
|
||||||
if (set_signal(SIGTERM, restconf_sig_term, NULL) < 0){
|
|
||||||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (set_signal(SIGINT, restconf_sig_term, NULL) < 0){
|
|
||||||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (set_signal(SIGCHLD, restconf_sig_child, NULL) < 0){
|
|
||||||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find and read configfile */
|
|
||||||
if (clicon_options_main(h) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* Now rest of options, some overwrite option file */
|
|
||||||
optind = 1;
|
|
||||||
opterr = 0;
|
|
||||||
while ((c = getopt(argc, argv, RESTCONF_OPTS)) != -1)
|
|
||||||
switch (c) {
|
|
||||||
case 'h' : /* help */
|
|
||||||
case 'D' : /* debug */
|
|
||||||
case 'f': /* config file */
|
|
||||||
case 'E': /* extra config dir */
|
|
||||||
case 'l': /* log */
|
|
||||||
break; /* see above */
|
|
||||||
case 'p' : /* yang dir path */
|
|
||||||
if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
case 'd': /* Plugin directory */
|
|
||||||
if (!strlen(optarg))
|
|
||||||
usage(h, argv0);
|
|
||||||
clicon_option_str_set(h, "CLICON_RESTCONF_DIR", optarg);
|
|
||||||
break;
|
|
||||||
case 'y' : /* Load yang spec file (override yang main module) */
|
|
||||||
clicon_option_str_set(h, "CLICON_YANG_MAIN_FILE", optarg);
|
|
||||||
break;
|
|
||||||
case 'a': /* internal backend socket address family */
|
|
||||||
clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg);
|
|
||||||
break;
|
|
||||||
case 'u': /* internal backend socket unix domain path or ip host */
|
|
||||||
if (!strlen(optarg))
|
|
||||||
usage(h, argv0);
|
|
||||||
clicon_option_str_set(h, "CLICON_SOCK", optarg);
|
|
||||||
break;
|
|
||||||
case 'r':{ /* Do not drop privileges if run as root */
|
|
||||||
drop_privileges = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'o':{ /* Configuration option */
|
|
||||||
char *val;
|
|
||||||
if ((val = index(optarg, '=')) == NULL)
|
|
||||||
usage(h, argv0);
|
|
||||||
*val++ = '\0';
|
|
||||||
if (clicon_option_add(h, optarg, val) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
usage(h, argv0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
argc -= optind;
|
|
||||||
argv += optind;
|
|
||||||
#endif
|
|
||||||
/* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */
|
/* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */
|
||||||
xml_nsctx_namespace_netconf_default(h);
|
xml_nsctx_namespace_netconf_default(h);
|
||||||
|
|
||||||
|
|
@ -1071,14 +956,6 @@ restconf_config_backend(clicon_handle h,
|
||||||
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */
|
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */
|
||||||
clicon_argv_set(h, argv0, argc, argv);
|
clicon_argv_set(h, argv0, argc, argv);
|
||||||
|
|
||||||
#if 0 /* Drop privileges after evhtp and server key/cert read */
|
|
||||||
if (drop_privileges){
|
|
||||||
/* Drop privileges to WWWUSER if started as root */
|
|
||||||
if (restconf_drop_privileges(h, WWWUSER) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Init cligen buffers */
|
/* Init cligen buffers */
|
||||||
cligen_buflen = clicon_option_int(h, "CLICON_CLI_BUF_START");
|
cligen_buflen = clicon_option_int(h, "CLICON_CLI_BUF_START");
|
||||||
cligen_bufthreshold = clicon_option_int(h, "CLICON_CLI_BUF_THRESHOLD");
|
cligen_bufthreshold = clicon_option_int(h, "CLICON_CLI_BUF_THRESHOLD");
|
||||||
|
|
@ -1159,12 +1036,14 @@ restconf_config_backend(clicon_handle h,
|
||||||
/* Query backend of config.
|
/* Query backend of config.
|
||||||
* Before evhtp, try again if not done */
|
* Before evhtp, try again if not done */
|
||||||
while (1){
|
while (1){
|
||||||
if (clicon_session_id_get(h, &id) < 0){
|
if (clicon_hello_req(h, &id) < 0){
|
||||||
if (errno == ENOENT){
|
if (errno == ENOENT){
|
||||||
fprintf(stderr, "waiting");
|
fprintf(stderr, "waiting");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// clicon_err(OE_UNIX, errno, "clicon_session_id_get");
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_session_id_set(h, id);
|
clicon_session_id_set(h, id);
|
||||||
break;
|
break;
|
||||||
|
|
@ -1198,9 +1077,6 @@ restconf_config_backend(clicon_handle h,
|
||||||
if (nsc)
|
if (nsc)
|
||||||
cvec_free(nsc);
|
cvec_free(nsc);
|
||||||
clicon_debug(1, "restconf_main_evhtp done");
|
clicon_debug(1, "restconf_main_evhtp done");
|
||||||
// stream_child_freeall(h);
|
|
||||||
evhtp_terminate(eh);
|
|
||||||
restconf_terminate(h);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1451,9 +1327,6 @@ restconf_config_local(clicon_handle h,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "restconf_main_evhtp done");
|
clicon_debug(1, "restconf_main_evhtp done");
|
||||||
// stream_child_freeall(h);
|
|
||||||
evhtp_terminate(eh);
|
|
||||||
restconf_terminate(h);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@
|
||||||
#include "restconf_stream.h"
|
#include "restconf_stream.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define RESTCONF_OPTS "hD:f:E:l:p:d:y:a:u:ro:"
|
#define RESTCONF_OPTS "hD:f:E:l:p:d:y:a:u:ro:b"
|
||||||
|
|
||||||
/*! Convert FCGI parameters to clixon runtime data
|
/*! Convert FCGI parameters to clixon runtime data
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
|
|
@ -180,6 +180,7 @@ usage(clicon_handle h,
|
||||||
"\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
|
"\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
|
||||||
"\t-u <path|addr>\t Internal socket domain path or IP addr (see -a)\n"
|
"\t-u <path|addr>\t Internal socket domain path or IP addr (see -a)\n"
|
||||||
"\t-r \t\t Do not drop privileges if run as root\n"
|
"\t-r \t\t Do not drop privileges if run as root\n"
|
||||||
|
"\t-b \t\t Read config from backend - no-op only applies to evhtp \n"
|
||||||
"\t-o \"<option>=<value>\" Give configuration option overriding config file (see clixon-config.yang)\n",
|
"\t-o \"<option>=<value>\" Give configuration option overriding config file (see clixon-config.yang)\n",
|
||||||
argv0,
|
argv0,
|
||||||
clicon_restconf_dir(h)
|
clicon_restconf_dir(h)
|
||||||
|
|
@ -289,6 +290,7 @@ main(int argc,
|
||||||
case 'f': /* config file */
|
case 'f': /* config file */
|
||||||
case 'E': /* extra config dir */
|
case 'E': /* extra config dir */
|
||||||
case 'l': /* log */
|
case 'l': /* log */
|
||||||
|
case 'b': /* backend config no-op for fcgi */
|
||||||
break; /* see above */
|
break; /* see above */
|
||||||
case 'p' : /* yang dir path */
|
case 'p' : /* yang dir path */
|
||||||
if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
|
if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
|
||||||
|
|
|
||||||
|
|
@ -1380,9 +1380,8 @@ netconf_module_load(clicon_handle h)
|
||||||
if (yang_spec_parse_module(h, "clixon-xml-changelog", NULL, yspec)< 0)
|
if (yang_spec_parse_module(h, "clixon-xml-changelog", NULL, yspec)< 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Clixon restconf daemon */
|
/* Clixon restconf daemon */
|
||||||
if (clicon_option_bool(h, "CLICON_RESTCONF_CONFIG"))
|
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
|
||||||
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
|
goto done;
|
||||||
goto done;
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
16
test/lib.sh
16
test/lib.sh
|
|
@ -49,6 +49,22 @@ if [ -f ./site.sh ]; then
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Auto-start nginx
|
||||||
|
nginxactive=$(systemctl show nginx |grep ActiveState=active)
|
||||||
|
if [ "${WITH_RESTCONF}" = "fcgi" ]; then
|
||||||
|
if [ -z "$nginxactive" ]; then
|
||||||
|
echo -e "\e[31m\nwith-restconf=fcgi set but nginx not running, start with systemctl start nginx"
|
||||||
|
echo -e "\e[0m"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ -n "$nginxactive" ]; then
|
||||||
|
echo -e "\e[31m\nwith-restconf=fcgi not set but nginx running, stop with systemctl stop nginx"
|
||||||
|
echo -e "\e[0m"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Test number from start
|
# Test number from start
|
||||||
: ${testnr:=0}
|
: ${testnr:=0}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,261 +35,293 @@ EOF
|
||||||
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
|
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
|
||||||
state='{"clixon-example:state":{"op":\["41","42","43"\]}'
|
state='{"clixon-example:state":{"op":\["41","42","43"\]}'
|
||||||
|
|
||||||
new "test params: -f $cfg -- -s"
|
if [ ${RCPROTO} = "https" ]; then
|
||||||
if [ $BE -ne 0 ]; then
|
ssl=true
|
||||||
new "kill old backend"
|
port=443
|
||||||
sudo clixon_backend -zf $cfg
|
else
|
||||||
if [ $? -ne 0 ]; then
|
ssl=false
|
||||||
err
|
port=80
|
||||||
|
fi
|
||||||
|
|
||||||
|
testrun()
|
||||||
|
{
|
||||||
|
USEBACKEND=$1
|
||||||
|
|
||||||
|
new "test params: -f $cfg -- -s"
|
||||||
|
if [ $BE -ne 0 ]; then
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $cfg
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
sudo pkill -f clixon_backend # to be sure
|
||||||
|
|
||||||
|
new "start backend -s init -f $cfg -- -s"
|
||||||
|
start_backend -s init -f $cfg -- -s
|
||||||
fi
|
fi
|
||||||
sudo pkill -f clixon_backend # to be sure
|
|
||||||
|
|
||||||
new "start backend -s init -f $cfg -- -s"
|
new "wait backend"
|
||||||
start_backend -s init -f $cfg -- -s
|
wait_backend
|
||||||
fi
|
|
||||||
|
|
||||||
new "wait backend"
|
if $USEBACKEND; then
|
||||||
wait_backend
|
new "netconf edit config"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><restconf xmlns=\"https://clicon.org/restconf\"><socket><namespace>default</namespace><address>0.0.0.0</address><port>$port</port><ssl>$ssl</ssl></socket><auth-type>password</auth-type></restconf></config></edit-config></rpc>]]>]]>"
|
||||||
|
"^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
new "netconf commit"
|
||||||
new "kill old restconf daemon"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||||
stop_restconf_pre
|
fi
|
||||||
|
|
||||||
new "start restconf daemon"
|
if [ $RC -ne 0 ]; then
|
||||||
start_restconf -f $cfg
|
new "kill old restconf daemon"
|
||||||
|
stop_restconf_pre
|
||||||
|
|
||||||
fi
|
|
||||||
new "wait restconf"
|
|
||||||
wait_restconf
|
|
||||||
|
|
||||||
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
if $USEBACKEND; then
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
new "start restconf daemon -b"
|
||||||
|
start_restconf -f $cfg -b
|
||||||
|
else
|
||||||
|
new "start restconf daemon"
|
||||||
|
start_restconf -f $cfg
|
||||||
|
fi
|
||||||
|
|
||||||
new "restconf get restconf resource. RFC 8040 3.3 (json)"
|
fi
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+json" $RCPROTO://localhost/restconf)" 0 'HTTP/1.1 200 OK' '{"ietf-restconf:restconf":{"data":{},"operations":{},"yang-library-version":"2016-06-21"}}'
|
new "wait restconf"
|
||||||
|
wait_restconf
|
||||||
|
|
||||||
new "restconf get restconf resource. RFC 8040 3.3 (xml)"
|
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
||||||
# Get XML instead of JSON?
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf)" 0 'HTTP/1.1 200 OK' '<restconf xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><data/><operations/><yang-library-version>2016-06-21</yang-library-version></restconf>'
|
|
||||||
|
|
||||||
# Should be alphabetically ordered
|
new "restconf get restconf resource. RFC 8040 3.3 (json)"
|
||||||
new "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
expectpart "$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+json" $RCPROTO://localhost/restconf)" 0 'HTTP/1.1 200 OK' '{"ietf-restconf:restconf":{"data":{},"operations":{},"yang-library-version":"2016-06-21"}}'
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/operations)" 0 'HTTP/1.1 200 OK' '{"operations":{"clixon-example:client-rpc":\[null\],"clixon-example:empty":\[null\],"clixon-example:optional":\[null\],"clixon-example:example":\[null\],"clixon-lib:debug":\[null\],"clixon-lib:ping":\[null\],"clixon-lib:stats":\[null\],"clixon-lib:restart-plugin":\[null\],"ietf-netconf:get-config":\[null\],"ietf-netconf:edit-config":\[null\],"ietf-netconf:copy-config":\[null\],"ietf-netconf:delete-config":\[null\],"ietf-netconf:lock":\[null\],"ietf-netconf:unlock":\[null\],"ietf-netconf:get":\[null\],"ietf-netconf:close-session":\[null\],"ietf-netconf:kill-session":\[null\],"ietf-netconf:commit":\[null\],"ietf-netconf:discard-changes":\[null\],"ietf-netconf:validate":\[null\]}}'
|
|
||||||
|
|
||||||
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
new "restconf get restconf resource. RFC 8040 3.3 (xml)"
|
||||||
ret=$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/operations)
|
# Get XML instead of JSON?
|
||||||
expect='<operations><client-rpc xmlns="urn:example:clixon"/><empty xmlns="urn:example:clixon"/><optional xmlns="urn:example:clixon"/><example xmlns="urn:example:clixon"/><debug xmlns="http://clicon.org/lib"/><ping xmlns="http://clicon.org/lib"/><stats xmlns="http://clicon.org/lib"/><restart-plugin xmlns="http://clicon.org/lib"/><get-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><copy-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><delete-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><lock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><unlock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><close-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><kill-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><commit xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><discard-changes xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><validate xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/></operations>'
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf)" 0 'HTTP/1.1 200 OK' '<restconf xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><data/><operations/><yang-library-version>2016-06-21</yang-library-version></restconf>'
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
|
||||||
if [ -z "$match" ]; then
|
|
||||||
err "$expect" "$ret"
|
|
||||||
fi
|
|
||||||
|
|
||||||
new "restconf get restconf/yang-library-version. RFC8040 3.3.3"
|
# Should be alphabetically ordered
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/yang-library-version)" 0 'HTTP/1.1 200 OK' '{"yang-library-version":"2016-06-21"}'
|
new "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
||||||
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/operations)" 0 'HTTP/1.1 200 OK' '{"operations":{"clixon-example:client-rpc":\[null\],"clixon-example:empty":\[null\],"clixon-example:optional":\[null\],"clixon-example:example":\[null\],"clixon-lib:debug":\[null\],"clixon-lib:ping":\[null\],"clixon-lib:stats":\[null\],"clixon-lib:restart-plugin":\[null\],"ietf-netconf:get-config":\[null\],"ietf-netconf:edit-config":\[null\],"ietf-netconf:copy-config":\[null\],"ietf-netconf:delete-config":\[null\],"ietf-netconf:lock":\[null\],"ietf-netconf:unlock":\[null\],"ietf-netconf:get":\[null\],"ietf-netconf:close-session":\[null\],"ietf-netconf:kill-session":\[null\],"ietf-netconf:commit":\[null\],"ietf-netconf:discard-changes":\[null\],"ietf-netconf:validate":\[null\]'
|
||||||
|
|
||||||
new "restconf get restconf/yang-library-version. RFC8040 3.3.3 (xml)"
|
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
||||||
ret=$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/yang-library-version)
|
ret=$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/operations)
|
||||||
expect="<yang-library-version>2016-06-21</yang-library-version>"
|
expect='<operations><client-rpc xmlns="urn:example:clixon"/><empty xmlns="urn:example:clixon"/><optional xmlns="urn:example:clixon"/><example xmlns="urn:example:clixon"/><debug xmlns="http://clicon.org/lib"/><ping xmlns="http://clicon.org/lib"/><stats xmlns="http://clicon.org/lib"/><restart-plugin xmlns="http://clicon.org/lib"/><get-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><copy-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><delete-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><lock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><unlock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><close-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><kill-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><commit xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><discard-changes xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><validate xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/>'
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895 (explicit resource)"
|
new "restconf get restconf/yang-library-version. RFC8040 3.3.3"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-interfaces,2018-02-20)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:module":\[{"name":"ietf-interfaces","revision":"2018-02-20","namespace":"urn:ietf:params:xml:ns:yang:ietf-interfaces","conformance-type":"implement"}\]}'
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/yang-library-version)" 0 'HTTP/1.1 200 OK' '{"yang-library-version":"2016-06-21"}'
|
||||||
|
|
||||||
new "restconf schema resource, mod-state top-level"
|
new "restconf get restconf/yang-library-version. RFC8040 3.3.3 (xml)"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-example","revision":"2020-03-11","namespace":"urn:example:clixon","conformance-type":"implement"},{"name":"clixon-lib","revision":"2020-04-23","'
|
ret=$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/yang-library-version)
|
||||||
|
expect="<yang-library-version>2016-06-21</yang-library-version>"
|
||||||
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
|
||||||
new "restconf options. RFC 8040 4.1"
|
new "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895 (explicit resource)"
|
||||||
expectpart "$(curl $CURLOPTS -X OPTIONS $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-interfaces,2018-02-20)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:module":\[{"name":"ietf-interfaces","revision":"2018-02-20","namespace":"urn:ietf:params:xml:ns:yang:ietf-interfaces","conformance-type":"implement"}\]}'
|
||||||
|
|
||||||
# -I means HEAD
|
new "restconf schema resource, mod-state top-level"
|
||||||
new "restconf HEAD. RFC 8040 4.2"
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-example","revision":"2020-03-11","namespace":"urn:example:clixon","conformance-type":"implement"},{"name":"clixon-lib","revision":"2020-04-23","'
|
||||||
expectpart "$(curl $CURLOPTS -I -H "Accept: application/yang-data+json" $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+json"
|
|
||||||
|
|
||||||
new "restconf empty rpc JSON"
|
new "restconf options. RFC 8040 4.1"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":null} $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 "HTTP/1.1 204 No Content"
|
expectpart "$(curl $CURLOPTS -X OPTIONS $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
|
||||||
|
|
||||||
new "restconf empty rpc XML"
|
# -I means HEAD
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+xml" -d '<input xmlns="urn:example:clixon"></input>' $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 "HTTP/1.1 204 No Content"
|
new "restconf HEAD. RFC 8040 4.2"
|
||||||
|
expectpart "$(curl $CURLOPTS -I -H "Accept: application/yang-data+json" $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+json"
|
||||||
|
|
||||||
new "restconf empty rpc, default media type should fail"
|
new "restconf empty rpc JSON"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -d {\"clixon-example:input\":null} $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":null} $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
new "restconf empty rpc, default media type should fail (JSON)"
|
new "restconf empty rpc XML"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Accept: application/yang-data+json" -d {\"clixon-example:input\":null} $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+xml" -d '<input xmlns="urn:example:clixon"></input>' $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
new "restconf empty rpc with extra args (should fail)"
|
new "restconf empty rpc, default media type should fail"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":{\"extra\":null}} $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Unrecognized parameter: extra in rpc: empty"}}}'
|
expectpart "$(curl $CURLOPTS -X POST -d {\"clixon-example:input\":null} $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
||||||
|
|
||||||
# Irritiating to get debugs on the terminal
|
new "restconf empty rpc, default media type should fail (JSON)"
|
||||||
#new "restconf debug rpc"
|
expectpart "$(curl $CURLOPTS -X POST -H "Accept: application/yang-data+json" -d {\"clixon-example:input\":null} $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
||||||
#expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-lib:input\":{\"level\":0}} $RCPROTO://localhost/restconf/operations/clixon-lib:debug)" 0 "HTTP/1.1 204 No Content"
|
|
||||||
|
|
||||||
new "restconf get empty config + state json"
|
new "restconf empty rpc with extra args (should fail)"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state)" 0 "HTTP/1.1 200 OK" '{"clixon-example:state":{"op":\["41","42","43"\]}}'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":{\"extra\":null}} $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Unrecognized parameter: extra in rpc: empty"}}}'
|
||||||
|
|
||||||
new "restconf get empty config + state json with wrong module name"
|
# Irritiating to get debugs on the terminal
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/badmodule:state)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"badmodule"},"error-severity":"error","error-message":"No such yang module prefix"}}}'
|
#new "restconf debug rpc"
|
||||||
|
#expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-lib:input\":{\"level\":0}} $RCPROTO://localhost/restconf/operations/clixon-lib:debug)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
#'HTTP/1.1 404 Not Found'
|
new "restconf get empty config + state json"
|
||||||
#'{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"invalid-value","error-severity":"error","error-message":"No such yang module: badmodule"}}}'
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state)" 0 "HTTP/1.1 200 OK" '{"clixon-example:state":{"op":\["41","42","43"\]}}'
|
||||||
|
|
||||||
new "restconf get empty config + state xml"
|
new "restconf get empty config + state json with wrong module name"
|
||||||
ret=$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data/clixon-example:state)
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/badmodule:state)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"badmodule"},"error-severity":"error","error-message":"No such yang module prefix"}}}'
|
||||||
expect='<state xmlns="urn:example:clixon"><op>41</op><op>42</op><op>43</op></state>'
|
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
|
||||||
if [ -z "$match" ]; then
|
|
||||||
err "$expect" "$ret"
|
|
||||||
fi
|
|
||||||
|
|
||||||
new "restconf get data type json"
|
#'HTTP/1.1 404 Not Found'
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state/op=42)" 0 '{"clixon-example:op":"42"}'
|
#'{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"invalid-value","error-severity":"error","error-message":"No such yang module: badmodule"}}}'
|
||||||
|
|
||||||
new "restconf get state operation"
|
new "restconf get empty config + state xml"
|
||||||
# Cant get shell macros to work, inline matching from lib.sh
|
ret=$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data/clixon-example:state)
|
||||||
ret=$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data/clixon-example:state/op=42)
|
expect='<state xmlns="urn:example:clixon"><op>41</op><op>42</op><op>43</op></state>'
|
||||||
expect='<op xmlns="urn:example:clixon">42</op>'
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
if [ -z "$match" ]; then
|
||||||
if [ -z "$match" ]; then
|
err "$expect" "$ret"
|
||||||
err "$expect" "$ret"
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
new "restconf get state operation type json"
|
new "restconf get data type json"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state/op=42)" 0 '{"clixon-example:op":"42"}'
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state/op=42)" 0 '{"clixon-example:op":"42"}'
|
||||||
|
|
||||||
new "restconf get state operation type xml"
|
new "restconf get state operation"
|
||||||
# Cant get shell macros to work, inline matching from lib.sh
|
# Cant get shell macros to work, inline matching from lib.sh
|
||||||
ret=$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data/clixon-example:state/op=42)
|
ret=$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data/clixon-example:state/op=42)
|
||||||
expect='<op xmlns="urn:example:clixon">42</op>'
|
expect='<op xmlns="urn:example:clixon">42</op>'
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "restconf GET datastore"
|
new "restconf get state operation type json"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state)" 0 "HTTP/1.1 200 OK" '{"clixon-example:state":{"op":\["41","42","43"\]}}'
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state/op=42)" 0 '{"clixon-example:op":"42"}'
|
||||||
|
|
||||||
# Exact match
|
new "restconf get state operation type xml"
|
||||||
new "restconf Add subtree eth/0/0 to datastore using POST"
|
# Cant get shell macros to work, inline matching from lib.sh
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Accept: application/yang-data+json" -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}}' $RCPROTO://localhost/restconf/data)" 0 'HTTP/1.1 201 Created' "Location: $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces"
|
ret=$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data/clixon-example:state/op=42)
|
||||||
|
expect='<op xmlns="urn:example:clixon">42</op>'
|
||||||
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
|
||||||
new "restconf Re-add subtree eth/0/0 which should give error"
|
new "restconf GET datastore"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}}' $RCPROTO://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}'
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state)" 0 "HTTP/1.1 200 OK" '{"clixon-example:state":{"op":\["41","42","43"\]}}'
|
||||||
|
|
||||||
new "restconf Check interfaces eth/0/0 added"
|
# Exact match
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/1.1 200 OK" '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
new "restconf Add subtree eth/0/0 to datastore using POST"
|
||||||
|
expectpart "$(curl $CURLOPTS -X POST -H "Accept: application/yang-data+json" -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}}' $RCPROTO://localhost/restconf/data)" 0 'HTTP/1.1 201 Created' "Location: $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces"
|
||||||
|
|
||||||
new "restconf delete interfaces"
|
new "restconf Re-add subtree eth/0/0 which should give error"
|
||||||
expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/1.1 204 No Content"
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}}' $RCPROTO://localhost/restconf/data)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}'
|
||||||
|
|
||||||
new "restconf Check empty config"
|
new "restconf Check interfaces eth/0/0 added"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state)" 0 "HTTP/1.1 200 OK" "$state"
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/1.1 200 OK" '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
||||||
|
|
||||||
new "restconf Add interfaces subtree eth/0/0 using POST"
|
new "restconf delete interfaces"
|
||||||
expectpart "$(curl $CURLOPTS -X POST $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}')" 0 "HTTP/1.1 201 Created"
|
expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
new "restconf Check eth/0/0 added config"
|
new "restconf Check empty config"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-example:state)" 0 "HTTP/1.1 200 OK" "$state"
|
||||||
|
|
||||||
new "restconf Check eth/0/0 GET augmented state level 1"
|
new "restconf Add interfaces subtree eth/0/0 using POST"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}'
|
expectpart "$(curl $CURLOPTS -X POST $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}')" 0 "HTTP/1.1 201 Created"
|
||||||
|
|
||||||
new "restconf Check eth/0/0 GET augmented state level 2"
|
new "restconf Check eth/0/0 added config"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0/clixon-example:my-status)" 0 'HTTP/1.1 200 OK' '{"clixon-example:my-status":{"int":42,"str":"foo"}}'
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
||||||
|
|
||||||
new "restconf Check eth/0/0 added state XXXXXXX"
|
new "restconf Check eth/0/0 GET augmented state level 1"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/clixon-example:state)" 0 'HTTP/1.1 200 OK' '{"clixon-example:state":{"op":\["41","42","43"\]}}'
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}'
|
||||||
|
|
||||||
new "restconf Re-post eth/0/0 which should generate error"
|
new "restconf Check eth/0/0 GET augmented state level 2"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0/clixon-example:my-status)" 0 'HTTP/1.1 200 OK' '{"clixon-example:my-status":{"int":42,"str":"foo"}}'
|
||||||
|
|
||||||
new "Add leaf description using POST"
|
new "restconf Check eth/0/0 added state XXXXXXX"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:description":"The-first-interface"}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/1.1 201 Created"
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/clixon-example:state)" 0 'HTTP/1.1 200 OK' '{"clixon-example:state":{"op":\["41","42","43"\]}}'
|
||||||
|
|
||||||
new "Add nothing using POST (expect fail)"
|
new "restconf Re-post eth/0/0 which should generate error"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"The message-body MUST contain exactly one instance of the expected data resource"}}}'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
||||||
|
|
||||||
new "restconf Check description added"
|
new "Add leaf description using POST"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/1.1 200 OK" '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","description":"The-first-interface","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:description":"The-first-interface"}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/1.1 201 Created"
|
||||||
|
|
||||||
new "restconf delete eth/0/0"
|
new "Add nothing using POST (expect fail)"
|
||||||
expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/1.1 204 No Content"
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"The message-body MUST contain exactly one instance of the expected data resource"}}}'
|
||||||
|
|
||||||
new "Check deleted eth/0/0"
|
new "restconf Check description added"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "$state"
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/1.1 200 OK" '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","description":"The-first-interface","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
||||||
|
|
||||||
new "restconf Re-Delete eth/0/0 using none should generate error"
|
new "restconf delete eth/0/0"
|
||||||
expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/1.1 409 Conflict" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-missing","error-severity":"error","error-message":"Data does not exist; cannot delete resource"}}}'
|
expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
new "restconf Add subtree eth/0/0 using PUT"
|
new "Check deleted eth/0/0"
|
||||||
expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/1.1 201 Created"
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "$state"
|
||||||
|
|
||||||
new "restconf get subtree"
|
new "restconf Re-Delete eth/0/0 using none should generate error"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/1.1 200 OK" '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/1.1 409 Conflict" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-missing","error-severity":"error","error-message":"Data does not exist; cannot delete resource"}}}'
|
||||||
|
|
||||||
new "restconf rpc using POST json"
|
new "restconf Add subtree eth/0/0 using PUT"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 "HTTP/1.1 200 OK" '{"clixon-example:output":{"x":"42","y":"42"}}'
|
expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/1.1 201 Created"
|
||||||
|
|
||||||
if ! $YANG_UNKNOWN_ANYDATA ; then
|
new "restconf get subtree"
|
||||||
new "restconf rpc using POST json wrong"
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/1.1 200 OK" '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"wrongelement"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: wrongelement with parent: example in namespace: urn:example:clixon"}}}'
|
|
||||||
fi
|
|
||||||
|
|
||||||
new "restconf rpc non-existing rpc without namespace"
|
new "restconf rpc using POST json"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{}' $RCPROTO://localhost/restconf/operations/kalle)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 "HTTP/1.1 200 OK" '{"clixon-example:output":{"x":"42","y":"42"}}'
|
||||||
|
|
||||||
new "restconf rpc non-existing rpc"
|
if ! $YANG_UNKNOWN_ANYDATA ; then
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{}' $RCPROTO://localhost/restconf/operations/clixon-example:kalle)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}'
|
new "restconf rpc using POST json wrong"
|
||||||
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"wrongelement"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: wrongelement with parent: example in namespace: urn:example:clixon"}}}'
|
||||||
|
fi
|
||||||
|
|
||||||
new "restconf rpc missing name"
|
new "restconf rpc non-existing rpc without namespace"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{}' $RCPROTO://localhost/restconf/operations)" 0 'HTTP/1.1 412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"Operation name expected"}}}'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{}' $RCPROTO://localhost/restconf/operations/kalle)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}'
|
||||||
|
|
||||||
new "restconf rpc missing input"
|
new "restconf rpc non-existing rpc"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"restconf RPC does not have input statement"}}}'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{}' $RCPROTO://localhost/restconf/operations/clixon-example:kalle)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}'
|
||||||
|
|
||||||
new "restconf rpc using POST xml"
|
new "restconf rpc missing name"
|
||||||
ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{}' $RCPROTO://localhost/restconf/operations)" 0 'HTTP/1.1 412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"Operation name expected"}}}'
|
||||||
expect='<output xmlns="urn:example:clixon"><x>42</x><y>42</y></output>'
|
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
|
||||||
if [ -z "$match" ]; then
|
|
||||||
err "$expect" "$ret"
|
|
||||||
fi
|
|
||||||
|
|
||||||
new "restconf rpc using wrong prefix"
|
new "restconf rpc missing input"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"wrong:input":{"routing-instance-name":"ipv4"}}' $RCPROTO://localhost/restconf/operations/wrong:example)" 0 "HTTP/1.1 412 Precondition Failed" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"yang module not found"}}}'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"restconf RPC does not have input statement"}}}'
|
||||||
|
|
||||||
new "restconf local client rpc using POST xml"
|
new "restconf rpc using POST xml"
|
||||||
ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":"example"}}' $RCPROTO://localhost/restconf/operations/clixon-example:client-rpc)
|
ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)
|
||||||
expect='<output xmlns="urn:example:clixon"><x>example</x></output>'
|
expect='<output xmlns="urn:example:clixon"><x>42</x><y>42</y></output>'
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "restconf Add subtree without key (expected error)"
|
new "restconf rpc using wrong prefix"
|
||||||
expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"malformed key =interface, expected'
|
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"wrong:input":{"routing-instance-name":"ipv4"}}' $RCPROTO://localhost/restconf/operations/wrong:example)" 0 "HTTP/1.1 412 Precondition Failed" '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"yang module not found"}}}'
|
||||||
|
|
||||||
new "restconf Add subtree with too many keys (expected error)"
|
new "restconf local client rpc using POST xml"
|
||||||
expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=a,b)" 0 "HTTP/1.1 400 Bad Request" '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key interface length mismatch"}}}'
|
ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":"example"}}' $RCPROTO://localhost/restconf/operations/clixon-example:client-rpc)
|
||||||
|
expect='<output xmlns="urn:example:clixon"><x>example</x></output>'
|
||||||
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
new "restconf Add subtree without key (expected error)"
|
||||||
new "Kill restconf daemon"
|
expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"malformed key =interface, expected'
|
||||||
stop_restconf
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
new "restconf Add subtree with too many keys (expected error)"
|
||||||
exit # BE
|
expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=a,b)" 0 "HTTP/1.1 400 Bad Request" '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"List key interface length mismatch"}}}'
|
||||||
fi
|
|
||||||
|
|
||||||
new "Kill backend"
|
if [ $RC -ne 0 ]; then
|
||||||
# Check if premature kill
|
new "Kill restconf daemon"
|
||||||
pid=$(pgrep -u root -f clixon_backend)
|
stop_restconf
|
||||||
if [ -z "$pid" ]; then
|
fi
|
||||||
err "backend already dead"
|
|
||||||
fi
|
if [ $BE -ne 0 ]; then
|
||||||
# kill backend
|
new "Kill backend"
|
||||||
stop_backend -f $cfg
|
# Check if premature kill
|
||||||
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
stop_backend -f $cfg
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
new "Use local restconf config"
|
||||||
|
testrun false
|
||||||
|
|
||||||
|
new "Get restconf config from backend"
|
||||||
|
testrun true
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
|
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
# New Restconf config using backend config
|
|
||||||
# DOES NOT WORK WITH FCGI
|
|
||||||
|
|
||||||
# Magic line must be first in script (see README.md)
|
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
|
||||||
|
|
||||||
# Skip it other than evhtp
|
|
||||||
if [ "${WITH_RESTCONF}" != "evhtp" ]; then
|
|
||||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi # skip
|
|
||||||
fi
|
|
||||||
|
|
||||||
APPNAME=example
|
|
||||||
cfg=$dir/conf.xml
|
|
||||||
|
|
||||||
# Use yang in example
|
|
||||||
|
|
||||||
cat <<EOF > $cfg
|
|
||||||
<clixon-config xmlns="http://clicon.org/config">
|
|
||||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
|
||||||
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
|
||||||
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
|
|
||||||
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
|
|
||||||
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
|
|
||||||
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
|
|
||||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
|
||||||
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
|
|
||||||
<CLICON_RESTCONF_CONFIG>true</CLICON_RESTCONF_CONFIG>
|
|
||||||
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
|
|
||||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
|
||||||
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
|
||||||
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
|
||||||
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
|
||||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
|
||||||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
|
||||||
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
|
|
||||||
</clixon-config>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
if [ ${RCPROTO} = "https" ]; then
|
|
||||||
ssl=true
|
|
||||||
port=443
|
|
||||||
else
|
|
||||||
ssl=false
|
|
||||||
port=80
|
|
||||||
fi
|
|
||||||
cat<<EOF > $dir/startup_db
|
|
||||||
<config>
|
|
||||||
<restconf xmlns="https://clicon.org/restconf">
|
|
||||||
<socket>
|
|
||||||
<namespace>default</namespace>
|
|
||||||
<address>0.0.0.0</address>
|
|
||||||
<port>$port</port>
|
|
||||||
<ssl>$ssl</ssl>
|
|
||||||
</socket>
|
|
||||||
<auth-type>password</auth-type>
|
|
||||||
<server-cert-path>/etc/ssl/certs/clixon-server-crt.pem</server-cert-path>
|
|
||||||
<server-key-path>/etc/ssl/private/clixon-server-key.pem</server-key-path>
|
|
||||||
<server-ca-cert-path>/etc/ssl/certs/clixon-ca_crt.pem</server-ca-cert-path>
|
|
||||||
<client-cert-ca></client-cert-ca>
|
|
||||||
</restconf>
|
|
||||||
</config>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
new "test params: -f $cfg"
|
|
||||||
if [ $BE -ne 0 ]; then
|
|
||||||
new "kill old backend"
|
|
||||||
sudo clixon_backend -zf $cfg -s startup
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
err
|
|
||||||
fi
|
|
||||||
sudo pkill -f clixon_backend # to be sure
|
|
||||||
|
|
||||||
new "start backend -s startup -f $cfg"
|
|
||||||
start_backend -s startup -f $cfg
|
|
||||||
fi
|
|
||||||
|
|
||||||
new "wait backend"
|
|
||||||
wait_backend
|
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
|
||||||
new "kill old restconf daemon"
|
|
||||||
stop_restconf_pre
|
|
||||||
|
|
||||||
new "start restconf daemon"
|
|
||||||
start_restconf -f $cfg
|
|
||||||
|
|
||||||
fi
|
|
||||||
new "wait restconf"
|
|
||||||
wait_restconf
|
|
||||||
|
|
||||||
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
|
||||||
|
|
||||||
new "restconf get restconf resource. RFC 8040 3.3 (json)"
|
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+json" $RCPROTO://localhost/restconf)" 0 'HTTP/1.1 200 OK' '{"ietf-restconf:restconf":{"data":{},"operations":{},"yang-library-version":"2016-06-21"}}'
|
|
||||||
|
|
||||||
new "restconf get restconf resource. RFC 8040 3.3 (xml)"
|
|
||||||
# Get XML instead of JSON?
|
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf)" 0 'HTTP/1.1 200 OK' '<restconf xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><data/><operations/><yang-library-version>2016-06-21</yang-library-version></restconf>'
|
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
|
||||||
new "Kill restconf daemon"
|
|
||||||
stop_restconf
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
|
||||||
exit # BE
|
|
||||||
fi
|
|
||||||
|
|
||||||
new "Kill backend"
|
|
||||||
# Check if premature kill
|
|
||||||
pid=$(pgrep -u root -f clixon_backend)
|
|
||||||
if [ -z "$pid" ]; then
|
|
||||||
err "backend already dead"
|
|
||||||
fi
|
|
||||||
# kill backend
|
|
||||||
stop_backend -f $cfg
|
|
||||||
|
|
||||||
rm -rf $dir
|
|
||||||
|
|
@ -101,7 +101,7 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR
|
||||||
# This just catches the header and the jukebox module, the RFC has foo and bar which
|
# This just catches the header and the jukebox module, the RFC has foo and bar which
|
||||||
# seems wrong to recreate
|
# seems wrong to recreate
|
||||||
new "B.1.2. Retrieve the Server Module Information"
|
new "B.1.2. Retrieve the Server Module Information"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2020-04-23","namespace":"http://clicon.org/lib","conformance-type":"implement"},{"name":"example-events","revision":"","namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"},{"name":"example-system","revision":"","namespace":"http://example.com/ns/example-system","conformance-type":"implement"}'
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2020-04-23","namespace":"http://clicon.org/lib","conformance-type":"implement"}' '{"name":"example-events","revision":"","namespace":"urn:example:events","conformance-type":"implement"}' '{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"}' '{"name":"example-system","revision":"","namespace":"http://example.com/ns/example-system","conformance-type":"implement"}'
|
||||||
|
|
||||||
new "B.1.3. Retrieve the Server Capability Information"
|
new "B.1.3. Retrieve the Server Capability Information"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' '<capabilities xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability><capability>urn:ietf:params:restconf:capability:depth</capability>
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' '<capabilities xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability><capability>urn:ietf:params:restconf:capability:depth</capability>
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ test -d $certdir || mkdir $certdir
|
||||||
|
|
||||||
# Use yang in example
|
# Use yang in example
|
||||||
|
|
||||||
|
# Get config from backend?
|
||||||
cat <<EOF > $cfg
|
cat <<EOF > $cfg
|
||||||
<clixon-config xmlns="http://clicon.org/config">
|
<clixon-config xmlns="http://clicon.org/config">
|
||||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
|
|
@ -204,72 +205,114 @@ done
|
||||||
|
|
||||||
fi # genkeys
|
fi # genkeys
|
||||||
|
|
||||||
# Startup DB with proper NACM config
|
# Set a clixon-restconf config
|
||||||
cat <<EOF > $dir/startup_db
|
if [ ${RCPROTO} = "https" ]; then
|
||||||
<config>
|
ssl=true
|
||||||
$RULES
|
port=443
|
||||||
</config>
|
else
|
||||||
|
ssl=false
|
||||||
|
port=80
|
||||||
|
fi
|
||||||
|
authtype=client-certificate
|
||||||
|
|
||||||
|
# Run with and without getting config from backend
|
||||||
|
# arg 1: false: local config; true: use config backend
|
||||||
|
testrun()
|
||||||
|
{
|
||||||
|
USEBACKEND=$1
|
||||||
|
|
||||||
|
# Startup DB with proper NACM config
|
||||||
|
if $USEBACKEND; then
|
||||||
|
cat <<EOF > $dir/startup_db
|
||||||
|
<config>
|
||||||
|
<restconf xmlns="https://clicon.org/restconf">
|
||||||
|
<socket>
|
||||||
|
<namespace>default</namespace>
|
||||||
|
<address>0.0.0.0</address>
|
||||||
|
<port>$port</port>
|
||||||
|
<ssl>$ssl</ssl>
|
||||||
|
</socket>
|
||||||
|
<auth-type>$authtype</auth-type>
|
||||||
|
<server-cert-path>$srvcert</server-cert-path>
|
||||||
|
<server-key-path>$srvkey</server-key-path>
|
||||||
|
<server-ca-cert-path>$cacert</server-ca-cert-path>
|
||||||
|
</restconf>
|
||||||
|
$RULES
|
||||||
|
</config>
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat <<EOF > $dir/startup_db
|
||||||
|
<config>
|
||||||
|
$RULES
|
||||||
|
</config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
if [ $BE -ne 0 ]; then
|
|
||||||
new "kill old backend"
|
|
||||||
sudo clixon_backend -zf $cfg
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
err
|
|
||||||
fi
|
fi
|
||||||
sudo pkill -f clixon_backend # to be sure
|
if [ $BE -ne 0 ]; then
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $cfg
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
sudo pkill -f clixon_backend # to be sure
|
||||||
|
|
||||||
new "start backend -s startup -f $cfg"
|
new "start backend -s startup -f $cfg"
|
||||||
start_backend -s startup -f $cfg
|
start_backend -s startup -f $cfg
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "wait for backend"
|
if [ $RC -ne 0 ]; then
|
||||||
wait_backend
|
new "kill old restconf daemon"
|
||||||
|
stop_restconf_pre
|
||||||
|
if $USEBACKEND; then
|
||||||
|
new "start restconf daemon -b -- -s"
|
||||||
|
start_restconf -f $cfg -b -- -s
|
||||||
|
else
|
||||||
|
new "start restconf daemon -s -c -- -s"
|
||||||
|
start_restconf -f $cfg -s -c -- -s
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
new "wait for backend"
|
||||||
new "kill old restconf daemon"
|
wait_backend
|
||||||
stop_restconf_pre
|
|
||||||
|
|
||||||
new "start restconf daemon -c means client certs, -- -s means ssl client cert authentication in example"
|
new "wait for restconf"
|
||||||
start_restconf -f $cfg -c -- -s
|
wait_restconf --key $certdir/andy.key --cert $certdir/andy.crt
|
||||||
fi
|
|
||||||
|
|
||||||
new "wait for restconf"
|
new "enable nacm"
|
||||||
wait_restconf --key $certdir/andy.key --cert $certdir/andy.crt
|
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' $RCPROTO://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
new "enable nacm"
|
new "admin get x"
|
||||||
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' $RCPROTO://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 "HTTP/1.1 204 No Content"
|
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":0}'
|
||||||
|
|
||||||
new "admin get x"
|
new "guest get x"
|
||||||
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":0}'
|
expectpart "$(curl $CURLOPTS --key $certdir/guest.key --cert $certdir/guest.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 403 Forbidden" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}'
|
||||||
|
|
||||||
new "guest get x"
|
new "admin set x 42"
|
||||||
expectpart "$(curl $CURLOPTS --key $certdir/guest.key --cert $certdir/guest.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 403 Forbidden" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}'
|
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X PUT -H "Content-Type: application/yang-data+json" -d '{"example:x":42}' $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 204 No Content"
|
||||||
|
|
||||||
new "admin set x 42"
|
new "admin get x 42"
|
||||||
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X PUT -H "Content-Type: application/yang-data+json" -d '{"example:x":42}' $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 204 No Content"
|
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":42}'
|
||||||
|
|
||||||
new "admin get x 42"
|
if [ $RC -ne 0 ]; then
|
||||||
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":42}'
|
new "Kill restconf daemon"
|
||||||
|
stop_restconf
|
||||||
|
fi
|
||||||
|
if [ $BE -ne 0 ]; then
|
||||||
|
new "Kill backend"
|
||||||
|
# Check if premature kill
|
||||||
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
stop_backend -f $cfg
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
new "Use local restconf config"
|
||||||
|
testrun false
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
new "Get restconf config from backend"
|
||||||
new "Kill restconf daemon"
|
testrun true
|
||||||
stop_restconf
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
|
||||||
exit # BE
|
|
||||||
fi
|
|
||||||
|
|
||||||
new "Kill backend"
|
|
||||||
# Check if premature kill
|
|
||||||
pid=$(pgrep -u root -f clixon_backend)
|
|
||||||
if [ -z "$pid" ]; then
|
|
||||||
err "backend already dead"
|
|
||||||
fi
|
|
||||||
# kill backend
|
|
||||||
stop_backend -f $cfg
|
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,10 @@ cat <<EOF > $dir/startup_db
|
||||||
</config>
|
</config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
MODSTATE='<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"><module-set-id>0</module-set-id><module><name>clixon-lib</name><revision>2020-04-23</revision><namespace>http://clicon.org/lib</namespace></module><module><name>ietf-inet-types</name><revision>2020-07-06</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace></module><module><name>ietf-netconf</name><revision>2011-06-01</revision><namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace></module>'
|
MODSTATE1='<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"><module-set-id>0</module-set-id><module><name>clixon-lib</name><revision>2020-04-23</revision><namespace>http://clicon.org/lib</namespace></module>'
|
||||||
|
|
||||||
|
MODSTATE2='<module><name>interfaces</name><revision>2018-02-20</revision><namespace>urn:example:interfaces</namespace></module>'
|
||||||
|
|
||||||
|
|
||||||
XML='<interfaces xmlns="urn:example:interfaces"><interface><name>e0</name><docs><descr>First interface</descr></docs><type>eth</type><admin-status>up</admin-status><statistics><in-octets>54326.432</in-octets><in-unicast-pkts>8458765</in-unicast-pkts></statistics></interface><interface><name>e1</name><type>eth</type><admin-status>down</admin-status></interface></interfaces>'
|
XML='<interfaces xmlns="urn:example:interfaces"><interface><name>e0</name><docs><descr>First interface</descr></docs><type>eth</type><admin-status>up</admin-status><statistics><in-octets>54326.432</in-octets><in-unicast-pkts>8458765</in-unicast-pkts></statistics></interface><interface><name>e1</name><type>eth</type><admin-status>down</admin-status></interface></interfaces>'
|
||||||
|
|
||||||
|
|
@ -319,11 +322,19 @@ fi
|
||||||
new "start backend -s startup -f $cfg -q -- -u"
|
new "start backend -s startup -f $cfg -q -- -u"
|
||||||
output=$(sudo $clixon_backend -F -D $DBG -s startup -f $cfg -q -- -u)
|
output=$(sudo $clixon_backend -F -D $DBG -s startup -f $cfg -q -- -u)
|
||||||
|
|
||||||
match=$(echo "$output" | grep --null -o "$MODSTATE")
|
new "check modstate1"
|
||||||
|
match=$(echo "$output" | grep --null -o "$MODSTATE1")
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$MODSTATE" "$output"
|
err "$MODSTATE1" "$output"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
new "check modstate"
|
||||||
|
match=$(echo "$output" | grep --null -o "$MODSTATE2")
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$MODSTATE2" "$output"
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "check xml"
|
||||||
match=$(echo "$output" | grep --null -o "$XML")
|
match=$(echo "$output" | grep --null -o "$XML")
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$XML" "$output"
|
err "$XML" "$output"
|
||||||
|
|
|
||||||
|
|
@ -141,13 +141,6 @@ module clixon-restconf {
|
||||||
default "/etc/ssl/certs/clixon-ca_crt.pem";
|
default "/etc/ssl/certs/clixon-ca_crt.pem";
|
||||||
/* CLICON_SSL_CA_CERT */
|
/* CLICON_SSL_CA_CERT */
|
||||||
}
|
}
|
||||||
leaf client-cert-ca {
|
|
||||||
type string;
|
|
||||||
description
|
|
||||||
"Path to client certificate file
|
|
||||||
Note only applies if socket has ssl enabled AND auth-type has client-certificate
|
|
||||||
XXX: Is this relevant?";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rpc restconf-control {
|
rpc restconf-control {
|
||||||
input {
|
input {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue