Junos
Highlighted
Junos

Re: perl veteran struggling with xml/slax

‎07-06-2010 01:47 PM

Hi Michael,

 

I am failry certain the jcs:regex() is based on the POSIX style, but I would have to doublecheck the specifics.


Regarding the 'preceding' keyword - this is not a JUNOSscript keyword as you guessed, but actually an XPath keyword, and specifically an XPath axis.  I've found that the more I know XPath the easier writing JUNOScript has become.  If you haven't already read the "Day One: Navigating the Junos XML Heirarchy", I would definitely recommend it.  You can find a copy here.  I would also recommend the book "XSLT 1.0 Pocket Reference".

 

You are correct that my prior code snipped was not doing what you specifically wanted; but I was hoping it would get you started along a path (no pun!).  Here is another snipped that I do believe gives you exactly what you are looking for.  Hope this helps.  I've bolded the XPath parts that (a) retrieve the immediate prior node and (b) test that node is a comment element.

 

Cheers,

-- Jeremy

 

match / {
  <op-script-results> {  

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

    var $ospf-a0 = $config/protocols/ospf/area[name='0.0.0.0'];

    for-each($ospf-a0/interface) {

      expr jcsSmiley Surprisedutput('interface is ', name);
      var $pc := preceding-sibling::*[1];

      if($pc[name()=='comment']) {
         expr jcsSmiley Surprisedutput('   full comment is ', $pc);
         var $comment_regx = jcs:regex("/[*] (.*) [*]/", $pc);
         expr jcsSmiley Surprisedutput('        comment is ', $comment_regx[2]);
      }
      else {
         expr jcsSmiley Surprisedutput('   NO COMMENT');
      }
    }
  }
}

 

 

Here is my input configuration, notice that the last interface in the list does not have a comment.

 

          <protocols>
                <ospf>
                    <area>
                        <name>0.0.0.0</name>
                        <junos:comment>/* this is ge0 comment */</junos:comment>
                        <interface>
                            <name>ge-0/0/0.0</name>
                        </interface>
                        <junos:comment>/* this is ge1 comment */</junos:comment>
                        <interface>
                            <name>ge-0/0/1.0</name>
                        </interface>
                        <interface>
                            <name>fe-0/0/2.0</name>
                        </interface>
                    </area>
                </ospf>
            </protocols>

 

Here is the output of the op-script:

 

jeremy@srx210> op show-comment
interface is ge-0/0/0.0
   full comment is /* this is ge0 comment */
        comment is this is ge0 comment
interface is ge-0/0/1.0
   full comment is /* this is ge1 comment */
        comment is this is ge1 comment
interface is fe-0/0/2.0
   NO COMMENT


Cheers,
-- Jeremy

@nwkautomaniac
15 REPLIES 15
Junos

perl veteran struggling with xml/slax

‎07-02-2010 07:33 AM

Hello-

 

I am very familiar with perl but am struggling a little with XML and SLAX.  This is probably a simple XML parsing question, but if I am rooted at an interface under area 0.0.0.0, how do I retrieve the current comment for the interface for use in comparison in an 'if' statement?

 

I tried

 

        var $current_comment = ../junos:comment;

 

        which I didn't think would work because there are multiple interfaces commented at that level.  I also tried

 

        var $iface = "xe-4/0/0.3997";

        var $current_comment = ../junos:comment/interface[name == $iface];

 

       Thinking that it would nail down the comment to an interface but I still came up empty.

 

Here is the XML I am parsing.  Would appreciate any hints.

 

Thanks-

-Michael

 

{master}[edit]
m7h@r-myrouter-re0# show protocols ospf area 0.0.0.0 | display xml | no-more
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/9.5R2/junos">
    <configuration junos:changed-seconds="1278080065" junos:changed-localtime="2010-07-02 09:14:25 CDT">
            <protocols>
                <ospf>
                    <area>
                        <name>0.0.0.0</name>
                        <junos:comment>/* r-uwmadison-isp */</junos:comment>
                        <interface>
                            <name>xe-4/0/0.3997</name>
                            <apply-groups>bfd-ospf</apply-groups>
                            <metric>20</metric>
                        </interface>
                        <junos:comment>/* s-equinix-hub */</junos:comment>
                        <interface>
                            <name>xe-4/1/0.3977</name>
                            <passive>
                            </passive>
                        </interface>
                    </area>
                </ospf>
            </protocols>
    </configuration>
    <cli>
        <banner>{master}[edit]</banner>
    </cli>
</rpc-reply>

Junos

Re: perl veteran struggling with xml/slax

