Junos
Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-09-2010 06:22 AM

I must have been too tired last night.  The combination of this problem and the logic to check for both missing disable and missing description caused me grief.  Through my trial and error, I made the correct changes to each problem, but just not at the same time.  This morning, it all seemed obvious to me.

 

Thanks so much for walking me through this.  Again, I'll use this topic as a reference.

 

-Josh

11 REPLIES 11
Junos

JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

[ Edited ]
‎07-08-2010 12:35 PM

How do I create an if statement that matches on an xml element that there are duplicates of?  For instance, how would I do an if statement that matches where ge-0/0/3 DOES NOT have apply-groups BAR applied (regardless of whether it has FOO applied or not)

 

 

 

# show interfaces ge-0/0/3 | display xml 
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/9.2R3/junos">
    <configuration junos:changed-seconds="1278617547" junos:changed-localtime="2010-07-08 14:32:27 CDT">
            <interfaces>
                <interface>
                    <name>ge-0/0/3</name>
                    <apply-groups>FOO</apply-groups>
                    <apply-groups>BAR</apply-groups>
                </interface>
            </interfaces>
    </configuration>
    <cli>
        <banner>{master}[edit]</banner>
    </cli>
</rpc-reply>

 

 

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-08-2010 01:22 PM

This should work:

 

if( interfaces/interface[ name == "ge-0/0/3"][ jcs:empty( apply-macro[ . == "BAR" ] ) ] )

 

 

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-08-2010 01:43 PM

I assume you mean "apply-groups" instead of "apply-macro".  This doesn't seem to work. 

 

How would that work?

 

If interface name is ge-0/0/3 and apply-groups "BAR" is empty?  Wouldn't apply-groups "BAR" never be empty if it existed ? 

 

Is the idea that jcs:empty tests true if apply-groups "BAR" doesn't exist? 

 

Does apply-groups "FOO" NOT test empty/true because the predicate doesn't match?  If so, does a lack of matching predicate = empty?

 

I imagine I'm making this more difficult than it needs to be, so I really appreciate your explanation.

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-08-2010 02:01 PM

Yeah, I meant apply-groups rather than apply-macro, sorry. The following code works fine for me as an op script:

 

match / {
    var $configuration = jcs:invoke( "get-configuration" );
    
    if( $configuration/interfaces/interface[ name == "ge-0/0/3" ][ jcs:empty( apply-groups[ . == "BAR" ] ) ] ) {
        expr jcsSmiley Surprisedutput("ge-0/0/3 without BAR group");
    }
    else {
        expr jcsSmiley Surprisedutput( "no ge-0/0/3 without BAR group" );
    }
}

 

But are you trying to do this with a commit script rather than an op script? The problem you'll hit with a commit script is that the configuration they receive is post-inheritance so the "apply-groups" statements will not be present. You could try to look for the junos:group="BAR" attribute instead, which indicates that the configuration element was inherited by that group. What exactly are you trying to accomplish with this check?

 

As far as why it works, here is the logic behind it. The if statement just contains a location path, which will compute a node-set result. The conversion from node-set to boolean is that an empty node-set is false and one or more nodes is true. In other words, if the location path returns a node then it will evalute to true, false otherwise. The location path itself has two main predicates and one inner predicate. The first predicate just verifies that the interface name is "ge-0/0/3". So, if there is an <interface> node with a child <name> node of "ge-0/0/3" then that predicate will evaluate to true. The next predicate uses the jcs:empty() function, which returns true if the provided node-set is empty, or false otherwise. It is provided a location path of "apply-groups[ . == "BAR" ]". Keep in mind that the current context node is the <interface> node. So what this location path is looking for is any <apply-groups> node that has a value of "BAR" and that is a child of <interface>. Any other value for <apply-groups> is ignored, the only thing this path is looking for "BAR". So, if that exists then the result from jcs:empty() is false and therefore the predicate fails and an empty node-set is returned. If, however, it does not exist than the jcs:empty() returns true, so the predicate is true, and the if statement is run.

 

