Deleting a list entry based on its child continer emptiness

hi Experts,

i have a model which has list and child container,

list A {
key “name”;
leaf name { type sring;}
container CON;
}

Now i can have leafs inside the CONTAINER Deleted in the RPC . I want to make sure when the CON becomes empty , the list entry is also deleted.
Can i do this with a must statement ?

Or in the worst case , I would like to return a error to the user when they delete the last leaf in the container, also delete the list entry .

Many Thanks.

A must statement is applicable here - you need to require that CON has children when an instance of A exists, i.e. something like must "CON/." under A (note that this applies also to sub-containers). A RPC that tries to delete everything under CON but not the A instance itself would be refused with an error reply (and similarly a RPC that creates an A instance without configuring something under CON).

This also means that if anyone in the future augments your container A , the must statement would use that augmented nodes too, so if you actually have a set of leaves under A such that at least one of them must be configured, you better enumerate them in your must statement.

It is possible to implement a transaction hook that would delete an empty list instance instead of returning an error. This is not an advisable approach though, you are effectively changing the configuration under the operator’s or management software hands.

1 Like

Perfect!!!.

Thank you very much .I was able to set a error message in the rpc reply based on the must.
Yes you are right deleteing the list in the server could cause a difference betweenthe users config and the confd DB .

By the way , I was not able to check the xpath “CON/.” whereas “CON/leaf1” worked .

Is there a way to check all the leafs under CON at once ? please note that the CON is not a presence container.

Another question … is it possible to have two diffrent error-message based on the actions (one for create and other for delete)

Sorry, the XPath expression should have been "CON/*" - this tells ConfD to take all children of CON into consideration. This will also force you to add tailf:dependency statement, I believe tailf:dependency CON; should be enough.

You cannot have two different error messages, I’m afraid - the point is to verify the configuration, disregarding how it was created.

Great , Thanks for the confirmation.
By the way , how do i refer the nodes in same level in the xpath but in the case staements e.g

choice ch {

case a{
leaf a;
}

case b {
leaf b;
/* I did the following */
must (not("…/a"))
–> here i want to check if leaf a has already been created in this choice
}

}

That must statement will have no affect as leaf “a” will have been deleted when you set leaf “b” before the must statement check.

I believe you are looking for something like this:

leaf a {
  type string;
}
leaf b {
  type string;
  when 'not(../a)';
}

Thanks cohult .Very useful
That was my guess too. So the ‘leaf a’ is deleted before ‘leaf b’ is created and there is no way check what was set before .

The above example did not work through NETCONF RPC though !!! The RPC for setting leaf b passed when leaf a was already set (it was under choice though)

So what im looking for is

leaf all {
tailf:cli-reset-container;
type string;
}

leaf opt1 {
type string;
must “not(…/all)”
}

leaf opt2 {
type string;
must “not(…/all)”
}

If user creates opt1 or opt2 , when “all” is already set , throw a error stating that “all” is set

So any time user configures ‘all’ , opt1 and opt2 are deleted, if they exist.
So should i use tailf:cli-reset-container on all and must statements on opt1 and opt2 ?

Can u clarify that? Something like this?:

module choice-must {
  namespace "urn:example";
  prefix if;
  container x {
    choice ch {
      case a {
        leaf a { type empty; }
      }
      case b {
        leaf b { type empty; }
      }
    }
    leaf c {
      type empty;
      when 'not(../a)';
    }
  }
}
$ confd --version
7.3
$ netconf-console --edit-config=-<<<'<x xmlns="urn:example"><a/></x>'
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
  <ok/>
</rpc-reply>
$ netconf-console --edit-config=-<<<'<x xmlns="urn:example"><c/></x>'
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
  <rpc-error>
    <error-type>application</error-type>
    <error-tag>unknown-element</error-tag>
    <error-severity>error</error-severity>
    <error-path xmlns:if="urn:example">
    /rpc/edit-config/config/if:x/if:c
  </error-path>
    <error-message xml:lang="en">/x/c: the 'when' expression "not(../a)" failed</error-message>
    <error-info>
      <bad-element>c</bad-element>
    </error-info>
  </rpc-error>
</rpc-reply>

You seem to want to have this work over NETCONF too, so using a CLI extension will be a bad idea. Become friends with the YANG standard “when” statement instead and keep it simple.

7.21.5. The “when” Statement

leaf all {
  type string;
}
leaf opt1 {
  type string;
  when 'not(../all)';
}
leaf opt2 {
  type string;
  when 'not(../all)';
}

Thanks again Cohult …

I wanted to achieve something like the below
module choice-must {
namespace “urn:example”;
prefix if;
container x {
choice ch {
case a {
leaf a { type empty; }
}
case b {
leaf b { type empty; when ‘not(…/a)’; }
}
}

}
}

And what function would the choice around leaf a and b have? Can you see how the suggested alternative (no choice) is simpler and thus a better solution (besides that it actually works too)?

1 Like

Perfect. This way could achieve the mutual exclusion plus control over the delete.
Many Thanks @cohult @mvf for all the answers . I could model something very close what i wanted.

By the way , how do we customize the error message that is returned by the When statement evaluates to false?

See the examples.confd/dp/error_formatting/error-cbs.c ConfD example and the confd_lib_dp man page section “ERROR FORMATTING CALLBACK” (also available as an appendix in the ConfD UG).

You also have an example under “confd_error_seterr” that changes the “CONFD_ERR_TOO_MANY_ELEMS” error. You can do the same thing for other errors too.
Also note that you can, for example, check the context of the user, e.g. if the context is cli in the "struct confd_user_info”.

The error type you are interested in is CONFD_ERRTYPE_MISC and error code CONFD_ERR_NOEXISTS

1 Like

Thanks a lot for your response.

Thanks a lot for response.