‎07-02-2010 08:11 AM

I'm not fully understanding the examples you are showing....in slax the XML output of a command will be placed into a variable ( using jcs:invoke) and you use that variable with XPATH expressions to dig into the XML.

 

For exmple if the variable $output had the output of the command you ran, you would access a certain vlaue with:

 

$my_value = $output/first_level/second_leve/leaf_node;

 

 

Junos

Re: perl veteran struggling with xml/slax

‎07-02-2010 08:20 AM
Sorry for not being more clear. I've included the code being used below, which doesn't use jcs-invoke, but uses a for-each loop. I'm using as a basis for learning the commit script found here. http://juniper.cluepon.net/index.php/CS_Descriptions_for_Interface_References http://juniper.cluepon.net/index.php/Iface_descr.slax
Junos

Re: perl veteran struggling with xml/slax

‎07-02-2010 09:23 AM

I see, this is a commit script, I was thinking op script at first.  Is Iface desc.slax your script that you are using and having problems with?  If so, specifically what section are you having trouble with?  It looks like the script is adding annotation to certain lines.

Junos

Re: perl veteran struggling with xml/slax

‎07-02-2010 09:33 AM

Wow.  This forum software is driving my nuts.  My post had a lot more info in it that didn't make it, probably due to not escaping some tags or something.  So I tried to preview it the second time and it lost all of my input text when I clicked preview.. ARGH...   Anyway, this is the third attempt, so I'm going to be terse Smiley Happy 

 

Below, I am trying to get the value of the current comment for an if/else and I've tried a few things and all I get is ''.  As you can see I'm using a for-each loop and not a jcs:invoke.

 

    for-each (//protocols//interface[name == $iface]) {
        var $current_comment = ../junos:comment/interface[name == $iface];

 

       note: I have also tried

        var $current_comment = ../junos:comment

 

        if ( $current_comment == $comment) {
           /* no change, but this isn't working since current_comment is always ''... */
        } else {

        /* "annotate" a comment onto the interface references */

        call jcs:emit-change($dot = ..) {
            with $content = {
                <junos:comment replace="replace"> $comment;
                <interface> {
                    <name> $iface;
                }
            }
            with $message = "Change " _ $iface _ " to " _ $comment _ " from " _ $current_comment;
        }
        }
    }

Junos

Re: perl veteran struggling with xml/slax

‎07-02-2010 09:37 AM

To be more clear, I am trying to augment the already existing Iface desc.slax script as a learning exercise.  This first modification is a stepping stone to better understanding XML/SLAX before trying to change the script to work under CoS as well.

 

I have been through about 2/3rds of the following so far, which has been fairly helpful.

http://www.juniper.net/us/en/training/elearning/junos_scripting/course_start.html

Junos

Re: perl veteran struggling with xml/slax

‎07-02-2010 01:53 PM

Yes the Junos as a scripting language is very useful as an introduction, but is pretty limited in scope.

 

In looking at the XML in your first entry and the for-each loop you posted...from what you wrote I take it that $current_comment is always null.

 

I would't expect the  var $current_comment = ../junos:comment/interface[name == $iface]; to work, becuase the interface element is not a sub element of the junos:comment element.

 

The second line you show that you also tried seems to be good:

 

var $current_comment = ../junos:comment

 

Given the XML, assuming the vlaue of the variable in the $iface variable would match on one fo the names, within the for-each loop I'd expect the context node to be <interface> so the .. would get back up to the <area>.  There are two <junos:comment> nodes under the <area> node, so I wonder if you need to declare which of the node's values you want to put into $current.  You might try:

 

var $current_comment = ../junos:comment[1];

 

To see if that puts anything into the $current_comment variable. 

 

 

 

 

Junos

Re: perl veteran struggling with xml/slax

‎07-02-2010 02:51 PM

Thanks for your suggestion, but no dice on trying to treat junos:comment as an array reference.  It appears to be something funky with junos:comment.  If I set the 'comment' variable to a string, ../name or name [just to prove that I have the slightest clue about XML parsing] I get what I expect in my variable.

I wonder how one is supposed to parse the junos:comment tag in general as it is fairly loosely tied to an object.

Do you know if JTAC offers JunoScript support?

-Michael

Junos

Re: perl veteran struggling with xml/slax

‎07-03-2010 09:52 AM

Michael,

 

Please try the following; I put together a short op-script to show the comments for each interface in ospf area0.  I hope this helps.

 

Cheers,

-- Jeremy

 

version 1.0;
ns junos = "http://xml.juniper.net/junos/*/junos";
ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";
import "../import/junos.xsl";

