How to set length in a leaf?

I have a container with a string and another with a int32. i need to set my string to a name like “Billy” and calculate the length in the second parameter.
In my configuration i need to have “name Billy length 5” but in ConfD i write >>name Billy
I supose i need to use “(string-length(/name)”; but i don’t really know how that’s works.

  container name {
    leaf name {
      type string {
        length "1..35";
        tailf:info "WORD;;name:max 35 digits [a-z,A-Z]";
      }
      tailf:cli-drop-node-name;
    }
    leaf length {
      type uint32 {
        range "0..35";
        tailf:info "<0-35>;;Prefix length : max 35 digits";
      }
      tailf:cli-optional-in-sequence;
    }
    tailf:info "Set name";
    tailf:cli-compact-syntax;
    tailf:cli-sequence-commands;
  }
  }

It is not recommended to self configure a leaf value as a result of configuring another leaf value. This will confuse any northbound network management software or orchestrating software as the self configured leaf value isn’t part of the edit-config transaction. However, it will be OK to do so if the self-configured leaf node is made hidden, such as with the tailf:hidden YANG annotation. To automatically configure the length node in your data model, you will need to use ConfD’s set hooks feature as described in section 10.6, Hooks, of the ConfD User Guide.

xaitai, do you have some exemple?
Thanks a lot for your answer.

If you modify your YANG file as follows:

module test {
  namespace "http://www.example.com/yang/test";
  prefix "te";

  import tailf-common {
    prefix tailf;
  }

  container name {
    leaf name {
      tailf:callpoint name-hook {
        tailf:set-hook subtree;
      }
      type string {
        length "1..35";
      }
    }
    leaf length {
      //tailf:hidden full;
      type uint32 {
        range "0..35";
      }
    }
  }
}

The above YANG model makes use of the set hook feature in which the hook function is invoked as the name field is being modified in order to set the value of the length leaf element.

An example set hook client code for the above YANG model:

#include <string.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>

#include <confd.h>
#include <confd_maapi.h>

#include "test.h"

static int debuglevel = CONFD_TRACE;

static struct confd_daemon_ctx *dctx;
static int ctlsock;
static int workersock;
static struct confd_trans_cbs tcb;
static struct confd_data_cbs name_hook;

static int msock;
static struct sockaddr_in confd_addr;

static void _OK(int rval, int line)
{
    if (rval != CONFD_OK) {
        fprintf(stderr, "%s:%d: error not CONFD_OK: %d : %s \n",
                __FILE__, line, confd_errno, confd_lasterr());
        abort();
    }
}

#define OK(rval) _OK(rval, __LINE__)

static int do_maapi_connect(void)
{
    int sock;

    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) {
        confd_fatal("Failed to open socket\n");
    }

    if (maapi_connect(sock, (struct sockaddr*)&confd_addr,
                      sizeof (struct sockaddr_in)) < 0) {
        confd_fatal("Failed to maapi_connect() to confd \n");
    }
    return sock;
}

static int init_trans(struct confd_trans_ctx *tctx)
{
    OK(maapi_attach(msock, te__ns, tctx));
    confd_trans_set_fd(tctx, workersock);
    return CONFD_OK;
}

static int finish_trans(struct confd_trans_ctx *tctx)
{
    OK(maapi_detach(msock, tctx));
    return CONFD_OK;
}

static int name_hook_set_elem(struct confd_trans_ctx *tctx,
                              confd_hkeypath_t *kp,
                              confd_value_t *newval)
{

    if ((CONFD_GET_XMLTAG(&kp->v[0][0]) == te_name)) {
        int length = strlen((char*)CONFD_GET_BUFPTR(newval));
        confd_value_t v;
        CONFD_SET_UINT32(&v, length);
        OK(maapi_set_elem(msock, tctx->thandle, &v, "/name/length"));
    }

    return CONFD_OK;
}