Basically, there are three possibilities:

 

1. There is no "ge-0/0/3" interface -> FALSE

2. There is a "ge-0/0/3" interface, but it has a "BAR" apply-groups -> FALSE

3. There is a "ge-0/0/3" interface, and it has no "BAR apply-groups -> TRUE

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

[ Edited ]
‎07-08-2010 04:26 PM

Thank you for the explanation on the boolean stuff.  That really clears some things up for me.

 

 


@ccall wrote:
The problem you'll hit with a commit script is that the configuration they receive is post-inheritance so the "apply-groups" statements will not be present.

 

 

@THE apply-groups node shouldn't be inherited.  Just the stuff in the group, right?  Or are you saying that 'post-inheritence' means the 'apply-group' is converted to a @junos:group type value, and is no longer in the config xml?

 

I'm trying to adjust my disable interface script to a) not process interfaces that I've already disabled (using a apply-group command), and b) disable any remaining interfaces missing a description.

 

@I tried to match on @junos:group, but I'm not sure I have the syntax right:

 

 

       if ( (not(@junos:group[.=="BAR"])) && jcs:empty(description)) {

 This appears to always be true, as  long as there is no description (even if apply-groups BAR is on the interface)

 

 

Its still trying to 'reapply' BAR to this interface:

 

 

# show interfaces ge-1/1/1   
apply-groups [ FOO BAR ];

 

 

 

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-08-2010 06:56 PM

Inheritance merges all the configuration group statements and removes the apply-groups along with any inactive configuration, so your commit script will never see the apply-groups, but it will see their effects. If you are using the config groups to disable interfaces then that is what your commit script will see.

 

It sounds like you can acocmplish what you want with something like this:

 

for-each( interfaces/interface[ jcs:empty( disable ) ][ jcs:empty( description ) ] ) {

...

}

 

That should match any interface nodes that have neither a disable nor a description child node.

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

[ Edited ]
‎07-08-2010 09:37 PM

OK, that makes sense.  I'm still struggling.  I'm doing my for-each through 'jcs:invoke( "get-interface-information" )' in order to go through all physical interfaces, not just interfaces in the configuration.

 

I'm not sure how to check configuration in reference to the interface information for-each.  I've tried several things, and this is kind of what I've tried most recently:

 

 

    var $config  = jcs:invoke( "get-configuration" );
    var $interfaces = jcs:invoke( "get-interface-information" );
    /* Only ge and xe interfaces */
    var $phyinterfaces = $interfaces/physical-interface[starts-with(name, "ge-") or starts-with(name, "xe-")];

    /* Go through each interface, if it isn't within the configuration than add apply-group  */
    for-each( $phyinterfaces ) {
       var $this = name;
       if ( $config/interfaces/interface[name == $this][ jcs:empty(disable) ] ) {

/* do stuff */
}

 The if statement is meant to check if the interface is NOT disabled already.  Once I got that to match, I intended on adding a third predicate to check that the description was not set/empty.

 

I appreciate all your help.  I routinely reference your posts (as I seem to forget a lot of this), so this medium is a great reference for me.

 

Thanks for your comments,

Josh

 

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-08-2010 09:57 PM

If this is a commit script then you don't need to retrieve the configuration and should instead just use the configuration provided automatically to the script because that will be the post-inheritance candidate configuration.

 

So, for a commit script you'd want to do it like this:

 

var $interfaces = jcs:invoke( "get-interface-information" );
/* Only ge and xe interfaces */
var $phyinterfaces = $interfaces/physical-interface[starts-with(name, "ge-") or starts-with(name, "xe-")];

/* Go through each interface, if it isn't within the configuration than add apply-group */
for-each( $phyinterfaces ) {
    var $this = name;
    if ( interfaces/interface[name == $this][ jcs:empty(disable) ] ) {

       ...

    }

}

 

If it is an op script though, and you want to work with the post-inheritance configuration so that the config includes the inherited <disable> node then you'll need to be more specific in your "get-configuration" RPC call since it does not perform inheritance by default. You could do this instead:

 

var $config-rpc = <get-configuration inherit="inherit">;

var $configuration = jcs:invoke( $config-rpc );

 

But again, if you are using a commit script then you should just use the configuration that is provided to your script automatically and which can be directly referenced within a location path as shown above.

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-08-2010 10:02 PM

BTW, since you are looping through physical interfaces that might not be present, keep in mind that you're looking at a few different possibilities:

 

/* Interface is present, disable is not present */

if ( interfaces/interface[name == $this][ jcs:empty(disable) ] ) {

    ....

}

/* Interface is present, disable must be present since it didn't match above */

else if( interfaces/interface[ name == $this ] ) {

}

/* Interface is not present */

else {

}

 

There are obviously lots of different ways you could structure the above.

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-08-2010 10:59 PM

I follow your logic, but for some reason, its still matching on all interfaces regardless. 

 

 

# show interfaces ge-0/0/0 
description inet stuf:;
gigether-options {
    auto-negotiation;
}
unit 0 {
    family inet {
        address 42.123.240.172/31;
    }
}
# commit check 
re0: 
warning: Disabling unconfigured interface: ge-0/0/0
warning: Disabling unconfigured interface: ge-0/0/1
warning: Disabling unconfigured interface: ge-0/0/2
warning: Disabling unconfigured interface: ge-0/0/3
warning: Disabling unconfigured interface: ge-0/0/4
warning: Disabling unconfigured interface: ge-0/0/5
warning: Disabling unconfigured interface: ge-0/0/6
warning: Disabling unconfigured interface: ge-0/0/7
warning: Disabling unconfigured interface: ge-0/0/8
warning: Disabling unconfigured interface: ge-0/0/9
warning: Disabling unconfigured interface: ge-0/1/0
warning: Disabling unconfigured interface: ge-0/1/1
warning: Disabling unconfigured interface: ge-0/1/2
warning: Disabling unconfigured interface: ge-0/1/3
warning: Disabling unconfigured interface: ge-0/1/4
warning: Disabling unconfigured interface: ge-0/1/5
warning: Disabling unconfigured interface: ge-0/1/6
warning: Disabling unconfigured interface: ge-0/1/7
warning: Disabling unconfigured interface: ge-0/1/8
warning: Disabling unconfigured interface: ge-0/1/9
warning: Disabling unconfigured interface: xe-0/2/0
warning: Disabling unconfigured interface: xe-0/3/0
warning: Disabling unconfigured interface: xe-1/0/0
warning: Disabling unconfigured interface: xe-1/1/0
warning: Disabling unconfigured interface: xe-1/2/0
warning: Disabling unconfigured interface: xe-1/3/0

# show interfaces ge-0/0/0 
apply-groups [ SERVICEPORT DISABLEIF ];
description inet stuf:;
gigether-options {
    auto-negotiation;
}
unit 0 {
    family inet {
        address 42.123.240.172/31;
    }
}
#

 

I've attached the script in its current form.

 

Attachments

Junos

Re: JUNOSCRIPT: Matching when duplicated xml elements at the same node/level

‎07-08-2010 11:25 PM

Sorry I didn't notice it earlier. The problem is that your if statements are occurring within a for-each loop that is looping through the XML output of 'get-interface-information'. What this means is that the context node is changed within the for-each loop from the default <configuration> node of the candidate configuration, so the location paths you are using in the if statement are not evaluated correctly because they are looking for interfaces/interface nodes within the physical interface output rather than the configuration output.

 

The solution is fairly simple, assign the context node to a variable prior to the for-each, and then change the location paths that refer to the configuration to use that variable.

 

So do this:

 

var $configuration = .;

 

Which assigns $configuration to point to the configuration XML data, and then change your location paths to be like this:

 

if( $configuration/interfaces/interface[name == ...etc

 

That should solve the problem.

 

Also, the <output> tag won't work in a commit script. You'll need to use <xnm:warning> for debug style messages as well. Or you could always use jcs:syslog() or jcs:trace() and look at those log files afterward.