Blogs

Scripting How-To: Use the track-ip script to implement the Track-IP feature on the SRX platforms

By Erdem posted 08-11-2015 02:53

  

Use the Track-IP Feature on SRX Platforms

 
For SLAX 1.0 version 1.0 and higher, you can use the track-ip event script to implement the Track-IP feature on the SRX platforms.
 
For SRX platforms, the Track-IP feature allows for path and next-hop validation through the existing network infrastructure with the ICMP protocol. Upon the detection of a failure, the script executes a failover to the other node in an attempt to prevent downtime.

 

Source Code and GitHub Links

 

The source code below is also available from the following GitHub locations:

Example Configuration


01	The track IP JUNOScript implementation utilizes the event system. The event system allows for the triggering of events based upon receiving a specific syslog or SNMP message. In this case an event "TRACKIP" is triggered every sixty seconds calling the Track IP JUNOScript. The script reads the chassis cluster redundancy group information looking for the track IP configuration elements. The elements are stored in a macro that is created in any redundancy group. Below is an example configuration for track IP is shown.
02	 
03	[Track IP configuration]
04	 
05	apply-macro monitoring-options {
06	       clear-failover;
07	       full-failover;
08	}
09	reth-count 2;
10	control-ports {
11	    fpc 2 port 0;
12	    fpc 14 port 0;
13	}
14	redundancy-group 0 {
15	    node 0 priority 254;
16	    node 1 priority 1;
17	}
18	redundancy-group 1 {
19	    apply-macro track-gateway {
20	        server 1.1.1.222;
21	        weight 255;
22	    count 5; /* Optional */
23	    routing-instance Test; /* Optional */
24	    interval 2; /* Optional */
25	    wait 1; /* Optional */
26	    }
27	/* Optional */
28	    node 0 priority 254;
29	    node 1 priority 1;
30	}
31	 
32	The macro requires that it begins with "track-" and contains a server variable and a weight. The server variable requires an IP address or hostname; this is the host that will be tested three times. If the ping attempt is successful then the script will exit successfully. If the ping attempt fails then it will check the weight. If the weight is equal to or greater than 255 then the firewall will fail that redundancy group over to the other chassis. If there are multiple hosts listed and several of them fail the weights will be added and again checked to see if they equal or exceed 255. The track-ip script only can run within a sixty-second window. Because of this the total run time is calculated   with the following formula: ((60 / ((count * interval) + (wait -1))). Any fractional number is remained so partial attempts are not run. It is important to calculate the total run time so it does not exceed 60 seconds.
33	 
34	Configuring Track IP Event Options
35	 
36	When the script starts it will test to see if the current routing engine is the primary for redundancy group zero, if it is not then the script will not run. Only the primary routing engine is able to generate pings so it will only execute script. Example two below the event-options configuration is shown.
37	 
38	[Event Option Configuration]
39	 
40	generate-event {
41	    TRACK-IP time-interval 60;
42	}
43	policy TRACK-IP {
44	    events TRACK-IP;
45	    then {
46	        event-script track-ip.xsl;
47	    }
48	}
49	event-script {
50	    file track-ip.xsl;
51	}
52	 
53	There are four important stanzas that are configured in example two. The first is generate event; this stanza generates a "TRACK-IP" event every sixty seconds. Then there is the policy "TRACK-IP". This policy listens for the "TRACK-IP" event. When it sees the event it executes the track-ip.xsl JUNOScript. Any output generated is sent to the destination TRACKIPLOG. The event script stanza loads the track-ip.xsl script and has JUNOS validate it so it is ready for execution.
54	 
55	Validating the Track IP Configuration
56	 
57	The configuration options that begin with "apply macro" are all user created options. Because of this JUNOS does not validate these by default. To create custom validation options a commit script must be used. To validate the track IP configuration the commit script "srx-ha-validate.xsl" was created. The script must be placed in the /var/db/scripts/commit directory. Secondly it must be added to the JUNOS configuration by using the command "set system scripts commit file srx-ha-validate.xsl". Upon the committing of this configuration the options for track IP will be validated. This prevents misspelling items like "routing-instance" or giving numbers that are out of the range of the scripts capabilities. In the event that an option is not correctly con figured a warning will be emitted. This does notify the administrator that something is not right. It will not prevent the misconfiguration of track IP; it just creates a warning message. This was done to ensure interoperability with the Network and Security Manager platform (NSM). In the event that a warning message is received simply review the message and resolve the error by correcting the configuration mistake.

 

SLAX Script Contents


001	/* Machine Crafted with Care (tm) by slaxWriter */
002	version 1.0;
003	 
004	 
005	/*
006	Copyright Juniper Networks 2008
007	All rights reserved and owned by Juniper Networks
008	 
009	For the SRX platform, the JUNOScripted track-ip implmentation allows the user to
010	utilize this critical feature on the SRX platform. It allows for path and next
011	hop validation through the existing network infrastructure with the ICMP protocol.
012	Upon detection of a failure the script will execute a failover to the other node
013	in an attempt to prevent downtime.
014	 
015	Authors: Rob Cameron (robc@juniper.net) and Patricio Giecco (pgiecco@juniper.net)
016	 
017	 */
018	 
019	/*
020	Things to do:
021	Add in more logging
022	 */
023	ns junos = "http://xml.juniper.net/junos/*/junos";
024	ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
025	ns ext = "http://xmlsoft.org/XSLT/namespace";
026	ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";
027	 
028	import "../import/junos.xsl";
029	/* srx-ha-lib.xsl file start */
030	/* use a global connection for all rpc connections */
031	var $connection = jcs:open();
032	/* Pull the chassis cluster status and use throughout the script */
033	var $get-cluster-status = <rpc> {
034	    <command> "show chassis cluster status";
035	}
036	var $cluster-status-results = jcs:execute($connection, $get-cluster-status);
037	var $chassis-cluster-rg-rpc = <rpc> {
038	    <get-configuration> {
039	        <configuration> {
040	            <chassis> {
041	                <cluster>;
042	            }
043	        }
044	    }
045	}
046	/* Pull the redundancy group information information out of the configuration, used throughout made global */
047	var $chassis-cluster-config = jcs:execute($connection, $chassis-cluster-rg-rpc);
048	/* use this as a global to determine the interface ownership by chassis model */
049	var $product-model = {
050	    call get-product-model();
051	}
052	var $get-interface-ownership = {
053	    if ($product-model == "srx5600") {
054	        var $node0-max-interface = 5;
055	        var $node0-min-interface = 0;
056	        var $node1-max-interface = 11;
057	        var $node1-min-interface = 6;
058	        <max-interface-number> {
059	            <node0-max> $node0-max-interface;
060	            <node0-min> $node0-min-interface;
061	            <node1-max> $node1-max-interface;
062	            <node1-min> $node1-min-interface;
063	        }
064	     
065	    } else if ($product-model == "srx5800") {
066	        var $node0-max-interface = 11;
067	        var $node0-min-interface = 0;
068	        var $node1-max-interface = 23;
069	        var $node1-min-interface = 12;
070	        <max-interface-number> {
071	            <node0-max> $node0-max-interface;
072	            <node0-min> $node0-min-interface;
073	            <node1-max> $node1-max-interface;
074	            <node1-min> $node1-min-interface;
075	        }
076	    }
077	}
078	var $chassis-interface-ownership = ext:node-set($get-interface-ownership);
079	/* end global section */
080	/* start template section */
081	/* Determine which interface are monitored */
082	template get-monitor-interface-current-weight ($redundancy-group) {
083	    var $results-get-monitor-interface-weight = jcs:execute($connection, $chassis-cluster-rg-rpc);
084	    var $interface-monitor-weight = $results-get-monitor-interface-weight/chassis/cluster/apply-macro[name == "failover-interface-monitor"]/data[name == "$redundancy-group"]/value;
085	     
086	    if (boolean($interface-monitor-weight)) {
087	        <text> $interface-monitor-weight;
088	     
089	    } else {
090	        <text> "0";
091	    }
092	}
093	 
094	/* Determine current time */
095	template get-current-time () {
096	    var $rpc-get-current-time = <rpc> {
097	        <get-system-uptime-information>;
098	    }
099	    var $results-get-current-time = jcs:execute($connection, $rpc-get-current-time);
100	     
101	    if ($results-get-current-time/multi-routing-engine-item) {
102	        var $current-time = $results-get-current-time/multi-routing-engine-item[1]/system-uptime-information/current-time/date-time/@junos:seconds;
103	        <text> $current-time;
104	     
105	    } else {
106	        var $current-time = $results-get-current-time/current-time/date-time/@junos:seconds;
107	        <text> $current-time;
108	    }
109	}
110	 
111	/* Check if RG0 is ready to failover */
112	template check-RG0-failback () {
113	    var $rg0-last-failover = {
114	        call get-rg0-last-failover();
115	    }
116	    var $current-time = {
117	        call get-current-time();
118	    }
119	    var $local-node = {
120	        call get-local-node();
121	    }
122	    var $rg0-master = {
123	        call get-master() {
124	            with $redundancy-group = {
125	                expr "0";
126	             }
127	        }
128	    }
129	    var $rg1-master = {
130	        call get-master() {
131	            with $redundancy-group = {
132	                expr "1";
133	             }
134	        }
135	    }
136	    var $rg0-primary-node = {
137	        /* Check who is the primary and whether the cluster has not been failed over already */
138	        if ($cluster-status-results/redundancy-group[1]/device-stats/redundancy-group-status[1] == "secondary" && $cluster-status-results/redundancy-group[1]/device-stats/redundancy-group-status[2] == "primary" && $cluster-status-results/redundancy-group[1]/device-stats/failover-mode[2] == "no") {
139	            /* failover RG to node0 */
140	            <text> "0";
141	         
142	        } else if ($cluster-status-results/redundancy-group[1]/device-stats/redundancy-group-status[1] == "primary" && $cluster-status-results/redundancy-group[1]/device-stats/redundancy-group-status[2] == "secondary" && $cluster-status-results/redundancy-group[1]/device-stats/failover-mode[1] == "no") {
143	            /* failover RG to node1 */
144	            <text> "1";
145	        }
146	    }
147	     
148	    if ($local-node == $rg0-master) {
149	        if ($rg0-master != $rg1-master) {
150	            if (($current-time) >($rg0-last-failover + 300)) {
151	                call request-rg-failover($node = $rg0-primary-node) {
152	                    with $redundancy-group = {
153	                        expr "0";
154	                     }
155	                }
156	            }
157	        }
158	    }
159	}
160	 
161	 
162	/* Check to to see the manual failover flag needs to be reset, if it does then reset it for all of the rgs
163	 
164	 */
165	template check-and-reset-manual-failover-flag () {
166	    if (boolean($chassis-cluster-config/chassis/cluster/apply-macro[name == "monitoring-options"]/data[name == "clear-failover"])) {
167	        var $rpc-check-manual-failover-flag = <rpc> {
168	            <command> "show chassis cluster status";
169	        }
170	        var $result-check-manual-failover-flag = jcs:execute($connection, $rpc-check-manual-failover-flag);
171	        var $result-check-manual-failover-flag-node-set = ext:node-set($result-check-manual-failover-flag);
172	         
173	        for-each ($result-check-manual-failover-flag//redundancy-group) {
174	            if (./device-stats/failover-mode[1] == "yes") {
175	                call reset-failover-flag($redundancy-group = ./redundancy-group-id[1]);
176	            }
177	        }
178	    }
179	}
180	 
181	/* Determine the minute in the configuration */
182	template get-rg0-last-failover () {
183	    var $results-get-rg0-last-failover = jcs:execute($connection, $chassis-cluster-rg-rpc);
184	    var $last-rg0-failover-time = $results-get-rg0-last-failover/chassis/cluster/apply-macro[name == "failover-monitoring"]/data[name == "last-failover"]/value;
185	     
186	    if (boolean($last-rg0-failover-time)) {
187	        <text> $last-rg0-failover-time;
188	     
189	    } else {
190	        <text> "0";
191	    }
192	}
193	 
194	/* Insert the last minute into the configuration */
195	template set-rg0-last-failover () {
196	    var $current-time = {
197	        call get-current-time();
198	    }
199	    /* <xsl:value-of select="jcs:output(concat('Setting last failover time for RG0 to ', $current-time))"/> */
200	    var $rpc-configure-private = <rpc> {
201	        <open-configuration> {
202	            <private>;
203	        }
204	    }
205	     
206	    expr jcs:execute($connection, $rpc-configure-private);
207	    var $rpc-set-rg0-last-failover = <rpc> {
208	        <load-configuration> {
209	            <configuration> {
210	                <chassis> {
211	                    <cluster> {
212	                        <apply-macro> {
213	                            <name> "failover-monitoring";
214	                            <data> {
215	                                <name> "last-failover";
216	                                <value> $current-time;
217	                            }
218	                        }
219	                    }
220	                }
221	            }
222	        }
223	    }
224	    expr jcs:execute($connection, $rpc-set-rg0-last-failover);
225	    var $commit = <rpc> {
226	        <commit-configuration>;
227	    }
228	    expr jcs:execute($connection, $commit);
229	}
230	 
231	/* Insert the last minute into the configuration */
232	template set-track-interface-last-weight ($weight = 0, $redundancy-group) {
233	    var $current-weight = {
234	        call get-monitor-interface-current-weight($redundancy-group);
235	    }
236	    var $total-weight = $weight + $current-weight;
237	    /* <xsl:value-of select="jcs:output(concat('Setting track interface weight to ', $weight, ' for RG ', $redundancy-group))"/> */
238	    /* <xsl:value-of select="jcs:output(concat('Setting last failover time for RG0 to ', $current-time))"/> */
239	    var $rpc-configure-private = <rpc> {
240	        <open-configuration> {
241	            <private>;
242	        }
243	    }
244	     
245	    expr jcs:execute($connection, $rpc-configure-private);
246	    var $rpc-set-track-interface-last-weight = <rpc> {
247	        <load-configuration> {
248	            <configuration> {
249	                <chassis> {
250	                    <cluster> {
251	                        <apply-macro> {
252	                            <name> "failover-interface-monitor";
253	                            <data> {
254	                                <name> $redundancy-group;
255	                                <value> $total-weight;
256	                            }
257	                        }
258	                    }
259	                }
260	            }
261	        }
262	    }
263	    expr jcs:execute($connection, $rpc-set-track-interface-last-weight);
264	    var $commit = <rpc> {
265	        <commit-configuration>;
266	    }
267	    expr jcs:execute($connection, $commit);
268	}
269	 
270	/* abstract the actual failover command outside of request failover */
271	template request-rg-failover ($node, $redundancy-group) {
272	     
273	    if ($redundancy-group != "") {
274	        /* rpc command for failover */
275	        var $rpc-failover = <rpc> {
276	            <command> {
277	                expr "request chassis cluster failover node ";
278	                expr $node;
279	                expr " redundancy-group ";
280	                expr $redundancy-group;
281	            }
282	        }
283	         
284	        expr jcs:execute($connection, $rpc-failover);
285	    }
286	    /* added to allow command take effect */
287	    expr jcs:sleep(0, 500);
288	}
289	 
290	 
291	/*
292	request-failover :: Chassis failover
293	This template performs an rg failover of the requested group
294	 
295	@param redundancy-group specifies the redundancy group to failover, defaults to 1
296	@param reset-flag specifies the manual failover flag should be cleared, defaults to false
297	@param fullfailover-flag specifies if both redundancy groups should be failed over, defaults to faulse
298	@param rg0-failover-check specifies if the failover time should be checked, defaults to true
299	 */
300	template request-failover () {
301	    param $redundancy-group = {
302	        expr "1";
303	    }
304	    param $reset-flag = {
305	        expr false();
306	    }
307	    param $fullfailover-flag = {
308	        expr "0";
309	    }
310	    param $rg0-failover-check = {
311	        expr "1";
312	    }
313	    /* Define which RG to failover */
314	    /* force the selection of a parameter disable the default */
315	    /* Chosing this forces both RGs to failover */
316	    /* Verify if its safe to failover RG0 */
317	    /* determite the other RG that would need to failover in a full failover */
318	    var $other-redundancy-group = {
319	        if ($redundancy-group == 0) {
320	            <text> "1";
321	         
322	        } else if ($redundancy-group == 1) {
323	            <text> "0";
324	        }
325	    }
326	    /* used to determine if we should fully failover */
327	    var $rg0-master = {
328	        call get-master() {
329	            with $redundancy-group = {
330	                expr "0";
331	             }
332	        }
333	    }
334	    var $rg1-master = {
335	        call get-master() {
336	            with $redundancy-group = {
337	                expr "1";
338	             }
339	        }
340	    }
341	    var $rg0-last-failover = {
342	        call get-rg0-last-failover();
343	    }
344	    var $current-time = {
345	        call get-current-time();
346	    }
347	     
348	    /* <xsl:variable name="local-node">
349	    <xsl:call-template name="get-local-node"/>
350	    </xsl:variable> */
351	    var $rg-primary-node = {
352	        /* Check who is the primary and whether the cluster has not been failed over already */
353	        if ($cluster-status-results/redundancy-group[$redundancy-group + 1]/device-stats/redundancy-group-status[1] == "secondary" && $cluster-status-results/redundancy-group[$redundancy-group + 1]/device-stats/redundancy-group-status[2] == "primary" && $cluster-status-results/redundancy-group[$redundancy-group + 1]/device-stats/failover-mode[2] == "no") {
354	            /* failover RG to node0 */
355	            <text> "0";
356	         
357	        } else if ($cluster-status-results/redundancy-group[$redundancy-group + 1]/device-stats/redundancy-group-status[1] == "primary" && $cluster-status-results/redundancy-group[$redundancy-group + 1]/device-stats/redundancy-group-status[2] == "secondary" && $cluster-status-results/redundancy-group[$redundancy-group + 1]/device-stats/failover-mode[1] == "no") {
358	            /* failover RG to node1 */
359	            <text> "1";
360	        }
361	    }
362	    var $rg0-primary-node = {
363	        /* Check who is the primary and whether the cluster has not been failed over already */
364	        if ($cluster-status-results/redundancy-group[1]/device-stats/redundancy-group-status[1] == "secondary" && $cluster-status-results/redundancy-group[1]/device-stats/redundancy-group-status[2] == "primary" && $cluster-status-results/redundancy-group[1]/device-stats/failover-mode[2] == "no") {
365	            /* failover RG to node0 */
366	            <text> "0";
367	         
368	        } else if ($cluster-status-results/redundancy-group[1]/device-stats/redundancy-group-status[1] == "primary" && $cluster-status-results/redundancy-group[1]/device-stats/redundancy-group-status[2] == "secondary" && $cluster-status-results/redundancy-group[1]/device-stats/failover-mode[1] == "no") {
369	            /* failover RG to node1 */
370	            <text> "1";
371	        }
372	    }
373	     
374	    /*
375	    Execute the failover to the other chassis
376	     */
377	    if (boolean($rg0-failover-check == 1)) {
378	        if (boolean($rg-primary-node != "")) {
379	            if (boolean($fullfailover-flag &&((($rg0-master == "node0") &&($rg1-master == "node0")) ||(($rg0-master == "node1") &&($rg1-master == "node1"))))) {
380	                if (($current-time) >($rg0-last-failover + 300)) {
381	                    var $time-diff = $current-time - $rg0-last-failover;
382	                     
383	                    expr jcs:syslog(146, concat($time-diff, " seconds since last failover of RG0. Failing over RG0 to node", $rg-primary-node));
384	                    /* <xsl:value-of select="jcs:output(concat($time-diff, ' seconds since last failover of RG0. Failing over RG0.'))"/> */
385	                    /* <xsl:value-of select="jcs:output('Requesting failover for RG1')"/> */
386	                    expr jcs:syslog(146, concat("Requesting failover for RG1 to node", $rg-primary-node));
387	                    call request-rg-failover($node = $rg-primary-node, $redundancy-group);
388	                    /* full failover matched requesting RG0 failover */
389	                    call request-rg-failover($node = $rg0-primary-node, $redundancy-group = $other-redundancy-group);
390	                    call set-rg0-last-failover();
391	                 
392	                } else {
393	                    var $time-diff = $current-time - $rg0-last-failover;
394	                     
395	                    expr jcs:syslog(146, concat("Not enough time has passed to failover RG0 only ", $time-diff, " seconds have passed on node", $rg0-primary-node));
396	                    /* <xsl:value-of select="jcs:output(concat('Not enough time has passed to failover RG0 only ', $time-diff, ' seconds have passed'))"/> */
397	                    /* <xsl:value-of select="jcs:output('Requesting failover for RG1')"/> */
398	                    expr jcs:syslog(146, concat("Requesting failover for RG1 to node", $rg-primary-node));
399	                    call request-rg-failover($node = $rg-primary-node) {
400	                        with $redundancy-group = {
401	                            expr "1";
402	                         }
403	                    }
404	                }
405	             
406	            } else if ($redundancy-group == 0) {
407	                if ($current-time >($rg0-last-failover + 300)) {
408	                    var $time-diff = $current-time - $rg0-last-failover;
409	                    /* <xsl:value-of select="jcs:output(concat($time-diff, ' seconds since last failover of RG0. Failing over RG0.'))"/> */
410	                    expr jcs:syslog(146, concat($time-diff, " seconds since last failover of RG0. Failing over RG0 to node", $rg-primary-node));
411	                    call request-rg-failover($node = $rg-primary-node, $redundancy-group);
412	                    call set-rg0-last-failover();
413	                 
414	                } else {
415	                    var $time-diff = $current-time - $rg0-last-failover;
416	                    /* <xsl:value-of select="jcs:output(concat('Not enough time has passed to failover RG0 over ', $time-diff, ' seconds have passed'))"/> */
417	                    expr jcs:syslog(146, concat("Not enough time has passed to failover RG0 only ", $time-diff, " seconds have passed on node", $rg0-primary-node));
418	                }
419	             
420	            } else if ($redundancy-group == 1) {
421	                expr jcs:syslog(146, concat("Requesting failover for RG1 to node", $rg-primary-node));
422	                call request-rg-failover($node = $rg-primary-node, $redundancy-group);
423	            }
424	        }
425	     
426	    } else {
427	        if (boolean($rpc-failover != "")) {
428	            if (boolean($fullfailover-flag)) {
429	                /* <xsl:value-of select="jcs:output('Requesting full failover for both RG0 and RG1')"/> */
430	                expr jcs:syslog(146, concat("Requesting failover for RG0 and RG1 to node", $rg-primary-node));
431	                call request-rg-failover($node = $rg-primary-node, $redundancy-group);
432	                /* full failover matched requesting RG0 failover */
433	                call request-rg-failover($node = $rg0-primary-node, $redundancy-group = $other-redundancy-group);
434	                call set-rg0-last-failover();
435	             
436	            } else if ($redundancy-group == 0) {
437	                /* <xsl:value-of select="jcs:output('Requesting failover for RG0')"/> */
438	                expr jcs:syslog(146, concat("Requesting failover for RG0 to node", $rg0-primary-node));
439	                call request-rg-failover($node = $rg-primary-node, $redundancy-group);
440	                call set-rg0-last-failover();
441	             
442	            } else if ($redundancy-group == 1) {
443	                /* <xsl:value-of select="jcs:output('Requesting failover for RG1')"/> */
444	                expr jcs:syslog(146, concat("Requesting failover for RG1 to node", $rg-primary-node));
445	                call request-rg-failover($node = $rg-primary-node, $redundancy-group);
446	            }
447	        }
448	    }
449	     
450	    /*
451	    Clear the failover status if requested
452	     */
453	    if (boolean($reset-flag)) {
454	        if (boolean($fullfailover-flag)) {
455	            call reset-failover-flag($redundancy-group);
456	            call reset-failover-flag($redundancy-group = $other-redundancy-group);
457	         
458	        } else {
459	            call reset-failover-flag($redundancy-group);
460	        }
461	    }
462	}
463	 
464	 
465	/*
466	reset-failover-flag :: Get Master
467	This template is used to reset the failover flag
468	 
469	@param redundancy-group specifies the redundancy group to failover, 1 is the default
470	 */
471	template reset-failover-flag () {
472	    param $redundancy-group = {
473	        expr "1";
474	    }
475	    var $rpc-clear-failover-flag = <rpc> {
476	        <command> {
477	            expr "request chassis cluster failover reset redundancy-group ";
478	            expr $redundancy-group;
479	        }
480	    }
481	     
482	    /* <xsl:value-of
483	    select="jcs:output(concat('Reseting manual failover for redundancy group ', $redundancy-group))"/> */
484	    expr jcs:syslog(146, concat("Reseting manual failover for redundancy group ", $redundancy-group));
485	    expr jcs:execute($connection, $rpc-clear-failover-flag);
486	    expr jcs:sleep(0, 500);
487	}
488	 
489	 
490	/*
491	get-master :: Get Master
492	This template is used to determine device is master of a redundancy group (RG0 by default).
493	 
494	@param redundancy-group specifies the redundancy group to check master default is 0
495	 */
496	template get-master () {
497	    param $redundancy-group = {
498	        expr "0";
499	    }
500	    /* Determine the master of the chassis cluster */
501	    var $rg-node0-priority = $cluster-status-results/redundancy-group[$redundancy-group + 1]/device-stats/redundancy-group-status[1];
502	    var $rg-node1-priority = $cluster-status-results/redundancy-group[$redundancy-group + 1]/device-stats/redundancy-group-status[2];
503	     
504	    if (not($rg-node0-priority) || not($rg-node1-priority)) {
505	        /* One Device is not communicating to the other the test will not run */
506	         
507	        /* <xsl:value-of
508	        select="jcs:output('Only one cluster member has been found. Check connectivity to the other cluster member.')"
509	        /> */
510	     
511	    } else if ($rg-node0-priority == "primary" && $rg-node1-priority != "primary") {
512	        /* Node0 is the primary returning Node0 */
513	        /* <xsl:value-of select="jcs:output(concat('Node0 is the master for redundancy group: ', $redundancy-group))"/> */
514	        <text> "node0";
515	     
516	    } else if ($rg-node0-priority != "primary" && $rg-node1-priority == "primary") {
517	        /* Node1 is the primary returning Node1 */
518	        /* <xsl:value-of select="jcs:output(concat('Node1 is the master for redundancy group: ', $redundancy-group))"/> */
519	        <text> "node1";
520	     
521	    } else {
522	        /* priorities are the same */
523	        /* <xsl:value-of select="jcs:output('An unexpected result has occured while checking the node status.')" /> */
524	    }
525	}
526	 
527	/* Return the local node value */
528	template get-local-node () {
529	    var $get-local-RE = <rpc> {
530	        <command> "show chassis routing-engine node local";
531	    }
532	    /* Get the local RE node */
533	    var $local-check-results = jcs:execute($connection, $get-local-RE);
534	    <text> $local-check-results/multi-routing-engine-item/re-name;
535	}
536	 
537	 
538	/*
539	get-manual-failover-flag :: Get manual failover flag
540	This template is used to determine if the failover flag is set
541	 
542	@param redundancy-group specifies the redundancy group to check master default is 0
543	 */
544	template get-manual-failover-flag ($redundancy-group) {
545	    var $rpc-check-manual-failover-flag = <rpc> {
546	        <command> "show chassis cluster status";
547	    }
548	    var $result-check-manual-failover-flag = jcs:execute($connection, $rpc-check-manual-failover-flag);
549	    <text> $result-check-manual-failover-flag/redundancy-group[$redundancy-group + 1]/device-stats/failover-mode[1];
550	}
551	 
552	/* determine and return the current product model */
553	template get-product-model () {
554	    var $rpc-product-model = <rpc> {
555	        <command> "show version";
556	    }
557	    var $results-product-model = jcs:execute($connection, $rpc-product-model);
558	     
559	    if ($results-product-model/multi-routing-engine-item) {
560	        <text> $results-product-model/multi-routing-engine-item[1]/software-information/product-model;
561	     
562	    } else {
563	        expr $results-product-model/software-information/product-model;
564	    }
565	}
566	 
567	/* end template section */
568	/* srx-ha-lib.xsl file end */
569	/* Global variables */
570	var $local-node-name = {
571	    call get-local-node();
572	}
573	/* Determine the master for RG0 */
574	var $master-node-name = {
575	    call get-master() {
576	        with $redundancy-group = {
577	            expr "0";
578	         }
579	    }
580	}
581	var $master-RG1 = {
582	    call get-master() {
583	        with $redundancy-group = {
584	            expr "1";
585	         }
586	    }
587	}
588	var $node-regex = "(node)([0-9]+)";
589	var $local-node-number = jcs:regex($node-regex, $local-node-name);
590	var $rg1-node-number = jcs:regex($node-regex, $master-RG1);
591	 
592	/*
593	ping-server :: Ping server
594	This template returns the status of the server by using
595	the ping rpc provided by JUNOS
596	 
597	@param host: the IP address or hostname of the system
598	@param interval: the time between ping attempts 1 second is the default
599	@param count: the total number of ping attempts 3 attepmts is the default
600	 */
601	template ping-server ($host, $interval, $count, $wait, $routing-instance) {
602	    /* Optimize template to provide defaults for params */
603	    /* This variable is the JUNOScript RPC call to execute the ping */
604	    var $rpc-ping = <rpc> {
605	        <ping> {
606	            <host> $host;
607	            if (boolean($interval)) {
608	                <interval> $interval;
609	             
610	            } else {
611	                <interval> "0.1";
612	            }
613	            if (boolean($count)) {
614	                <count> $count;
615	             
616	            } else {
617	                <count> "3";
618	            }
619	            if (boolean($wait)) {
620	                <wait> $wait;
621	             
622	            } else {
623	                <wait> "1";
624	            }
625	            if (boolean($routing-instance)) {
626	                <routing-instance> $routing-instance;
627	            }
628	            <verbose>;
629	        }
630	    }
631	    /* contains the results from the ping test */
632	    var $ping-results = jcs:execute($connection, $rpc-ping);
633	    /* counts the number of successful pings */
634	    var $ping-ok = count($ping-results/probe-result/probe-success);
635	    /* <xsl:value-of select="jcs:output(concat('SUCCESS COUNT ', $ping-ok))"/> */
636	    if ($ping-ok != 0) {
637	        expr "ok";
638	     
639	    } else {
640	        expr "nok";
641	    }
642	}
643	 
644	 
645	/*
646	main :: The starting point and main template for track ip
647	This is the main loop for the test.
648	It executes the ping tests and then will failover the cluster if there is an issue.
649	 
650	@param count the specified number of times this loop should run
651	 */
652	template main ($count) {
653	    /* check to see if we need to ruin through the loop again */
654	    if ($count > 0) {
655	        /* Log the iteration number */
656	        /* <xsl:value-of select="jcs:output(concat('checking servers ',$count,' iterations to go'))"/> */
657	        /* This variable stores the list of RGs that need to be failed over */
658	        var $ping-test-results = <redundancy-groups> {
659	             
660	            for-each ($chassis-cluster-config//cluster/redundancy-group) {
661	                var $rg = ./name;
662	                <redundancy-group> {
663	                    <name> $rg;
664	                     
665	                    /* Loop through the apply-macro track-* statements and check each server
666	                    adds a server node to the redundancy group for each host tracked */
667	                     
668	                    for-each (./apply-macro[starts-with(name, "track-")]) {
669	                        var $server-status = {
670	                            /* Ping with the user specified ping count */
671	                            call ping-server($host = ./data[name == "server"]/value, $count = ./data[name == "count"]/value, $wait = ./data[name == "wait"]/value, $interval = ./data[name == "interval"]/value, $routing-instance = ./data[name == "routing-instance"]/value);
672	                        }
673	                         
674	                        if ($server-status == "nok") {
675	                            <server> {
676	                                <name> name;
677	                                <weight> ./data[name == "weight"]/value;
678	                            }
679	                         
680	                        } else if ($server-status == "ok") {
681	                            /* Do nothing */
682	                        }
683	                    }
684	                }
685	            }
686	        }
687	        var $rg-ping-results = ext:node-set($ping-test-results);
688	         
689	        if ($rg-ping-results/redundancy-groups/redundancy-group[sum(server/weight) > 254]) {
690	            expr jcs:output($ping-test-results);
691	            /* failover each redundancy group that exceeds 254 */
692	             
693	            for-each ($rg-ping-results/redundancy-groups/redundancy-group[sum(server/weight) > 254]) {
694	                /* <xsl:value-of select="jcs:output(concat('RG:', name ,' needs to be failed over'))"/> */
695	                call request-failover($redundancy-group = name, $reset-flag = boolean($chassis-cluster-config/chassis/cluster/apply-macro[name == "monitoring-options"]/data[name == "clear-failover"]), $fullfailover-flag = boolean($chassis-cluster-config/chassis/cluster/apply-macro[name == "monitoring-options"]/data[name == "full-failover"]));
696	                call set-rg0-last-failover();
697	            }
698	         
699	        } else {
700	            /* <xsl:value-of select="jcs:output('Tested servers are ok')"/> */
701	            call main($count = $count - 1);
702	        }
703	     
704	    } else {
705	        /* No more interations to run */
706	        /* determine if RG0 should follow the leader RG1 */
707	        call check-RG0-failback();
708	    }
709	}
710	 
711	match / {
712	    <op-script-results> {
713	        /* In here we loop through the Track-ip statements and execute pings against them */
714	        if (($local-node-name == $master-node-name) && $cluster-status-results/redundancy-group[2]/device-stats[1]/device-priority[$rg1-node-number[3] + 1] != 0) {
715	            /* <xsl:value-of select="jcs:output('Node is the master of RG0, cheking tracked objects')"/> */
716	            /* Figure out how long it takes to check all the servers */
717	            var $runtimes = <exec-time> {
718	                 
719	                for-each ($chassis-cluster-config//cluster/redundancy-group) {
720	                     
721	                    for-each (./apply-macro[starts-with(name, "track-")]) {
722	                        <time> {
723	                            var $count = {
724	                                if (boolean(./data[name == "count"]/value)) {
725	                                    expr ./data[name == "count"]/value;
726	                                 
727	                                } else {
728	                                    expr "3";
729	                                }
730	                            }
731	                            var $interval = {
732	                                if (boolean(./data[name == "interval"]/value)) {
733	                                    expr ./data[name == "interval"]/value;
734	                                 
735	                                } else {
736	                                    expr "0.1";
737	                                }
738	                            }
739	                            var $wait = {
740	                                if (boolean(./data[name == "wait"]/value)) {
741	                                    expr ./data[name == "wait"]/value;
742	                                 
743	                                } else {
744	                                    expr "1";
745	                                }
746	                            }
747	                             
748	                            expr (($count * $interval) +($wait - 1)) * 0.668;
749	                        }
750	                    }
751	                }
752	            }
753	            var $total-runtime = sum(ext:node-set($runtimes)//time);
754	             
755	            /* <xsl:value-of
756	            select="jcs:output(concat('It will take at most ',$total-runtime, ' seconds to run each iteration'))"/> */
757	            var $execute-iterations = ceiling(60 div $total-runtime);
758	             
759	            call main($count = $execute-iterations);
760	         
761	        } else if ($cluster-status-results/redundancy-group[2]/device-stats[1]/device-priority[$rg1-node-number[3] + 1] == 0) {
762	             
763	            /* <xsl:value-of
764	            select="jcs:output('Node is the maser of RG0. RG1 master in priority 0 state. Nothing to do!')"/> */
765	         
766	        } else {
767	            /* This note is not master so it shouldn't ping as it will fail */
768	             
769	            /* <xsl:value-of
770	            select="jcs:output('Node is not the maser of RG0. Nothing to do!')"/> */
771	        }
772	    }
773	}

 

XML Script Contents


01	<?xml version="1.0"?>
02	<script>
03	<author>rcameron</author>
04	<title>track-ip.slax</title>
05	<synopsis>
06	This event script implements the Track-IP feature on the SRX platforms.
07	</synopsis>
08	<coe>event</coe>
09	<type>HA</type>
10	 
11	<description>
12	For the SRX platform, the Track-IP feature allows for path and next hop validation through the existing network infrastructure with the ICMP protocol. Upon the detection of a failure the script will execute a failover to the other node in an attempt to prevent downtime
13	</description>
14	 
15	 <example>
16	 <title>Example</title>
17	 <config>example-1.conf</config>
18	 </example>
19	 
20	<xhtml:script xmlns:xhtml="http://www.w3.org/1999/xhtml"
21	src="../../../../../web/leaf.js"
22	type="text/javascript"/>
23	</script>

#ScriptingHow-To
#srxseries
#eventscript
#How-To
#track-ip
#Slax