AVAILABLE SINCE 20.10-0 RELEASE
The SIL-SA version of the Get Data API has the same goal as regular SIL version; however, it has different template definition since the SIL-SA does not have a direct access to the server and the call to Get Data API will trigger message exchange with the server in order to retrieve the requested node.
If the XPath expression matches multiple nodes, then only the first instance is returned. The exact instance is implementation-dependent if the data is “ordered-by system”.
The following function template definition is used for SIL-SA Get Data API callback functions:
/* FUNCTION sil_sa_get_data */ val_value_t * sil_sa_get_data (ncx_cfg_t cfg_id, const xmlChar *defpath, status_t *retres) typedef enum ncx_cfg_t_ { NCX_CFGID_RUNNING, NCX_CFGID_CANDIDATE, NCX_CFGID_STARTUP } YPACK ncx_cfg_t;
API Template
- Type: Subsystem Utility Function
File: sil_sa.h
Template: sil_sa_get_data
Inputs:
cfgid == datastore enumeration to use (candidate or running)
NCX_CFGID_RUNNING
NCX_CFGID_CANDIDATE
defpath == XPath expression specifying the data instance to add
retres == address of return status
Outputs:
*retres == set to the return status
Returns: val_value_t pointer to data node if found
This function will return value only if there is existing node in the datastore or there is defaults for the node.
Data cannot be saved and used later, can only be used immediately after the call to sil_sa_get_data() API.
If the XPath expression "defpath" matches multiple nodes, then only the first instance is returned.
ERR_NCX_DEF_NOT_FOUND can be returned if the XPath expression contains unknown or ambiguous object names.
Example
Assume we register Transaction Hook callback for the top level /if:interfaces container element. In this example, we will validate the container node with help of the callback and a Get Data API call to retrieve the specific desired node.
Now, whenever the 'interfaces' node is edited, the callback function will be called and perform specific validation actions.
The callback function may look as follows:
/******************************************************************** * FUNCTION hooks_sethook_edit * * Callback function for server object handler * Used to provide a callback for a specific named object * * * Transaction-Hook: * trigger: DELETE /interface * * effect: * - if testval node exist the CREATE operation will be denied * - if testval has value 'deny-delete', the operation will be denied * * INPUTS: * scb == session control block making the request * msg == incoming rpc_msg_t in progress * editop == edit operation enumeration for the node being edited * newval == container object holding the proposed changes to * apply to the current config, depending on * the editop value. Will not be NULL. * curval == current container values from the <running> * or <candidate> configuration, if any. Could be NULL * for create and other operations. * transaction_id == transaction ID of the transaction control block in progress * isvalidate == TRUE if this Transaction is for <validate> operation * isload == TRUE if this Transaction is for a Load operation * isrunning == TRUE if this Transaction is for the the running datastore * * RETURNS: * status *********************************************************************/ static status_t transhook_callback (ses_cb_t *scb, rpc_msg_t *msg, op_editop_t editop, val_value_t *newval, val_value_t *curval, const xmlChar *transaction_id, boolean isvalidate, boolean isload, boolean isrunning) { log_debug("\nEnter Transaction-Hook callback"); status_t res = NO_ERR; status_t res2 = NO_ERR; val_value_t *errorval = (curval) ? curval : newval; const xmlChar *defpath = (const xmlChar *)"/if:interfaces/if:status"; const xmlChar *user = sil_sa_get_username(); const xmlChar *client_addr = sil_sa_get_client_addr(); if (LOGDEBUG2) { log_debug2("\n\n********************************************"); log_debug2("\nEnter transhook_callback callback for silsa-test " "---- 1"); log_debug2("\ntransaction_id -- %s", transaction_id); log_debug2("\nuser_id -- %s", user); log_debug2("\nclient_addr -- %s", client_addr); log_debug2("\nisvalidate -- %s", isvalidate ? NCX_EL_TRUE : NCX_EL_FALSE); log_debug2("\nisload -- %s", isload ? NCX_EL_TRUE : NCX_EL_FALSE); log_debug2("\nisrunning -- %s", isrunning ? NCX_EL_TRUE : NCX_EL_FALSE); log_debug2("\n********************************************\n\n"); } /* find a test node and validate its value */ val_value_t *testval = sil_sa_get_data(NCX_CFGID_RUNNING, defpath, &res2); switch (editop) { case OP_EDITOP_LOAD: break; case OP_EDITOP_MERGE: case OP_EDITOP_REPLACE: case OP_EDITOP_CREATE: /* deny an edit, if the test exist */ if (testval) { res = ERR_NCX_ACCESS_DENIED; } break; case OP_EDITOP_DELETE: /* deny an edit, if the test value set to “deny-delete” */ if (testval && !xml_strcmp(VAL_STR(testval), (const xmlChar *)"deny-delete") { res = ERR_NCX_ACCESS_DENIED; } else { res2 = NO_ERR; } break; default: res = SET_ERROR(ERR_INTERNAL_VAL); } if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_CONTENT, res, NULL, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval); } return res; } /* hooks_transhook_edit */
So whenever some north bound agent edits an /if:interfaces node the callback is invoked and additionally validates the /if:interfaces/if:status node. Based on this validation, the operation can be denied or granted.