int main(int argc, char **argv)
{
    int c;
    int num = -1;

    while ((c = getopt(argc, argv, "n:tdpsr")) != -1) {
        switch(c) {
        case 'n':
            num = atoi(optarg);
            break;
        case 't':
            debuglevel = CONFD_TRACE;
            break;
        case 'd':
            debuglevel = CONFD_DEBUG;
            break;
        case 'p':
            debuglevel = CONFD_PROTO_TRACE;
            break;
        case 's':
            debuglevel = CONFD_SILENT;
            break;
        }
    }

    confd_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    confd_addr.sin_family = AF_INET;
    confd_addr.sin_port = htons(CONFD_PORT);

    /* Initialize confdlib */

    confd_init((char *)"name-hook", stderr, debuglevel);

    /* Load data model schemas from to ConfD */

    if ((dctx = confd_init_daemon("name-hook")) == NULL)
        confd_fatal("Failed to initialize confd\n");

    if ((ctlsock = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
        confd_fatal("Failed to open ctlsocket\n");

    if (confd_load_schemas((struct sockaddr*)&confd_addr,
                           sizeof (struct sockaddr_in)) != CONFD_OK) {
        confd_fatal("Failed to load schemas from confd\n");
    }

    /* MAAPI connect to ConfD */

    msock = do_maapi_connect();

    /* Create the first control socket, all requests to */
    /* create new transactions arrive here */

    if (confd_connect(dctx, ctlsock, CONTROL_SOCKET,
                      (struct sockaddr*)&confd_addr,
                      sizeof (struct sockaddr_in)) < 0)
        confd_fatal("Failed to confd_connect() to confd \n");

    /* Also establish a workersocket, this is the most simple */
    /* case where we have just one ctlsock and one workersock */

    if ((workersock = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
        confd_fatal("Failed to open workersocket\n");
    if (confd_connect(dctx, workersock, WORKER_SOCKET,
                      (struct sockaddr*)&confd_addr,
                      sizeof (struct sockaddr_in)) < 0)
        confd_fatal("Failed to confd_connect() to confd \n");

    tcb.init = init_trans;
    tcb.finish = finish_trans;
    confd_register_trans_cb(dctx, &tcb);

    /* Register the name hook */

    name_hook.set_elem   = name_hook_set_elem;

    strcpy(name_hook.callpoint, "name-hook");

    if (confd_register_data_cb(dctx, &name_hook) == CONFD_ERR)
        confd_fatal("Failed to register hook cb \n");

    if (confd_register_done(dctx) != CONFD_OK)
        confd_fatal("Failed to complete registration \n");


    while (1) {
        struct pollfd set[2];
        int ret;

        set[0].fd = ctlsock;
        set[0].events = POLLIN;
        set[0].revents = 0;

        set[1].fd = workersock;
        set[1].events = POLLIN;
        set[1].revents = 0;


        if (poll(&set[0], 2, -1) < 0) {
            perror("Poll failed:");
            continue;
        }

        if (set[0].revents & POLLIN) {
            if ((ret = confd_fd_ready(dctx, ctlsock)) == CONFD_EOF) {
                confd_fatal("Control socket closed\n");
            } else if (ret == CONFD_ERR && confd_errno != CONFD_ERR_EXTERNAL) {
                confd_fatal("Error on control socket request: %s (%d): %s\n",
                            confd_strerror(confd_errno),
                            confd_errno, confd_lasterr());
            }
        }
        if (set[1].revents & POLLIN) {
            if ((ret = confd_fd_ready(dctx, workersock)) == CONFD_EOF) {
                confd_fatal("Worker socket closed\n");
            } else if (ret == CONFD_ERR && confd_errno != CONFD_ERR_EXTERNAL) {
                confd_fatal("Error on worker socket request: %s (%d): %s\n",
                            confd_strerror(confd_errno),
                            confd_errno, confd_lasterr());
            }
        }

    }
}

A sample CLI session output:

$ confd_cli -C --user=admin

admin connected from 127.0.0.1 using console on localhost
localhost# show running-config name
% No entries found.
localhost# config
Entering configuration mode terminal
localhsot(config)# name name David
localhost(config)# show configuration name
name name David
name length 5
localhost(config)# commit
Commit complete.

The debug output from the set hook client code corresponding to the above CLI session:

TRACE New user session: 11 for user:admin ctx:cli --> CONFD_OK
TRACE CALL trans init(thandle=9,mode="rw",db=running)TRACE MAAPI_ATTACH  --> CONFD_OK
 --> CONFD_OK
TRACE CALL data set_elem(thandle=9, /name/name, David)TRACE MAAPI_SET_ELEM /name/length --> CONFD_OK
 --> CONFD_OK
TRACE CALL trans finish(thandle=9)TRACE MAAPI_DETACH  --> CONFD_OK
 --> CONFD_OK
TRACE CALL trans init(thandle=31,mode="rw",db=running)TRACE MAAPI_ATTACH  --> CONFD_OK
 --> CONFD_OK
TRACE CALL data set_elem(thandle=31, /name/name, David)TRACE MAAPI_SET_ELEM /name/length --> CONFD_OK
 --> CONFD_OK
TRACE CALL trans finish(thandle=31)TRACE MAAPI_DETACH  --> CONFD_OK
 --> CONFD_OK
TRACE Close user sess 11
 --> CONFD_OK

When you are done with debugging your code, the length leaf element in your data model can be hidden using the commented out tailf:hidden annotation shown above as described in section 10.7, Hidden Data, of the ConfD User Guide.