yangcli-pro Interface

The yangcli-pro client application supports external yangcli functions.

The external callback functions must be registered with yangcli-pro.

External Show Callback Functions

The function 'ycli_show_extern_register_callbacks' in 'yangcli/yangcli_show_extern.h' is used by the external code to register its own show callback functions. The show functions are used by the yangcli-pro.

/********************************************************************
* FUNCTION ycli_show_extern_register_callbacks
*
* Register the external callbacks for show implementation
*
* INPUTS:
*    module   == YANG module used for this function
*    showfn_keyword == key word used for this function.
*    showfn ==  show function callback
*    cookie == context pointer (may be null)
* RETURNS:
*   status of the function registration.
*
*********************************************************************/
extern status_t ycli_show_extern_register_callbacks(
                                    const xmlChar* module,
                                    const xmlChar* keyword,
                                    ycli_show_extern_fn_t showfn,
                                    void *cookie);

If the external method is selected in the yangcli-pro initialization then the callback function MUST be provided.

The function must be registered:

  • show fn: Invoke the a vendor specific function. The yangcli_show_extern_fn_t template is used for this callback.

The following code snippet shows the API template definitions from yangcli/yangcli_show_extern.h.

/********************************************************************
*
* Callback yangcli_show_extern_fn_t to handle external show
* functions.
*
* INPUTS:
*   server_name == The current server name.
*   rpc == RPC method for the show command being processed.
*   line == CLI line input.
*   session_name == The name of the current session.
*   valset == valset filled in with parameters for the specified RPC
*   mode == help_mode_t(none, brief, normal, full)
*   cookie == context pointer passed in register time, (may be null)
*
* RETURNS:
*   Status: NO_ERR or error.
*********************************************************************/
typedef status_t
    (*yangcli_show_extern_fn_t) (const xmlChar *server_name
                                    obj_temp_t    *rpc,
                                    const xmlChar *line,
                                    const xmlChar *session_name
                                    const val_value_t *valset,
                                    help_mode_t mode,
                                    void *cookie);

Example External yangcli Command

The following example code is available in 'example-show.cpp'. It shows some dummy external functions and how they are registered during initialization.

/*
 * Copyright (c) 2012 - 2017, YumaWorks, Inc., All Rights Reserved.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*  FILE: example-show.c

  Example External Show Library

*********************************************************************
*                                                                   *
*                     I N C L U D E    F I L E S                    *
*                                                                   *
*********************************************************************/

#include <string.h>
#include <stdlib.h>
#include <xmlstring.h>

/* always include procdefs.h before all other YumaPro files */
#include "procdefs.h"

/* these H files can be in any order */
#include "example-show.h"
#include "log.h"
#include "ncx.h"
#include "ncxmod.h"
#include "ncxtypes.h"
#include "obj.h"
#include "status.h"
#include "val.h"
#include "xml_util.h"
#include "yangcli.h"
#include "yangcli_cmd.h"
#include "yangcli_control.h"
#include "yangcli_libshow.h"
#include "yangcli_session_cb.h"
#include "yangcli_term.h"



#define MODNAME (const xmlChar *)"example-fan"
#define FAN (const xmlChar *)"fan"
#define DIAGNOSTICS (const xmlChar *)"diagnostics"
#define EXAMPLE_CMDSTR (const xmlChar *)"example-cmd"

/* comment out to disable show fan command */
#define SHOW_FAN 1

/* comment out to disable show version command */
#define SHOW_VER 1

/* remove comment to enable term display hook example */
// #define TERM_API 1

/* comment out to disable top-level command example-cmd */
#define EXAMPLE_CMD 1

static ncx_module_t *mymod = NULL;


/************  Example External Yangcli external call Hooks ****************/

#ifdef SHOW_FAN
/********************************************************************
* FUNCTION show_fan
*
* INPUTS:
*    server_name == the server name.
*    rpc == RPC method for the show command
*    line == CLI input in progress
*    session_name == the current session name.
*    valset == value set to check if not NULL
*    mode ==  HELP_MODE_NONE, HELP_MODE_BRIEF, HELP_MODE_NORMAL,
*             HELP_MODE_DETAIL
*    cookie == context pointer (may be null)
* RETURNS:
*   status
*********************************************************************/
static status_t
     show_fan (
              const xmlChar *server_name,
              obj_template_t *rpc,
              const xmlChar *line,
              const xmlChar *session_name,
              val_value_t *valset,
              help_mode_t mode,
              void *cookie)
{
    /* parms not used */
    (void)server_name;
    (void)rpc;
    (void)line;
    (void)session_name;
    (void)cookie;

    /* get the fan number
     * yangcli returns a union type as a string!
     */
    const xmlChar *fan_num = (const xmlChar *)"1";
    val_value_t *fanval = val_find_child(valset, MODNAME, FAN);
    if (fanval) {
        if (VAL_TYPE(fanval) == NCX_BT_STRING) {
            if (!val_all_whitespace(VAL_STR(fanval))) {
                /* fan_num should be a valid number string */
                fan_num = VAL_STR(fanval);
            }
        } else {
            // some sort of error
            ;
        }
    } // else error mandatory parm

    /* get the value, there is no value to get for 'empty' */
    val_value_t *diagval =
        val_find_child(valset, MODNAME, DIAGNOSTICS);

    /* print banner for fan */
    log_write("\nReport for Fan %s", fan_num);
    log_write("\n  put fan status here...");

    if (mode != HELP_MODE_BRIEF) {

        /* only normal of full modes print diagnostics */
        log_write("\n  put more fan status here...");

        if (mode == HELP_MODE_FULL) {
            log_write("\n  put even more fan status here...");
        }

        if (diagval) {
            /* print last diagnostics report */
            log_write("\nLast Diagnostics Report for Fan %s:", fan_num);
        }
    }

    log_write("\n");

    server_cb_t *server_cb = get_default_server_cb();
    if (server_cb == NULL) {
        return ERR_NCX_OPERATION_FAILED;
    }

    session_cb_t *session_cb = get_cur_session_cb(server_cb);
    if (session_cb == NULL) {
        return ERR_NCX_OPERATION_FAILED;
    }

    if (!session_connected(session_cb)) {
        /* cannot send commands to server */
        return NO_ERR;
    }

    /* get data from the server */
    xmlChar *getstring =
        xml_strdup((const xmlChar *)"sget /modules-state/module-set-id");
    if (!getstring) {
        return ERR_INTERNAL_MEM;
    }


    status_t res =
        conn_command(server_cb, session_cb, getstring, FALSE, FALSE);
    if (res != NO_ERR) {
        log_error("\nError: send %s failed %s",
                  getstring, get_error_string(res));
    }
    m__free(getstring);

    getstring =
        xml_strdup((const xmlChar *)"sget /netconf-state/sessions --nofill");
    if (!getstring) {
        return ERR_INTERNAL_MEM;
    }

    res = conn_command(server_cb, session_cb, getstring, FALSE, FALSE);
    if (res != NO_ERR) {
        log_error("\nError: send %s failed %s",
                  getstring, get_error_string(res));
    }
    m__free(getstring);

    return res;

} /* show_fan */

#endif  // SHOW_FAN


#ifdef SHOW_VER
/********************************************************************
* FUNCTION show_version
*
* INPUTS:
*    server_name == the server name.
*    rpc == RPC method for the show command
*    line == CLI input in progress
*    session_name == the current session name.
*    valset == value set to check if not NULL
*    mode ==  HELP_MODE_NONE, HELP_MODE_BRIEF, HELP_MODE_NORMAL,
*             HELP_MODE_DETAIL
*    cookie == context pointer (may be null)
* RETURNS:
*   status
*********************************************************************/
static status_t
     show_version (
              const xmlChar *server_name,
              obj_template_t *rpc,
              const xmlChar *line,
              const xmlChar *session_name,
              val_value_t *valset,
              help_mode_t mode,
              void *cookie)
{
    /* parms not used */
    (void)server_name;
    (void)rpc;
    (void)line;
    (void)session_name;
    (void)cookie;

    /* no input to get for <version> leaf
     * just print version line
     */
    log_write("\nExample Version: 10.1");

    if (mode != HELP_MODE_BRIEF) {

        /* only normal of full modes print diagnostics */
        log_write("\n  Release: A4");

        if (mode == HELP_MODE_FULL) {
            log_write("\n  Firmware: R12.4.001");
        }
    }

    log_write("\n");

    return NO_ERR;

} /* show_version */

#endif  // SHOW_VER


#ifdef TERM_API

/* example terminal output test API
 */
static boolean
    term_api_test_fn (void *session_cb,
                      const char *command_name,
                      boolean reply_output)
{
    /* current session control block if needed */
    session_cb_t *cb = (session_cb_t *)session_cb;
    (void)cb;

    if (reply_output == FALSE) {
        return FALSE;
    }

    if (!strcmp(command_name, "get") ||
        !strcmp(command_name, "get-config")) {

        return TRUE;
    }

    return FALSE;

}  /* term_api_test_fn */


/* example terminal output API
 * This API alters the command or server output so
 * yangcli_term can process the More and Pipe commands
 */
static status_t
    term_api_fn (void *session_cb,
                 const char *in_filespec,
                 const char *out_filespec)
{
    /* current session control block if needed */
    session_cb_t *cb = (session_cb_t *)session_cb;
    (void)cb;

    /* get file into a buffer
     * this is just one way to process the input;
     * a line-by-line approach could be used to save memory
     */
    xmlChar *in_buff = NULL;
    status_t res = ncx_file_to_buffer(in_filespec, &in_buff);
    if (in_buff == NULL || res != NO_ERR) {
        m__free(in_buff);
        return res;
    }

    /* change all the '{' and '}' chars to spaces just
     * as an example of altering the output
     */
    xmlChar *p = in_buff;
    while (*p) {
        if (*p == '{' || *p == '}') {
            *p = ' ';
        }
        p++;
    }

    /* write altered buffer out to a file */
    res = ncx_buffer_to_file(out_filespec, in_buff);

    m__free(in_buff);

    return res;

}  /* term_api_fn */


#endif  // TERM_API


#ifdef EXAMPLE_CMD
/********************************************************************
 * FUNCTION do_example_cmd (local RPC)
 *
 * Do Example Command
 *
 * INPUTS:
 *    server_cb == server control block to use
 *    session_cb == session control block to use
 *    rpc == RPC method for the example-cmd command
 *    line == CLI input in progress
 *    len == offset into line buffer to start parsing
 *
 * RETURNS:
 *   status
 *********************************************************************/
static status_t
    do_example_cmd (server_cb_t *server_cb,
                    session_cb_t *session_cb,
                    obj_template_t *rpc,
                    const xmlChar *line,
                    uint32 len)
{
    (void)rpc;

    status_t res = NO_ERR;
    val_value_t *valset =
        get_valset(server_cb, session_cb, rpc, &line[len], &res);
    if (valset && (res == NO_ERR)) {
        val_value_t *parm1 =
            val_find_child(valset, MODNAME, (const xmlChar *)"parm1");
        if (parm1) {
            log_debug("\nGot parm1=%s", VAL_STR(parm1));
        }

        val_value_t *parm2 =
            val_find_child(valset, MODNAME, (const xmlChar *)"parm2");
        if (parm2) {
            log_debug("\nGot parm2=%d", VAL_INT32(parm2));
        }

        /* do something with the parameters */
    }

    val_free_value(valset);

    return res;

}  /* do_example_cmd */
#endif  // EXAMPLE_CMD


/****************  Required Show Library Hooks *******************/

/* show init callback
 * init show call
 * INPUTS: void
 * RETURNS:
 *  status; error will abort startup
 */
extern "C" status_t yp_show_init (void)
{
    status_t res = NO_ERR;

    log_debug("\nyp_show init\n");

#ifdef TERM_API
    ycli_register_term_callback(term_api_test_fn, term_api_fn);
#endif  // TERM_API

#if defined(SHOW_FAN) || defined(SHOW_VER) || defined(EXAMPLE_CMD)
    /*
     * Example: load a fan module for show fan function.
     */
    res = ncxmod_load_module(MODNAME,
                             NULL,   // revision
                             NULL,   // savedevQ
                             &mymod);

#endif  // SHOW_FAN or SHOW_VER or EXAMPLE_CMD

    /*
     * Example: Register a show function with yangcli-pro
     * module name: example-fan for example-fan.yang
     * key word: fan
     * function: show_fan
     */

    if (res == NO_ERR) {
#ifdef SHOW_FAN
        /* Create a cookie context if any or NULL */
        void *cookie_show_fan = NULL;
        ycli_show_extern_register_callbacks(MODNAME,
                                            (const xmlChar *)"fan",
                                            show_fan,
                                            cookie_show_fan);
#endif  // SHOW_FAN

#ifdef SHOW_VER
        /* Create a cookie context if any or NULL */
        void *cookie_show_ver = NULL;
        ycli_show_extern_register_callbacks(MODNAME,
                                            (const xmlChar *)"version",
                                            show_version,
                                            cookie_show_ver);
#endif  // SHOW_VER

#ifdef EXAMPLE_CMD
        server_cb_t *server_cb = get_default_server_cb();
        if (server_cb == NULL){
            res = ERR_NCX_NOT_FOUND;
        } else {
            res = register_command(server_cb,
                                   MODNAME,
                                   (const xmlChar *)"example-cmd",
                                   do_example_cmd,
                                   TRUE,   // is_top_cmd
                                   TRUE,   // yangcli_ok
                                   TRUE,   // ypshell_ok
                                   FALSE); // ypserver_ok (not used)
        }
#endif  // EXAMPLE_CMD

    } else {
       log_debug("\nyp_show_init: return ERROR\n");
    }

    return res;

}  /* yp_show_init */


/* show cleanup callback
 * this callback is invoked once during yancli_cleanup
 */
extern "C" void yp_show_cleanup (void)
{
    log_debug("\nyp_show cleanup\n");

} /* yp_show_cleanup */


/* END example-show.c */