The DB-API database variant allows an external process to initiate database edits, that are processed by the server as user or system edits.

The DB-API functions described in the this article can be used by the subsystem to edit the server configuration database.

This variant can be used with other variants for processing non-volatile storage. This variant is used to co-exist with a legacy or canonical database owned by the system.


 Configuration properties:

  • Tree-based data structures in memory for run-time transaction processing

  • This may or may not be the canonical database, depending on the non-volatile storage options.

  • There may be another database in the system

  • The server uses its copy in memory as the complete database

  • The DB-API “send_edit” and “send_edit_ex” API functions can be used to transfer configuration from the system to netconfd-pro.

  • Data is transferred in XML

  • Error responses are sent by the server if an edit is not accepted.

  • An error will be returned if a client is already in the process of editing the database

  • The db-api-app application is installed in /usr/share/yumapro/src/db-api-app by default, and includes some examples of initializing the DB-API service and sending edits to the server


DB-API Examples


The DB-API subsystem allows an external process on the same system as netconfd-pro to send database edits to the server.

  • db_api_register_service

  • db_api_service_ready

  • db_api_send_edit

  • db_api_send_edit_ex

  • db_api_send_edit_full

  • db_api_check_edit


extern status_t
    db_api_register_service (void);


extern boolean
    db_api_service_ready (void);


extern status_t
    db_api_send_edit (const xmlChar *edit_target,
                      const xmlChar *edit_operation,
                      const xmlChar *edit_xml_value);


extern status_t
    db_api_send_edit_ex (const xmlChar *edit_target,
                         const xmlChar *edit_operation,
                         const xmlChar *edit_xml_value,
                         const xmlChar *patch_id_str,
                         boolean system_edit);


/********************************************************************
* FUNCTION db_api_send_edit_full
*
* Create a YANG Patch edit request and send it to the DB-API service
* on the main server.
*
* The content should represent the intended target resource
* as specified in YANG-API (NOT RESTCONF)
* Only the data resource identifier is provided, not the
* API wrapper identifiers (so this can change when RESTCONF is supported)
* Example leaf:
*
*   edit_target == /interfaces/interface/eth0/mtu
*   edit_value == "<mtu>9000</mtu>
*   edit_operation == "merge"
*   patch_id_str == "my-patch-x01'
*   system_edit == true
*
* Example list:
*
*   edit_operation == <operation string>
*           "create"
*           "delete"
*           "insert"
*           "merge"
*           "move"
*           "replace"
*           "remove"
*
*   edit_target == /interfaces/interface/eth0/ipv4
*   edit_value == "<ipv4>
*                    <enabled>true</enabled><
*                    <forwarding>true</forwarding>
*                    <address>204.102.10.4</address>
*                    <prefix-length>24</prefix-length>
*                  </ipv4>"
*
* INPUTS:
*   edit_target == target resource (YANG-API path expression)
*   edit_operation == edit operation (create merge replace delete remove)
*   edit_xml_value == XML payload in string form, whitespace allowed
*                     MAY BE NULL if no value required (delete remove))
*   patch_id_str == string to use as the patch ID
*                == NULL to use the default patch-id field
*   system_edit == TRUE if this edit is from the system and should
*                  bypass access control enforcement
*               == FALSE if this edit is from a user and should not
*                  bypass access control enforcement
*   insert_point is a string like the target except a different instance
*             of the same list of leaf-list; only for before, after
*   insert_where == <insert enum string>
*           "before"
*           "after"
*           "first"
*           "last"
* RETURNS:
*   status
*********************************************************************/
extern status_t
    db_api_send_edit_full (const xmlChar *edit_target,
                           const xmlChar *edit_operation,
                           const xmlChar *edit_xml_value,
                           const xmlChar *patch_id_str,
                           boolean system_edit,
                           const xmlChar *insert_point,
                           const xmlChar *insert_where);


