Added state data
This commit is contained in:
parent
43c39160a5
commit
f5c19d8586
24 changed files with 512 additions and 224 deletions
|
|
@ -232,7 +232,7 @@ from_client_get_config(clicon_handle h,
|
|||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
||||
if ((selector = xml_find_value(xfilter, "select"))==NULL)
|
||||
selector="/";
|
||||
if (xmldb_get(h, db, selector, &xret) < 0){
|
||||
if (xmldb_get(h, db, selector, 1, &xret) < 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>application</error-type>"
|
||||
|
|
@ -260,6 +260,54 @@ from_client_get_config(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Internal message: get
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xe Netconf request xml tree
|
||||
* @param[out] cbret Return xml value cligen buffer
|
||||
*/
|
||||
static int
|
||||
from_client_get(clicon_handle h,
|
||||
cxobj *xe,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xfilter;
|
||||
char *selector = "/";
|
||||
cxobj *xret = NULL;
|
||||
|
||||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
||||
if ((selector = xml_find_value(xfilter, "select"))==NULL)
|
||||
selector="/";
|
||||
if (xmldb_get(h, "running", selector, 0, &xret) < 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>application</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-info>read-registry</error-info>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
goto ok;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply><data>");
|
||||
/* if empty only <data/>, if any data then <data><config>..</config></data> */
|
||||
if (xret!=NULL){
|
||||
if (xml_child_nr(xret)){
|
||||
if (xml_name_set(xret, "config") < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
cprintf(cbret, "</data></rpc-reply>");
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Internal message: edit-config
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
|
|
@ -281,7 +329,13 @@ from_client_edit_config(clicon_handle h,
|
|||
cxobj *x;
|
||||
enum operation_type operation = OP_MERGE;
|
||||
int piddb;
|
||||
int non_config = 0;
|
||||
yang_spec *yspec;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
||||
goto done;
|
||||
}
|
||||
if ((target = netconf_db_find(xn, "target")) == NULL){
|
||||
clicon_err(OE_XML, 0, "db not found");
|
||||
goto done;
|
||||
|
|
@ -295,7 +349,6 @@ from_client_edit_config(clicon_handle h,
|
|||
"</rpc-error></rpc-reply>", target);
|
||||
goto ok;
|
||||
}
|
||||
|
||||
/* Check if target locked by other client */
|
||||
piddb = xmldb_islocked(h, target);
|
||||
if (piddb && mypid != piddb){
|
||||
|
|
@ -320,6 +373,20 @@ from_client_edit_config(clicon_handle h,
|
|||
}
|
||||
}
|
||||
if ((xc = xpath_first(xn, "config")) != NULL){
|
||||
if (xml_apply(xc, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xc, CX_ELMNT, xml_non_config_data, &non_config) < 0)
|
||||
goto done;
|
||||
if (non_config){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>invalid-value</error-tag>"
|
||||
"<error-type>protocol</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-message>state data not allowed</error-message>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
goto ok;
|
||||
}
|
||||
|
||||
if (xmldb_put(h, target, operation, xc) < 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
|
|
@ -875,6 +942,10 @@ from_client_msg(clicon_handle h,
|
|||
if (from_client_unlock(h, xe, pid, cbret) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(name, "get") == 0){
|
||||
if (from_client_get(h, xe, cbret) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(name, "close-session") == 0){
|
||||
xmldb_unlock_all(h, pid);
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
|
|
|
|||
|
|
@ -146,9 +146,9 @@ validate_common(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
/* 2. Parse xml trees */
|
||||
if (xmldb_get(h, "running", "/", &td->td_src) < 0)
|
||||
if (xmldb_get(h, "running", "/", 1, &td->td_src) < 0)
|
||||
goto done;
|
||||
if (xmldb_get(h, candidate, "/", &td->td_target) < 0)
|
||||
if (xmldb_get(h, candidate, "/", 1, &td->td_target) < 0)
|
||||
goto done;
|
||||
|
||||
/* 3. Compute differences */
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ cli_dbxml(clicon_handle h,
|
|||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
goto done;
|
||||
if (y->yn_keyword != Y_LIST){
|
||||
if (y->yn_keyword != Y_LIST && y->yn_keyword != Y_LEAF_LIST){
|
||||
len = cvec_len(cvv);
|
||||
if (len > 1){
|
||||
cval = cvec_i(cvv, len-1);
|
||||
|
|
|
|||
|
|
@ -530,6 +530,76 @@ netconf_unlock(clicon_handle h,
|
|||
return netconf_lock(h, xn, xret);
|
||||
}
|
||||
|
||||
/*! Get running configuration and device state information
|
||||
*
|
||||
*
|
||||
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
|
||||
* @param[out] xret Return XML, error or OK
|
||||
* @note filter type subtree and xpath is supported, but xpath is preferred, and
|
||||
* better performance and tested. Please use xpath.
|
||||
*
|
||||
* @example
|
||||
* <rpc><get><filter type="xpath" select="//SenderTwampIpv4"/>
|
||||
* </get></rpc>]]>]]>
|
||||
*/
|
||||
static int
|
||||
netconf_get(clicon_handle h,
|
||||
cxobj *xn,
|
||||
cxobj **xret)
|
||||
{
|
||||
cxobj *xfilter; /* filter */
|
||||
int retval = -1;
|
||||
char *ftype = NULL;
|
||||
cxobj *xfilterconf;
|
||||
cxobj *xconf;
|
||||
|
||||
/* ie <filter>...</filter> */
|
||||
if ((xfilter = xpath_first(xn, "filter")) != NULL)
|
||||
ftype = xml_find_value(xfilter, "type");
|
||||
if (ftype == NULL || strcmp(ftype, "xpath")==0){
|
||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(ftype, "subtree")==0){
|
||||
/* Default rfc filter is subtree. I prefer xpath and use it internally.
|
||||
Get whole subtree and then filter aftwerwards. This is suboptimal.
|
||||
Therefore please use xpath.
|
||||
*/
|
||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||
goto done;
|
||||
if (xfilter &&
|
||||
(xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
|
||||
(xconf = xpath_first(*xret, "/rpc-reply/data/configuration")) != NULL){
|
||||
/* xml_filter removes parts of xml tree not matching */
|
||||
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
|
||||
xml_filter(xfilterconf, xconf) < 0){
|
||||
clicon_xml_parse(xret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>applicatio</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-info>filtering</error-info>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
clicon_xml_parse(xret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>applicatio</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-message>filter type not supported</error-message>"
|
||||
"<error-info>type</error-info>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
}
|
||||
// ok: /* netconf error is not fatal */
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Close a (user) session
|
||||
<close-session/>
|
||||
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
|
||||
|
|
@ -818,6 +888,8 @@ netconf_rpc_dispatch(clicon_handle h,
|
|||
return netconf_lock(h, xe, xret);
|
||||
else if (strcmp(xml_name(xe), "unlock") == 0)
|
||||
return netconf_unlock(h, xe, xret);
|
||||
else if (strcmp(xml_name(xe), "get") == 0)
|
||||
return netconf_get(h, xe, xret);
|
||||
else if (strcmp(xml_name(xe), "close-session") == 0)
|
||||
return netconf_close_session(h, xe, xret);
|
||||
else if (strcmp(xml_name(xe), "kill-session") == 0)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,96 @@
|
|||
|
||||
#include "restconf_lib.h"
|
||||
|
||||
/* See RFC 8040 Section 7: Mapping from NETCONF<error-tag> to Status Code
|
||||
* and RFC 6241 Appendix A. NETCONF Error list
|
||||
*/
|
||||
static const map_str2int netconf_restconf_map[] = {
|
||||
{"in-use", 409},
|
||||
{"invalid-value", 400},
|
||||
{"invalid-value", 404},
|
||||
{"invalid-value", 406},
|
||||
{"too-big", 413}, /* request */
|
||||
{"too-big", 400}, /* response */
|
||||
{"missing-attribute", 400},
|
||||
{"bad-attribute", 400},
|
||||
{"unknown-attribute", 400},
|
||||
{"bad-element", 400},
|
||||
{"unknown-element", 400},
|
||||
{"unknown-namespace", 400},
|
||||
{"access-denied", 401},
|
||||
{"access-denied", 403},
|
||||
{"lock-denied", 409},
|
||||
{"resource-denied", 409},
|
||||
{"rollback-failed", 500},
|
||||
{"data-exists", 409},
|
||||
{"data-missing", 409},
|
||||
{"operation-not-supported",405},
|
||||
{"operation-not-supported",501},
|
||||
{"operation-failed", 412},
|
||||
{"operation-failed", 500},
|
||||
{"partial-operation", 500},
|
||||
{"malformed-message", 400},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
/* See 7231 Section 6.1
|
||||
*/
|
||||
static const map_str2int http_reason_phrase_map[] = {
|
||||
{"Continue", 100},
|
||||
{"Switching Protocols", 101},
|
||||
{"OK", 200},
|
||||
{"Created", 201},
|
||||
{"Accepted", 202},
|
||||
{"Non-Authoritative Information", 203},
|
||||
{"No Content", 204},
|
||||
{"Reset Content", 205},
|
||||
{"Partial Content", 206},
|
||||
{"Multiple Choices", 300},
|
||||
{"Moved Permanently", 301},
|
||||
{"Found", 302},
|
||||
{"See Other", 303},
|
||||
{"Not Modified", 304},
|
||||
{"Use Proxy", 305},
|
||||
{"Temporary Redirect", 307},
|
||||
{"Bad Request", 400},
|
||||
{"Unauthorized", 401},
|
||||
{"Payment Required", 402},
|
||||
{"Forbidden", 403},
|
||||
{"Not Found", 404},
|
||||
{"Method Not Allowed", 405},
|
||||
{"Not Acceptable", 406},
|
||||
{"Proxy Authentication Required", 407},
|
||||
{"Request Timeout", 408},
|
||||
{"Conflict", 409},
|
||||
{"Gone", 410},
|
||||
{"Length Required", 411},
|
||||
{"Precondition Failed", 412},
|
||||
{"Payload Too Large", 413},
|
||||
{"URI Too Long", 414},
|
||||
{"Unsupported Media Type", 415},
|
||||
{"Range Not Satisfiable", 416},
|
||||
{"Expectation Failed", 417},
|
||||
{"Upgrade Required", 426},
|
||||
{"Internal Server Error", 500},
|
||||
{"Not Implemented", 501},
|
||||
{"Bad Gateway", 502},
|
||||
{"Service Unavailable", 503},
|
||||
{"Gateway Timeout", 504},
|
||||
{"HTTP Version Not Supported", 505},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
int
|
||||
restconf_err2code(char *tag)
|
||||
{
|
||||
return clicon_str2int(netconf_restconf_map, tag);
|
||||
}
|
||||
|
||||
const char *
|
||||
restconf_code2reason(int code)
|
||||
{
|
||||
return clicon_int2str(http_reason_phrase_map, code);
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int restconf_err2code(char *tag);
|
||||
const char *restconf_code2reason(int code);
|
||||
int notfound(FCGX_Request *r);
|
||||
int badrequest(FCGX_Request *r);
|
||||
int conflict(FCGX_Request *r);
|
||||
|
|
|
|||
|
|
@ -190,8 +190,8 @@ api_data_get_gen(clicon_handle h,
|
|||
notfound(r); /* bad reply? */
|
||||
goto done;
|
||||
}
|
||||
code = clicon_str2int(netconf_restconf_map, xml_body(xtag));
|
||||
if ((reason_phrase = clicon_int2str(http_reason_phrase_map, code)) == NULL)
|
||||
code = restconf_err2code(xml_body(xtag));
|
||||
if ((reason_phrase = restconf_code2reason(code)) == NULL)
|
||||
reason_phrase="";
|
||||
clicon_debug(1, "%s code:%d reason phrase:%s",
|
||||
__FUNCTION__, code, reason_phrase);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue