Identifiers are used as unique keys to differentiate between two otherwise identical configuration stanzas. For example, consider the <interfaces> hierarchy, which can, and almost always does, contain multiple instances of <interface> child elements, with each of these elements being distinguished by an identifier element named <name>.
01 <interfaces>
02 <interface>
03 <name>ge-0/0/0</name>
04 </interface>
05 <interface>
06 <name>ge-0/0/1</name>
07 </interface>
08 <interface>
09 <name>lo0</name>
10 </interface>
11 </interfaces>
Most identifiers are conveniently named <name>, making it easy to identify the majority of identifiers by simply scanning for elements with a name of "name". This is how the jcs:emit-change template builds its change configuration hierarchies. It is provided a chunk of configuration XML along with a reference point, and it then adds the ancestors of that structure backwards, pulling out and including <name> identifiers as it goes.
Using Non-Name Identifier Elements
Now, if all identifiers were named "name", then there would be no need for this article, but they are not. Other identifier elements include: <from-zone-name>, <to-zone-name>,<neighbor-id>, <transit-area>, and so on, and any configuration change made within one of these hierarchies, which have non-"name" identifiers, must include the identifiers in order to be valid. However, the problem is that there is no indication given within the configuration XML itself whether a particular element is an identifier or not.
Why is this a problem? Well, return to the jcs:emit-change example and assume that you want to make a change within a security policy. You would provide the code chunk to jcs:emit-change, which would happily generate a <change> element for you, and Junos OS would just as happily fail your commit with an error message.
Why? Because the generated <change> element would be invalid because that jcs:emit-change had no idea that <from-zone-name> and <to-zone-name> were identifiers and needed to be included. Now, it might be possible to go through and manually identify every single non-name identifier possible in the configuration and hard-code that into your script, but what happens if the next Junos OS version adds a new one? Is that a commitment you really want to make?
Ultimately, we need a mechanism that informs scripts whether an element is an identifier or not. This would ideally be included as an attribute of <get-configuration>, allowing you to specify whether you want identifiers identified or not. This is being requested by PR 492912, which has yet to see a fix.
In the meantime, here is a workaround that could be useful in some scenarios, but not all. The "| display xml" CLI pipe has an undocument option that can be appended, "junos-key", and if you include that option then you will get output like this:
01 jnpr@srx210> show configuration interfaces ge-0/0/0 | display xml junos-key
02 <rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.1D0/junos">
03 <configuration junos:commit-seconds="1327137218" junos:commit-localtime="2012-01-21 09:13:38 UTC" junos:commit-user="jnpr">
04 <interfaces>
05 <interface>
06 <name junos:key="key">ge-0/0/0</name>
07 <unit>
08 <name junos:key="key">0</name>
09 <family>
10 <inet>
11 <address>
12 <name junos:key="key">10.0.0.10/24</name>
13 </address>
14 </inet>
15 </family>
16 </unit>
17 </interface>
18 </interfaces>
19 </configuration>
20 <cli>
21 <banner></banner>
22 </cli>
23 </rpc-reply>
This can be leveraged within a script as well, using code such as below:
1 var $rpc = <command> "show configuration security policies | display xml junos-key";
2 var $results = jcs:invoke( $rpc );
Here is the returned XML content:
01 <pipe>
02 <display-xml>
03 <junos-key/>
04 </display-xml>
05 </pipe>
06 <configuration xmlns:junos="http://xml.juniper.net/junos/*/junos" junos:commit-seconds="1327137218" junos:commit-localtime="2012-01-21 09:13:38 UTC" junos:commit-user="jnpr">
07 <security>
08 <policies>
09 <policy>
10 <from-zone-name junos:key="key">trust</from-zone-name>
11 <to-zone-name junos:key="key">trust</to-zone-name>
12 <policy>
13 <name junos:key="key">example</name>
14 <match>
15 <source-address junos:key="key">any</source-address>
16 <destination-address junos:key="key">any</destination-address>
17 <application junos:key="key">any</application>
18 </match>
19 <then>
20 <permit>
21 </permit>
22 <count>
23 </count>
24 </then>
25 </policy>
26 </policy>
27 </policies>
28 </security>
29 </configuration>
As you can see, all of the identifiers are now tagged with the junos:key attribute, making it possible to identify them through an attribute check (@junos:key).
Limitations
- Pipes are not actually supported in Junos OS scripts. On the other hand, there is no supported way to do this today, and it works
- Only the committed configuration database can be returned in this fashion
- So it is not useful in commit scripts