/********************************************************************
* FUNCTION db_api_check_edit
*
* Check on the status of an edit in progress
* RETURNS:
*   status:
*
*     ERR_NCX_NOT_FOUND if final status and no message
*        response is pending
*     ERR_NCX_SKIPPED if final status is not known yet
*     NO_ERR if there is a last-completed operation that
*        completed with an OK response
*     <errcode> if there is a last-completed operation that
*        completed with an ERROR response
*********************************************************************/
extern status_t
    db_api_check_edit (void);



 Example db-api-app send_edit from ap-api-app.c


/********************************************************************
* FUNCTION send_test_edit
*
* This is an example send edit function.
* The module ietf-interfaces needs to be loaded for this to work
*********************************************************************/
static void
    send_test_edit (void)
{
    /* mef-cfm test */
    const xmlChar *path_str = (const xmlChar *)"/maintenance-domain/mdTest";
    const xmlChar *operation_str = (const xmlChar *)"merge";
    const xmlChar *value_str = (const xmlChar *)
        "<cfm:maintenance-domain xmlns:cfm='http://metroethernetforum.org/"
        "ns/yang/mef-cfm'><cfm:id>mdTest</cfm:id><cfm:name-type>character"
        "-string</cfm:name-type><cfm:name>mdTestName</cfm:name><cfm:md-le"
        "vel>4</cfm:md-level><cfm:mhf-creation>none</cfm:mhf-creation>"
        "<cfm:id-permission>none</cfm:id-permission></cfm:maintenance"
        "-domain>";

    const xmlChar *patch_id_str = NULL;
    boolean system_edit = FALSE;
    status_t res = db_api_send_edit_ex(path_str,
                                       operation_str,
                                       value_str,
                                       patch_id_str,
                                       system_edit);
    if (res != NO_ERR) {
        log_error("\nSend test edit failed %s %s = %s (%s)\n",
                  operation_str, path_str, value_str,
                  get_error_string(res));
    } else if (LOGDEBUG) {
        log_debug("\nSend test edit OK  %s %s = %s\n",
                  operation_str, path_str, value_str);
    }

}  /* send_test_edit */


The db-api-app main function example:


/********************************************************************
* FUNCTION main
*
* This is an example main function.
*
* RETURNS:
*   0 if NO_ERR
*   status code if error connecting or logging into ncxserver
*********************************************************************/
int main (int argc, char **argv)
{
#ifdef MEMORY_DEBUG
    mtrace();
#endif

    /* 1) setup yumapro messaging service profile */
    status_t res = ycontrol_init(argc, argv,
                                 (const xmlChar *)"subsys1");

    /* 2) register services with the control layer */
    if (res == NO_ERR) {
        res = db_api_register_service();
    }

    /* 3) do 2nd stage init of the control manager (connect to server) */
    if (res == NO_ERR) {
        res = ycontrol_init2();
    }

    useconds_t usleep_val = 100000;  // 100K micro-sec == 1/10 sec
    boolean done = FALSE;

    /* 4) call ycontrol_check_io periodically from the main program
     * control loop
     */
#ifdef DB_API_APP_DEBUG
    int id = 0;
#endif  // DB_API_APP_DEBUG

    boolean test_done = FALSE;

    while (!done && res == NO_ERR) {
#ifdef DB_API_APP_DEBUG
        if (LOGDEBUG3) {
            log_debug3("\ndb-api-app: checking ycontrol IO %d", id++);
        }
#endif  // DB_API_APP_DEBUG

        res = ycontrol_check_io();

        if (ycontrol_shutdown_now()) {
            // YControl has received a <shutdown-event>
            // from the server subsystem is no longer active
            // could ignore or shut down YControl IO loop
            done = TRUE;
        }

        // Using sleep to represent other program work; remove for real
        if (!done && res == NO_ERR) {
            (void)usleep(usleep_val);
        }

        if (db_api_service_ready() && !test_done) {
            send_test_edit();
            test_done = TRUE;
        }

    }

    /* 5) cleanup the control layer before exit */
    ycontrol_cleanup();

#ifdef MEMORY_DEBUG
    muntrace();
#endif

    return (int)res;

}  /* main */