match / {
  <op-script-results> {  

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

    var $ospf-a0 = $config/protocols/ospf/area[name='0.0.0.0'];

    for-each($ospf-a0/interface) {  /* */
      var $pc = preceding::comment[1];
      expr jcsSmiley Surprisedutput('interface is ', name);
      expr jcsSmiley Surprisedutput('comment is ', $pc);
    }
  }
}


Cheers,
-- Jeremy

@nwkautomaniac
Junos

Re: perl veteran struggling with xml/slax

‎07-03-2010 09:55 AM

Also, here was my config for this test:

 

jeremy@srx210# show | display xml
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/10.1R1/junos">
    <configuration junos:changed-seconds="1278203527" junos:changed-localtime="2010-07-04 00:32:07 UTC">
            <protocols>
                <ospf>
                    <area>
                        <name>0.0.0.0</name>
                        <junos:comment>/* this is ge0 comment */</junos:comment>
                        <interface>
                            <name>ge-0/0/0.0</name>
                        </interface>
                        <junos:comment>/* this is ge1 comment */</junos:comment>
                        <interface>
                            <name>ge-0/0/1.0</name>
                        </interface>
                    </area>
                </ospf>
            </protocols>
    </configuration>

 

And here was the output of the op-script:

 

jeremy@srx210> op show-comment
interface is ge-0/0/0.0
comment is /* this is ge0 comment */
interface is ge-0/0/1.0
comment is /* this is ge1 comment */

Cheers,
-- Jeremy

@nwkautomaniac
Junos

Re: perl veteran struggling with xml/slax

‎07-03-2010 01:16 PM

Michael,

 

I also tested a similar commit-script, and it appears that the comment tags are being removed.  You can retreive them using the technique I am showing below:

 

version 1.0;
ns junos = "http://xml.juniper.net/junos/*/junos";
ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";
import "../import/junos.xsl";

match configuration {

  var $get-ospf-a0 = <get-configuration commit-scripts="view"> {
    <configuration> {
      <protocols> { <ospf> { <area> { <name> '0.0.0.0'; }}}
    }
  };

  var $got-ospf-a0 = jcs:invoke($get-ospf-a0);

  var $ospf-a0 = $got-ospf-a0/protocols/ospf/area[name='0.0.0.0'];
 
  for-each($ospf-a0/interface) {  
    var $pc = preceding::comment[1];
    <xnm:warning> {
      <message> {
        expr 'interface is ' _ name;
        expr '  comment is ' _ $pc;
      }
    }
  }
}

 

Here is the output when Ithis commit-script is executed:

 

[edit]
jeremy@srx210# commit check
warning: interface is ge-0/0/0.0  comment is /* this is ge0 comment */
warning: interface is ge-0/0/1.0  comment is /* this is ge1 comment */
configuration check succeeds

 

Please Note the following relating to using <get-configuration> from within a commit script, as documented in the "Day One: Applying Junos Configuration Automation":

 

ALERT! Do not use the <get-configuration> API element within a commit script prior to the following releases: 9.3S5, 9.4R4, 9.5R3, 9.6R2, or 10.0R1, as it can cause the Junos device to hang while booting. For further details refer to PR 452398.

 

Hope this helps,

-- Jeremy

Cheers,
-- Jeremy

@nwkautomaniac
Junos

Re: perl veteran struggling with xml/slax

‎07-03-2010 01:30 PM

Hi Jeremy, good timing!  I was just crafting something to the effect that perhaps the comment tags were removed in commit scripts.  Hadn't yet looked/found out how to see what XML was being passed to the parser.

 

I really need to start glancing at the automation guide.  Hopefully with your help [and warning] I can figure out how to more generically apply this to my goal of describing any interface as found under /protocols.

 

Thanks!
-Michael

Junos

Re: perl veteran struggling with xml/slax

‎07-04-2010 09:31 AM

Jeremy-

Hopefully I haven't tried your patience as I now have a regex question. 

 

The documentation for jcs:regex doesn't mention what type of regular expressions it takes.  I'd assume POSIX 1003.2 but if so I'm at a loss with respect to the below behavior.  Can you please point me towards documentation of what is allowed in a jcs:regex call as I have not had any success in finding it.

 

As an aside, I couldn't find information about the 'get-configuration' command in combination with 'commit-scripts' argument.  I'd certainly like to be more self sufficient in figuring this stuff out.  I checked the JUNOScript API guide and the Configuration and Diagnostic Automation Guide.  Are there other resources I should be looking at in general?

 

