Permanent items in CDB DB?

Is it possible to mark items as “permanent” - i.e., don’t let the user delete/remove them after they have been created? It doesn’t appear validate is called on deleted items, I just receive the MOP_DELETED on the subscription callback, but by then it’s too late to stop it (or is there a way to abort the transaction…then I need to deal with rollback I suppose). Anyway, just wondering if there is something else I’m missing that I can tag/mark the entries as “undeletable”?

There is no way to mark items in YANG as “permanent” but there are way to achieve your requirement using AAA for example. It all depends on how the elements you mentioned are being created.

For example, if the configuration you want to persist in the database and block users from modifying, is configuration that is tied to your device and is fixed, then you can use init files to provide that configuration as “factory” configuration and block all users from deleting/updating it.

If the configuration can only determined once the system is up, you can write that configuration programatically in CDB and write AAA data rules along with it to control user permissions.

If the configuration is user provided, you will have to write AAA rules to control those permissions in a separate transaction or, in the same transaction using transaction hooks (Chapter 10.6 talks about Hooks).

Regarding validation of deletes, the practice is to validate configuration data that will be eventually committed and not the lack of configuration, the delete can be tracked in validation if you validate the parent node which will be MOP_MODIFIED in this case.

Usually users want to block the delete operation on certain elements that are being used or referred too in other parts of the configuration, for this scenario, we suggest creating constraints on the elements using leafref for example. This is ConfD enforces the delete rule without having to write extra code. This is just one case. There might be others where a must statement would do.

Ah, hadn’t thought of watching the parent node…that seems like in my case may be cleanest way to deal with it (just iterate over all the children and make sure none have disappeared when the parent is touched). Let me go explore that, thanks!

You may consider using the CDB two-phase subscriptions mechanism to abort the transaction, perhaps in the prepare phase of the transaction.

I was able to kludge it with the validation of the container object…although it proved to be more difficult than I thought because I kept running into bugs with the maapi_ commands when trying to iterate over a list (yea, those just don’t work…)

Hi mgr, can you provide a bit more detailed feedback and we’ll take a look at the issues you are referring to in the maapi_ iterate related commands?
Can you give a code example / snippet of what’s not working?

1 Like

Unfortunately, the code has been replaced with the work around, so I would need to recreate it from scratch, so going from memory here…but in a nutshell, I was calling from a validate callback (using the linuxcfg shell code/framework):

    int sock = *(int *)(tctx->t_opaque);
    int handle = tctx->thandle;
    len = maapi_num_instances(sock, handle, "/path/to/my-list-object");
    for (i = 0; i < len; i++) {
        maapi_pushd(sock, handle, "/path/to/my-list-object[%d]", i));
                // Try to fetch object here
        maapi_popd(sock, handle);

The call to maapi_num_instances() would return the correct count, but the maapi_pushd() would barf with an error about expecting a key after /path/to/my-list-object. The interesting thing I thought was the index it was printing in the error message would go [0] then [1]… [8] then go funky like [~] [$] then go back to numbers, then go to alpha. It was like the format string was not being processed correctly despite being a simple %d. Same thing happened without trying to do the push/pop and just directly fetching elements. When I switched to doing it with keys instead of indexes (which I could only do because I knew the keys out of band…since I can’t’ query the keys)

Should be maapi_pushd(sock, handle, "/path/to/my-list-object{%d}", i));

For more on keypaths, see ConfD UG Chapter CDB - The ConfD XML Database --> Using keypaths

Except, I don’t know the keys (and they’re not numeric)… My understanding is that the {N} syntax requires the exact key to retrieve (get me the item with key value N), where the [N] syntax says get me the element at the Nth position. Since I don’t KNOW the keys (I’m trying to walk all the objects in a list that is user generated - incidentally, the key is a string in my case), I’m left with iterating by index…or am I completely missing the boat here?

From the user guide:

The paths for MAAPI work like paths for CDB (see confd_lib_cdb(3)) with the exception that the bracket
notation ‘[n]’ is not allowed for MAAPI paths.

Instead of using maapi_pushd you can use the example below to traverse a list from your validate code.

An example:

maapi_init_cursor(sock, th, &mc, “/servers/server”);
while (mc.n != 0) {
struct in_addr ip;
uint16_t port;
char tmpbuf[BUFSIZ];
maapi_get_ipv4_elem(sock, th, &ip,
maapi_get_u_int16_elem(sock, th, &port,
printf (“server name=%s ip=%s port=%d\n”,
tmpbuf, inet_ntoa(ip), port);

1 Like

Much happier with that, but the special %x can’t be used if the type is an enumeration can it (i.e., the list key is an enum)? When I tried that, I blew up. Also seems the numerical value can’t be used and instead (can’t do “{%d}”) I need to look up the correct string to replace the enum with and do the index as a %s. This works for me, just wondering if this is the best/right way to do it.

‘%x’ can be used on enums too. E.g. when the list key is an enum.
The numerical value ‘%d’ can’t be used since the value we use is a confd_value_t data type.
In nabils example above, if the list key was an enum the YANG model would look something like this:

container servers {
  list server {
    key name;
    leaf name {
      type enumeration {
        enum name1;
        enum name2;
        enum name3;
    leaf ip {
      type inet:ip-address;
      mandatory true;
    leaf port {
      type inet:port-number;
      mandatory true;

and after creating some list entries using the three enum values the printout from the example would look something like this:

server name=enum<0> ip= port=2000
server name=enum<1> ip= port=2002
server name=enum<2> ip= port=2001

From the ConfD UG:

We can use the following modifiers:
%d requiring an integer parameter (type int) to be substituted.
%u requiring an unsigned integer parameter (type unsigned int) to be substituted.
%s requiring a char* string parameter to be substituted.
%ip4 requiring a struct in_addr* to be substituted.
%ip6 requiring a struct in6_addr* to be substituted.
%x requiring a confd_value_t* to be substituted.
%*x requiring an array length and a confd_value_t* pointing to an array of values to be substituted.
%h requiring a confd_hkeypath_t* to be substituted.
%*h requiring a length and a confd_hkeypath_t* to be substituted.