Add a way to report rpc-errors from a plugin

Add plugin_rpc_err(), which works something like clixon_err, but it
saves error information from a plugin for reporting rpc-errors that
need to be returned.

Also add plugin_rpc_err_xml(), which does an XML formatted error.

The plugin error is stored in the clixon_handle and retrieved from
there.

Signed-off-by: Corey Minyard <corey@minyard.net>
This commit is contained in:
Corey Minyard 2024-09-27 15:14:46 -05:00 committed by Olof Hagsand
parent 3a1aa4052f
commit 9bdacc8671
2 changed files with 211 additions and 0 deletions

View file

@ -77,6 +77,7 @@
#include "clixon_netconf_lib.h"
#include "clixon_validate.h"
#include "clixon_proc.h"
#include "clixon_data.h"
#include "clixon_plugin.h"
/*
@ -1767,6 +1768,207 @@ clixon_auth_type_int2str(clixon_auth_type_t auth_type)
return clicon_int2str(clixon_auth_type, auth_type);
}
/*! Save an RPC error to be reported by clixon.
*
* @param[in] h Clixon
* @param[in] ns Namespace. If NULL the netconf base ns will be used
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] severity Severity: "error" or "warning"
* @param[in] tag Error tag, like "invalid-value" or "unknown-attribute"
* @param[in] info bad-attribute or bad-element xml. If NULL not included.
* @param[in] fmt Error message format. May be NULL.
* @retval 0 Success
* @retval -1 Error
*/
int
clixon_plugin_rpc_err(clixon_handle h,
const char *ns,
const char *type,
const char *tag,
const char *info,
const char *severity,
const char *fmt, ...)
{
int retval = -1;
int err;
cvec *cvv = NULL;
cvec *old_cvv = clicon_data_cvec_get(h, "rpc_err");
cvv = cvec_new(0);
if (!cvv)
goto done;
if (ns) {
if (cvec_add_string(cvv, "ns", ns))
goto done;
}
if (cvec_add_string(cvv, "type", type))
goto done;
if (cvec_add_string(cvv, "tag", tag))
goto done;
if (info) {
if (cvec_add_string(cvv, "info", info))
goto done;
}
if (cvec_add_string(cvv, "severity", severity))
goto done;
if (fmt) {
va_list args;
cbuf *cb;
cb = cbuf_new();
if (!cb)
goto done;
va_start(args, fmt);
err = vcprintf(cb, fmt, args);
va_end(args);
if (err < 0) {
cbuf_free(cb);
goto done;
}
cvec_add_string(cvv, "message", cbuf_get(cb));
cbuf_free(cb);
}
err = clicon_data_cvec_set(h, "rpc_err", cvv);
if (err)
goto done;
retval = 0;
done:
if (retval && cvv)
cvec_free(cvv);
if (!retval && old_cvv)
cvec_free(old_cvv);
return retval;
}
/*! Frees memory associated with clixon_rpc_err().
*
* @param[in] h Clixon
*/
static void
clixon_plugin_rpc_err_exit(clixon_handle h)
{
cvec *cvv = clicon_data_cvec_get(h, "rpc_err");
clicon_ptr_del(h, "rpc_err");
cvec_free(cvv);
}
/*! Returns if the rpc error has already been set.
*
* @param[in] h Clixon
*
* @retval 0 The rpc error is not set
* @retval 1 The rpc error is set
*/
int
clixon_plugin_rpc_err_set(clixon_handle h)
{
return clicon_data_cvec_get(h, "rpc_err") != NULL;
}
static int
netconf_gen_rpc_err(clixon_handle h, cbuf *cbret)
{
cvec *cvv = clicon_data_cvec_get(h, "rpc_err");
int retval;
/* Delete the pointer so the cvec doesn't get freed. */
clicon_ptr_del(h, "rpc_err");
retval = netconf_common_rpc_err(cbret,
cvec_find_str(cvv, "ns"),
cvec_find_str(cvv, "type"),
cvec_find_str(cvv, "tag"),
cvec_find_str(cvv, "severity"),
cvec_find_str(cvv, "info"),
cvec_find_str(cvv, "message"));
cvec_free(cvv);
return retval;
}
static int
netconf_gen_rpc_err_xml(clixon_handle h, cxobj **xret)
{
cvec *cvv = clicon_data_cvec_get(h, "rpc_err");
int retval;
/* Delete the pointer so the cvec doesn't get freed. */
clicon_ptr_del(h, "rpc_err");
retval = netconf_common_rpc_err_xml(xret,
cvec_find_str(cvv, "ns"),
cvec_find_str(cvv, "type"),
cvec_find_str(cvv, "tag"),
cvec_find_str(cvv, "severity"),
NULL,
cvec_find_str(cvv, "info"),
cvec_find_str(cvv, "message"));
cvec_free(cvv);
return retval;
}
/*! Report an error from a plugin.
*
* @param[in] h Clixon
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
* @retval 0 Success
* @retval -1 Error
*/
int
clixon_plugin_report_err(clixon_handle h,
cbuf *cbret)
{
int ret;
if (clixon_plugin_rpc_err_set(h)) {
if ((ret = netconf_gen_rpc_err(h, cbret)) < 0)
return ret;
} else if ((ret = netconf_operation_failed(cbret, "application",
clixon_err_reason())) < 0) {
return ret;
}
return 0;
}
/*! Report an error from a plugin.
*
* @param[in] h Clixon
* @param[out] xret Error XML tree. Free with xml_free after use
* @retval 0 Success
* @retval -1 Error
*/
int
clixon_plugin_report_err_xml(clixon_handle h,
cxobj **xret,
char *err,
...)
{
int ret = -1;
cbuf *cberr;
va_list ap;
if (clixon_plugin_rpc_err_set(h)) {
ret = netconf_gen_rpc_err_xml(h, xret);
} else {
if ((cberr = cbuf_new()) == NULL) {
clixon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
va_start(ap, err);
vcprintf(cberr, err, ap);
ret = netconf_operation_failed_xml(xret, "application",
cbuf_get(cberr));
cbuf_free(cberr);
}
done:
return ret;
}
/*! Initialize plugin module by creating a handle holding plugin and callback lists
*
* This should be called once at start by every application
@ -1818,5 +2020,7 @@ clixon_plugin_module_exit(clixon_handle h)
free(ph);
plugin_module_struct_set(h, NULL);
}
/* Free memory associated with plugin_rpc_err() */
clixon_plugin_rpc_err_exit(h);
return 0;
}