Regarding the regex question In more detail, after examining your working code, I recognized that I was going to have to strip the 'comment' characters from the annotations before doing a comparison.  Consider the following code.

    var $whole_current_comment =  preceding::comment[1];
    var $regex_current_comment = jcs:regex("^.. (.*) ..$", $whole_current_comment);        
    var $current_comment = $regex_current_comment[1];  

    <xnm:warning> {
      <message> {
        expr "interface is " _ name _  ", original_comment is '" _ $whole_current_comment _ "', regex comment is '" _ $current_commen
t _ "'";
      }
    }

It has the following behavior for an example interface.  I'm not sure why the regex didn't work.

warning: interface is xe-4/0/0.3980, original_comment is '/* s-uwmadison-432nm-hub */', regex comment is '/* s-uwmadison-432nm-hub */'

I then  tried further iterations of things that I'd expect would work (in perl) without success.  I kept trying simpler and simpler things, such as

        var $regex_current_comment = jcs:regex(".. (.*) ..", $whole_current_comment);          

which results in the same output as above.  I then tried the very simple

        var $regex_current_comment = jcs:regex(" (.*) ", $whole_current_comment);              

Which for some reason seems to keep the spaces intact.

warning: interface is xe-4/0/0.3980, original_comment is '/* s-uwmadison-432nm-hub */', regex comment is ' s-uwmadison-432nm-hub '

which lead me to try the following from a purely experimental point of view.

        var $regex_current_comment = jcs:regex('\s+(.*)\s+', $whole_current_comment);

which truncated my comment, implying perhaps things like \w and \s weren't supported.

warning: interface is xe-4/0/0.3980, original_comment is '/* s-uwmadison-432nm-hub */', regex comment is 's-uwmadis'

-Michael

Junos

Re: perl veteran struggling with xml/slax

‎07-06-2010 10:36 AM

Hi Michael,

 

Here is a code snipped that regex the inner comment.  Hope this helps.

 

Cheers,

-- Jeremy

 

version 1.0;
ns junos = "http://xml.juniper.net/junos/*/junos";
ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";
import "../import/junos.xsl";

match / {
  <op-script-results> {  

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

    var $ospf-a0 = $config/protocols/ospf/area[name='0.0.0.0'];

    for-each($ospf-a0/interface) {  /* */
      var $pc = preceding::comment[1];
      expr jcsSmiley Surprisedutput('interface is ', name);
      expr jcsSmiley Surprisedutput('full comment is ', $pc);
      var $comment_regx = jcs:regex("/[*] (.*) [*]/", $pc);
      expr jcsSmiley Surprisedutput('     comment is ', $comment_regx[2]);
    }
  }
}

Cheers,
-- Jeremy

@nwkautomaniac
Junos

Re: perl veteran struggling with xml/slax

‎07-06-2010 11:29 AM

I should have caught the whole '$2' bit.  While you didn't directly answer the regex style question you've given enough hints to figure it out.

So, this preceding-comment function doesn't seem to be quite ideal.  It seems that there is no guarantee that the preceding comment is relevant to the level you are at, correct?  Presumably because the 'preceding' comment in the below case is really up in the policy-options statement.  I can't find preceding::comment documented in the junoscript APIs documentation, so based on my googling I'm assuming this is an XML feature.  So in short, there is no way to get an annotation for a specific tag in the style that my original code scrap attempted?  I suppose this is why "show configuration | display set" doesn't preserve annotations?  (A somewhat major annoyance)

For example, I am noticing this [summarized] part of my config

            <policy-options>
                <junos:comment>/* WiscNet local preference will be 90 */</junos:comment>
                <community>
                    <name>wn_lp90</name>
                    <members>2381:90</members>
                </community>
            </policy-options>
            <class-of-service>
               <interfaces>
                    <interface>
                        <name>xe-4/0/0</name>
                        <scheduler-map>10g-cos-scheduler</scheduler-map>
                        <unit>
                            <name>3980</name>
                            <classifiers>
                                <inet-precedence>
                                    <classifier-name>inbound-classifier</classifier-name>
                                </inet-precedence>
                            </classifiers>
                        </unit>
                    </interface>
            </class-of-service>

will put out the following line as it goes through my script.  Problem is, the annotation of "WiscNet local preference will be 90" had nothing to do with CoS.

[edit class-of-service interfaces interface xe-4/0/0]
  warning: Change xe-4/0/0 to comment='s-uwmadison-432nm-hub TenGigabitEthernet 0/0' from comment='WiscNet local preference will be 90'

 

-Michael