Want to model when the CLI skips a sub-mode, if the root command was already configured

Hi Folks,

I have a CLI command, which changes the mode in the order-

(config)# << which indicate configuration mode.
(config)#my_command 1
(config-my-cmd)#probe A
(config-my-cmd-probe-A)#

So when I type in the command “my_command 1” it takes me to the new mode “config-my-cmd”. Under this sub-mode, it supports different types of probe types, and for our example, I would like to configure with “probe A”. Which makes the system to enter into a new mode “config-my-cmd-probe-A”.
And i will exit out multiple levels to come to (config)# mode

========================================================================

Now since the command “my_command 1” is already configured on the device. Now if I type in the command “my_command 1” and press enter, my CLI is designed to directly enter into the mode “config-my-cmd-probe-A” by skipping “config-my-cmd”. Reason being, for a given ID (my_command 1), we are not allowed to change the probe type.

So CLI transition looks like-

(config)# << which indicate configuration mode.
(config)#my_command 1
(config-my-cmd-probe-A)#

How can i model this kind of behavior using yang?

My existing implementation looks like -

container my_command {
      tailf:cli-incomplete-no;
      list entry {
        tailf:cli-drop-node-name;
        tailf:cli-suppress-list-no;
        tailf:cli-full-no;
        tailf:cli-full-command;
        tailf:cli-mode-name "config-my-cmd";
        key "number";
        leaf number {
          type uint32;
        }
        
        choice params {
          case param-A-case {
            container param-A {
              tailf:cli-add-mode;
              tailf:cli-mode-name "config-my-cmd-probe-A";
              tailf:cli-sequence-commands;
              tailf:cli-incomplete-command;
			  leaf a {
			    type uint8;
			  }
			  leaf b {
			    type uint8;
		          }
			  .
			  .
			  .

So with this model, i am able to achieve the first order of CLI mode changes. However, I wont be able to achieve the second order of CLI mode changes (ie the scenario of when the command is already configured).

I do not believe this can be achieved using just YANG means. If you need this
behavior just for human-CLI interaction, you may use custom CLI commands
(though I would suggest to consider other options before really implementing
it, such behavior can do more harm then good). If you need it so as to make
ConfD mimick a legacy device CLI or to interact with such device, you may need
to use other support channels, I’m afraid we are not CLI experts here.

In any case: please be careful before adapting your data model heavily to the
desired CLI behavior. In the ideal world the data model is the central piece
and should describe your system, not one of its interfaces; and even in the
real world other components of your system will likely need to interact with
ConfD using the data model-driven API, so better do not make it too complex.

Thanks for your response.
But i could not get it clear on these statements of yours. Could you please clarify-
1.

What is custom CLI commands?

Can you please redirect me to the right support channel?

Can you please make it more clear?

Custom (or user-defined) CLI commands are described in the ConfD documentation - look for the corresponding section in the chapter “The CLI Agent”. In short, you can declare a command that would be invoked from the CLI as if it was one of the ConfD built-in or auto-generated commands, and implement virtually any behavior you may need. But again, this is useful only if you are targeting human operator’s interaction with the ConfD CLI, these commands are completely useless anywhere else.

For further support, your team most likely has a RT support account, or someone in your team knows how to access one.

As for re-modelling: the data model should describe your system, its primary purpose should not be to describe behavior of your system’s CLI. So adding tailf:cli-... annotations is perfectly fine, it does not change the data model structure; but you should be careful with introducing complex model structures if that’s only to support unusual CLI behavior. (You should - I do not know your exact use case, sometimes there may be simply no other way.)

@mvf: I have got an idea to address this issue in a cleaner way by having a new tailf:cli-…
Hypothetically if there is a new tailf extension tailf:cli-new-extension whose behavior is similar to that of tailf:cli-drop-node-name. i.e., the node name should be dropped but on a conditional basis (in our case, when the entry is already configured).

container my_command {
  tailf:cli-incomplete-no;
  list entry {
	tailf:cli-drop-node-name;
	tailf:cli-suppress-list-no;
	tailf:cli-full-no;
	tailf:cli-full-command;
	tailf:cli-mode-name "config-my-cmd";
	key "number";
	leaf number {
	  type uint32;
	}

    choice params {
	  case param-A-case {
		container param-A {
		  **tailf:cli-new-extension {**
			tailf:cli-condition ("xpath");              << To check if the container instance is already present in the data tree
		  }
		  tailf:cli-add-mode;
		  tailf:cli-mode-name "config-my-cmd-probe-A";
		  tailf:cli-sequence-commands;
		  tailf:cli-incomplete-command;
		  leaf a {
			type uint8;
		  }
		  leaf b {
			type uint8;
			  }
		  .
		  .
		  .

If you think the new extension would be useful, try to suggest it through a RT ticket. But I fail to see how this "conditional drop-node-name" would help you - if I understand it correctly, you need something that would automatically change the CLI mode.

Can you explain your use-case? Is it for human-CLI interaction? Or for a synchronization between ConfD and a CLI-based subsystem? In the former case there are definitely other options, you do not need to stick with YANG means only.

I want something to automatically change the CLI mode, but on a condition. i.e., if the main (first level) command is already configured then it should skip the mode otherwise not.
So it is not always CLI mode will be skipped. I have explained the behavior of our CLI in the first post of this thread. Let me know if that is not clear.

So the CLI behavior (sequence of CLI mode change) is not static (sequence of CLI mode change depends based on the other factor). We can’t model this using static nature of yang.
So we need some mechanism to make the yang model to dynamically adjust; and i felt that can be achieved if there is a support to adjust based on a condition.

Mostly, the use case is - the device should support receiving the configuration send through NETCONF protocol and get that configured. Not the human CLI interaction on the confd prompt.

Yes, I understand. So “something that would automatically change the CLI mode based on current configuration”. I’m pretty sure no such thing is possible by just YANG means now.

I must be missing something - if you are interested only in NETCONF, why are you trying to solve CLI issues?

When it is NETCONF,
we would generate a RPC XML for my model as below when we want to edit the configuration-

<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
  <edit-config>
    <target>
      <running/>
    </target>
    <config>
      <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <my_command>
              <probeA>
                <destination>1.1.1.1</destination>
                <frequency>60</frequency>
              </probeA>
        </my_command>
      </native>
    </config>
  </edit-config>
</rpc>

Once the NETCONF server receives this RPC, i think ConfD uses this RPC XML data to generate corresponding CLI command and passes it to our parser.

The generated command would be like -
my_command probeA destination 1.1.1.1 frequency 60.

So this generated command would work when we are configuring probeA for the very first time.

because the CLI modes changes in this order -

(config)# << which indicate configuration mode.
(config)# my_command 1
(config-my-cmd)# probe A
(config-my-cmd-probe-A)#


However, if i want to edit the configuration of an already configured probeA.
the RPC generated would be like -

<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
  <edit-config>
    <target>
      <running/>
    </target>
    <config>
      <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <my_command>
              <probeA>
                <frequency>120</frequency>
              </probeA>
        </my_command>
      </native>
    </config>
  </edit-config>
</rpc>

Once the NETCONF server receives this RPC, ConfD uses this RPC XML data to generate corresponding CLI command and passes it to our parser.

The generated command would be like -
my_command probeA frequency 60.

So this generated command would NOT work when we are editing the already configured probeA.

because the CLI modes changes in this order -

(config)# << which indicate configuration mode.
(config)# my_command 1
(config-my-cmd-probe-A)# probe A << In this particular mode, probeA subcommand is not valid and hence throws an ERROR. Instead of probeA, we need to passing frequency at this mode.

So what i am thinking is, when we have a new tailf extension and used under the container probeA, then when we receive this RPC XML, the ConfD would know that this xml tag should not be used to generate the command. And hence the resultant command would look like-

my_command frequency 60

So this generated command would work when we are editing the already configured probeA.

because the CLI modes changes in this order -

(config)# << which indicate configuration mode.
(config)# my_command 1
(config-my-cmd-probe-A)# frequency 60

I understand. Is the NETCONF RPC structure fixed, or can you change that? In the latter case - restructuring the data model might give you the desired behavior towards the CLI, I do not think you need to model probeA as a container.

RPC structure is generated out of YANG model by NETCONF client utility.
And we can have only one model for a given command. Hence having 2 separate model for the same command (one applicable during creation mode and another applicable during modification mode) is not desirable.

Usually NETCONF clients would be RFC6020 compatible so they only understand YANG language and they generate RPC XML as shown above for the model. So the feasible solution I am seeing here is that - since we have ConfD as the “NETCONF server and YANG interpreter” which can understand some additional standards defined as part of tailf extension as well, we can have a new tailf extension to discard a tag during interpretation of the RPC XML.

Then may i know how do you want me to model it as?

I had something like this in mind:

  list my-command {
    key index;
    leaf index {
      type int32;
    }
    tailf:cli-compact-syntax;
    choice command-type {
      case probe-a {
        leaf probeA {
          type empty;
        }
        leaf destination {
          type inet:ip-address;
        }
        leaf frequency {
          type int32;
        }
      }
    }
  }

The ConfD CLI accepts and generates almost the right syntax:

box(config)# my-command 1
box(config-my-command-1)# probeA destination 1.1.1.1 frequency 60
box(config-my-command-1)# top
box(config)# show config
my-command 1
 probeA destination 1.1.1.1 frequency 60
!
box(config)# commit
Commit complete.
mvolf-lnx(config)# my-command 1
mvolf-lnx(config-my-command-1)# destination 1.1.1.2
mvolf-lnx(config-my-command-1)# top
mvolf-lnx(config)# show config
my-command 1
 probeA destination 1.1.1.2 frequency 60
!
box(config)# commit
Commit complete.
mvolf-lnx(config)# 

So it accepts what you need it to accept, in case of a new my-command instance ConfD generates the right CLI command; but simple leaf change generates again the full command, not just the change. Maybe this can be improved, but I do not see how. If this is not good enough, use the RT support account - as I wrote, not many CLI experts visit this forum.