IN THIS PAGE
ACX Deployment Scripts
The following scripts are used to deploy ACX routers as part of the ZTD Push and Pull methods.
Phase 0 Script
version 1.1; /* ------------------------------------------------------------------ */ /* This program performs Zero touch provisioning for the ACX platform */ /* It will load global configuration template from a remote location */ /* specified in the original configuration file loaded as a result */ /* of the autoconfiguration process. */ /* Version 1.0 User1 user1@example.com */ /* ------------------------------------------------------------------ */ /* XML namespaces */ /* ------------------------------------------------------------------ */ /* Juniper */ 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"; ns exsl extension = "http://exslt.org/common"; /* EXSLT */ ns str extension = "http://exslt.org/strings"; /* private namespace for this script */ ns ztp_script = "http://xml.juniper.com/ztp_script/1.0"; import '../import/junos.xsl'; /* ------------------------------------------------------------------ */ /* Constants */ /* ------------------------------------------------------------------ */ var $APPNAME = 'ztp_script[' _ $junos-context/pid _ ']'; var $JNPR_ZTP_SCRIPT = "ZTP Phase 0 SCRIPT"; var $SYSLOG = 'user.info'; var $TMPDIR = '/var/tmp'; var $CODEDIR = '/var/tmp'; var $ZTP_GROUP_NAME = "GR-ZTP"; var $ZTP_GROUP_STAGE_0 = "GR-ZTP-STAGE-0"; var $ZTP_GROUP_STAGE_1 = "GR-ZTP-STAGE-1"; var $ZTP_GROUP_STAGE_2 = "GR-ZTP-STAGE-2"; var $ZTP_CODE_MACRO_NAME = "CODE"; var $ZTP_CONFIG_MACRO_NAME = "CONFIG"; var $ZTP_CONFIG = "CONFIG"; var $ZTP_LOCKFILE = '/tmp/ztp_script.lock'; /* ------------------------------------------------------------------ */ /* Global variables */ /* ------------------------------------------------------------------ */ var $jnx = jcs:open(); /* ------------------------------------------------------------------ */ /* MAIN */ /* ------------------------------------------------------------------ */ match / { if( not( $jnx )) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": ERROR: unable to connect to Junos API"); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to connect to Junos API"); expr jcs:output( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to connect to Junos API"); terminate; } var $running = ztp_script:only_once(); if( $running ) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": process already running, backing off" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": process already running, backing off" ); expr jcs:output( $JNPR_ZTP_SCRIPT _ ": process already running, backing off" ); terminate; } expr jcs:syslog( $SYSLOG, $APPNAME _ ": ZTP phase 0 BEGIN" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTP phase 0 BEGIN" ); /*----------------------------------------------------------------*/ /* PHASE-0: LOAD GLOBAL CSR TEMPLATE */ /*----------------------------------------------------------------*/ /* Check if configuration for the next ZTP PHASE exists */ if ( not( ztp_script:ztp_grp_exists($ZTP_GROUP_NAME, $ZTP_CONFIG_MACRO_NAME) ) ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuration file name for global template (phase 0) not specified. Stop at this point" ); var $die = ztp_script:terminate(); } var $get = <get-configuration> { <configuration> { <groups> { <name> $ZTP_GROUP_NAME; } } } var $got = jcs:execute( $jnx, $get ); var $got_copy = $got; /* global ztp parameters for access node */ var $ztp_config_file = $got/groups[name=$ZTP_GROUP_NAME]/apply-macro[name=$ZTP_CONFIG_MACRO_NAME]/data[name=$ZTP_CONFIG]/value; /*-------------------------------------------------------*/ /* LOAD NEW ZTP PARAMETERS */ /*-------------------------------------------------------*/ if (not (ztp_script:load_config($ztp_config_file))) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: Global configuration template was not loaded. File not found or bad configuration"); var $die = ztp_script:terminate(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTP Global configuration template loaded" ); } /*----------------------------------------------------------------*/ /* Deactivate configuration group for PHASE-0 */ /* Activate configuration group for PHASE-1 if exists */ /*----------------------------------------------------------------*/ var $options_s0 := { <commit-options> { <log> "Enabling ZTP PHASE-1"; } } var $change_s0 = { <configuration> { <apply-groups delete = "delete"> $ZTP_GROUP_STAGE_0; if ( ztp_script:ztp_grp_exists($ZTP_GROUP_STAGE_1) ) { <apply-groups> $ZTP_GROUP_STAGE_1; } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Group name " _$ZTP_GROUP_STAGE_1 _ " with PHASE-1 script name and location NOT FOUND in global template. STOP ZTP AT THIS POINT" ); var $die = ztp_script:terminate(); } } } /* Load configuration */ var $results_stage_0 := { call jcs:load-configuration( $action="merge", $commit-options=$options_s0, $configuration=$change_s0, $connection = $jnx ); } if ($results_stage_0//xnm:warning) { for-each ($results_stage_0//xnm:warning) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": commit warning: " _ message ); } } if ($results_stage_0//xnm:error) { for-each ($results_stage_0//xnm:error) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": commit error: " _ message ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTP PHASE 0 Script failed." ); var $die = ztp_script:terminate(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTP Phase 0 completed SUCCESSFULLY" ); } var $die = ztp_script:terminate(); } /* ------------------------------------------------------------------ */ /* FUNCTION load_config LOADS CONFIGURATION FROM FILE */ /* ------------------------------------------------------------------ */ function ztp_script:load_config($config_url, $action = "merge") { mvar $load_config = true(); var $phrase = { if ($action == "merge") { expr "merged to existed configuration"; } else { if ($action == "replace") { expr " and replace existed statements"; } else { expr " be merged (default action) to existed configuration"; } } } var $new_action = { if (($action == "merge") or ($action == "replace")) { expr $action; } else { expr "merge"; } } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Config file: " _ $config_url _ " will be loaded and " _ $phrase ); /* lock the config */ var $lock = <lock-configuration>; var $did_lock = jcs:execute( $jnx, $lock ); if ( $did_lock//self::xnm:error ) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": ERROR: unable to lock config" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to lock config" ); set $load_config = false(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Got config lock" ); } if ($load_config) { set $load_config = false(); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Processing config url " _ $config_url ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Processing config url " _ $config_url ); /* load in new config */ var $do_load = <load-configuration action="merge" url=$config_url format="text">; var $did_load = jcs:execute( $jnx, $do_load ); if( not( $did_load/load-success )) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": ERROR: unable to load config " _ $config_url ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to load config " _ $config_url ); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuration was loaded" ); var $commit = <commit-configuration> { <full>; <synchronize>; <force-synchronize>; <log> "Initial config load"; } var $did_commit = jcs:execute( $jnx, $commit ); if ( $did_commit//self::xnm:error ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: Commit failed" ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": ERROR: Commit failed" ); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuration was committed" ); /* * reboot here * var $reboot := jcs:execute( $jnx, 'request-reboot' ); */ var $unlock = <unlock-configuration>; var $did_unlock = jcs:execute( $jnx, $unlock ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": release config lock" ); set $load_config = true(); } } } /* end of foreach config_url */ if (not($load_config)) { /* if we make it here, we failed to load the config */ var $unlock = <unlock-configuration>; var $did_unlock = jcs:execute( $jnx, $unlock ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": release config lock" ); } result $load_config; } /* --------------------------------------------------------------------------------- */ /* FUNCTION ztp_grp_exists VERIFIES IF configuration group name and apply-macro name*/ /* EXIST IN THE CONFIGURATION and RETURNES True or False /* --------------------------------------------------------------------------------- */ function ztp_script:ztp_grp_exists($group_name, $macro_name = "N/A") { var $get_grp = <get-configuration> { <configuration> { <groups> { <name>; } } } /* geting variables from apply-macro */ var $got_grp = jcs:execute( $jnx, $get_grp ); mvar $grp_flag = "skip"; for-each ($got_grp/groups/name) { set $grp_flag = { if ((../name!=$group_name) and ($grp_flag!="exists")) { expr "skip"; } else { expr "exists"; } /* End if */ } } /* Verification for the apply-macro */ if ($grp_flag != "exists") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Can't find a group " _ $group_name); result false(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found a group " _ $group_name); if ( $macro_name!="N/A") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Looking for apply-macro " _ $macro_name _ " in group " _ $group_name ); /* Look for apply-macro with specified name */ var $get_mcr = <get-configuration> { <configuration> { <groups> { <name> $group_name; } } } /* getting variables from apply-macro */ var $got_mcr = jcs:execute( $jnx, $get_mcr ); mvar $mcr_flag = "skip"; for-each ($got_mcr/groups[name=$group_name]/apply-macro/name) { set $mcr_flag = { if ((../name!=$macro_name) and ($mcr_flag!="exists")) { expr "skip"; } else { expr "exists"; } /* End if */ } } /* Verification for the group */ if ($mcr_flag != "exists") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Can't find apply-macro " _ $macro_name ); result false(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found apply-macro " _ $macro_name ); result true(); } } else { result true(); } } } /* ------------------------------------------------------------------ */ /* Helper routines /* ------------------------------------------------------------------ */ function ztp_script:file-exists( $filename ) { var $ls_file = <file-list> { <path> $filename; } var $ls_got = jcs:execute( $jnx, $ls_file ); var $retval = boolean( $ls_got//file-information ); result $retval; } function ztp_script:file-delete( $filename ) { var $do_rm = <file-delete> { <path> $filename; } var $did_rm = jcs:execute( $jnx, $do_rm ); /* @@@ trap error */ result true(); } function ztp_script:only_once() { if( ztp_script:file-exists( $ZTP_LOCKFILE )) { result true(); } else { var $do_lock = <file-put> { <filename> $ZTP_LOCKFILE; <encoding> 'ascii'; <file-contents> 'locked'; } var $did_lock = jcs:execute( $jnx, $do_lock ); result false(); } } function ztp_script:terminate() { expr jcs:syslog( $SYSLOG, $APPNAME _ ": SCRIPT-TERMINATE" ); var $rm_lock = ztp_script:file-delete( $ZTP_LOCKFILE ); terminate; }
Phase 1 Script
version 1.1; /* ------------------------------------------------------------------ */ /* This script performs PHASE-1 of the zero touch provisioning for */ /* the ACX platform. Script used for provisioning of the Layer 2 oam */ /* plane which enables management access to the access node on its */ /* interface. At the end of PHASE-1 Script will enable configuration */ /* for the following elements: */ /* 1. IRB Interface */ /* 2. Static IP configuration copied from Dynamic IP settings of the */ /* DHCP Client */ /* 3. OAM VLAN */ /* 4. OAM Bridge Domain */ /* 5. Core facing interfaces (NNI) */ /* 6. Generates a unique host name of the node */ /* 7. Deletes DHCP client configuration */ /* 8. Enables Phase 2 of the ZTP process */ /* -------------------------------------------------------------------*/ /* Version 1.0 User1 user1@example.com */ /* ------------------------------------------------------------------ */ /* XML namespaces*/ /* Juniper */ 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"; ns exsl extension = "http://exslt.org/common"; /* EXSLT */ ns str extension = "http://exslt.org/strings"; /* private namespace for this script */ ns ztp_script = "http://xml.juniper.com/ztp_script/1.0"; import '../import/junos.xsl'; version 1.1; /* ------------------------------------------------------------------ */ /* This program performs Zero touch provisioning for the ACX platform */ /* It will load global configuration template from a remote location */ /* specified in the original configuration file loaded as a result */ /* of the autoconfiguration process. */ /* */ /* Version 1.1 Vasily Mukhin */ /* Based on jctyztp script by Jeremy Schulman and Brian Sherwood */ /* */ /* ------------------------------------------------------------------ */ /* XML namespaces */ /* ------------------------------------------------------------------ */ /* Juniper */ 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"; ns exsl extension = "http://exslt.org/common"; /* EXSLT */ ns str extension = "http://exslt.org/strings"; /* private namespace for this script */ ns ztp_script = "http://xml.juniper.com/ztp_script/1.0"; import '../import/junos.xsl'; /* ------------------------------------------------------------------ */ /* Constants */ /* ------------------------------------------------------------------ */ var $APPNAME = 'ztp_script[' _ $junos-context/pid _ ']'; var $JNPR_ZTP_SCRIPT = "ZTP Phase 1 SCRIPT"; var $SYSLOG = 'user.info'; var $TMPDIR = '/var/tmp'; var $CODEDIR = '/var/tmp'; var $ZTP_GROUP_PLATFORM = "GR-ZTP-PLATFORM"; var $ZTP_GROUP_BOX = "GR-ZTP-BOX"; var $ZTP_CODE_MACRO_NAME = "CODE"; var $ZTP_CONFIG_MACRO_NAME = "CONFIG"; var $ZTP_MACRO_NAME_PREFIX = "ZTP-"; var $ZTP_GROUP_NNI_TAG = "GR-NNI-TAG"; var $ZTP_GROUP_AGG_NNI_TAG = "GR-AGG-INTF-TAG"; var $ZTP_GROUP_STAGE_1 = "GR-ZTP-STAGE-1"; var $ZTP_GROUP_STAGE_2 = "GR-ZTP-STAGE-2"; var $ZTP_HOSTNAME = "HOST_NAME"; var $ZTP_BD_OAM = "BD-ZTP-OAM"; var $ZTP_BD_BOOT = "BD-ZTP-BOOTP"; var $ZTP_OAM_VLAN = "OAM_VLAN"; var $ZTP_LOCKFILE = '/tmp/ztp_script.lock'; var $ZTP_IP_VLAN = "1"; /* ------------------------------------------------------------------ */ /* Global variables */ /* ------------------------------------------------------------------ */ var $jnx = jcs:open(); /* ------------------------------------------------------------------ */ /* MAIN */ /* ------------------------------------------------------------------ */ match / { if( not( $jnx )) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": ERROR: unable to connect to Junos API"); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to connect to Junos API"); expr jcs:output( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to connect to Junos API"); terminate; } var $running = ztp_script:only_once(); if( $running ) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": process already running, backing off" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": process already running, backing off" ); expr jcs:output( $JNPR_ZTP_SCRIPT _ ": process already running, backing off" ); terminate; } expr jcs:syslog( $SYSLOG, $APPNAME _ ": ZTP Phase 1 BEGIN" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTP Phase 1 BEGIN" ); /*--------------------------------------------------------------*/ /* DEACTIVATE PHASE-1 Configuration group */ /*--------------------------------------------------------------*/ expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Deactivating event-options for ZTP Phase 1 script..." ); var $options_0 := { <commit-options> { <log> "Deactivating configuration group for Phase 1"; } } var $change_0 = { <configuration> { <apply-groups delete="delete"> $ZTP_GROUP_STAGE_1; } } /* Load new configuration */ var $results_stage_0 := { call jcs:load-configuration( $action="merge", $commit-options=$options_0, $configuration=$change_0, $connection = $jnx ); } if ($results_stage_0//xnm:warning) { for-each ($results_stage_0//xnm:warning) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": commit warning: " _ message ); } } if ($results_stage_0//xnm:error) { for-each ($results_stage_0//xnm:error) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": commit error: " _ message ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Commit failed." ); var $die = ztp_script:terminate(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuration for event-options for ZTP Phase 1 was disabled" ); } mvar $nRollback = 1; /*---------------------------------------------------------------------------------------*/ /* Verify that configuration group and apply-macro with platform specific ZTP parameters */ /* exist in the global configuration template */ /*---------------------------------------------------------------------------------------*/ var $serial_no = ztp_script:get_serial_number(); var $platform = ztp_script:get_platform(); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Looking for " _ $platform _ " specific parameters." ); expr jcs:syslog( $SYSLOG, $APPNAME _ "Looking for " _ $platform _ " specific parameters." ); if ( not( ztp_script:ztp_grp_exists($ZTP_GROUP_PLATFORM, $ZTP_MACRO_NAME_PREFIX _ $platform) ) ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: Failed to find platform specific ZTP parameters in global template." ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Note: Make sure that apply-macro " _ $ZTP_MACRO_NAME_PREFIX _ $platform _ " exists under " _ $ZTP_GROUP_PLATFORM _ " group in global template." ); var $ztd_rollback = ztp_script:ztp_rollback_phase0(); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Script terminated." ); var $die = ztp_script:terminate(); } /* Creating static configuration and enabling management access to the node */ /* 0. Read parameters assigned dynamically via DHCP: - ip address and mask a.b.c.d/n - default route 1. Create host-name: csr<c.d>-<platform>) 2. Creates OAM VLAN on NNIs: - NNIs are listed under apply-macros (platform specific list) 3. Creates IRB interfaces - Copies address assigned by DHCP server to IRB 4. Deletes DHCP-client configuration 5. Creates OAM Bridge-domain and placess following interfaces into it - NNI IFLs - IRB 6. Enables VSTP and LLDP protocols on NNI interfaces */ var $results_step_1 = ztp_script:set_dhcp_to_static($platform); if ($results_step_1//xnm:warning) { for-each ($results_step_1//xnm:warning) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": set_dhcp_to_static() commit warning: " _ message ); } } if ($results_step_1//xnm:error) { for-each ($results_step_1//xnm:error) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": dhcp_to_static() commit error: " _ message ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ " ERROR: Commit failed." ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Note: Verify parametrs in global conviguration template." ); var $ztd_rollback = ztp_script:ztp_rollback_phase0(); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Script terminated." ); var $die = ztp_script:terminate(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Platform specific configuration committed successfully." ); set $nRollback = $nRollback + 1; } /*-----------------------------------------*/ /* Looking for box specific ZTP parameters */ /*-----------------------------------------*/ expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Looking for box (S/N: " _ $serial_no _ ") specific parameters." ); expr jcs:syslog( $SYSLOG, $APPNAME _ "Looking for box (S/N: " _ $serial_no _ ") specific parameters." ); if ( not( ztp_script:ztp_grp_exists($ZTP_GROUP_BOX, $serial_no) ) ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Box specific configuration for S/N: " _ $serial_no _ " was not found in global template. Skip this step." ); } else { /* Configuring box specific parameters (fxp0 and host name) */ var $results_step_2 = ztp_script:set_box_specific_config($platform, $serial_no); if ($results_step_2//xnm:warning) { for-each ($results//xnm:warning) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": set_box_specific_config() commit warning: " _ message ); } } if ($results_step_2//xnm:error) { for-each ($results_step_1//xnm:error) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": set_box_specific_config() commit error: " _ message ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: Failed to commit box specific parameters." ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Skip this step and continue ZTP process." ); var $ztd_rollback = ztp_script:rollback_cfg(0); /* var $die = ztp_script:terminate(); */ } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Box specific configuration committed successfully." ); set $nRollback = $nRollback + 1; } } /*--------------------------------------------------------------*/ /* DELETE Box specific configuration if exists */ /* ACTIVATE PHASE 2 Configuration group if exists */ /*--------------------------------------------------------------*/ var $options_1 := { <commit-options> { <log> "Enabling next ZTP Phase"; } } var $change_1 = { <configuration> { if ( ztp_script:ztp_grp_exists($ZTP_GROUP_BOX) ) { <groups delete="delete"> { <name> $ZTP_GROUP_BOX; expr jcs:syslog( $SYSLOG, $APPNAME _ ": Deleting configuration group " _ $ZTP_GROUP_BOX ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Deleting configuration group " _ $ZTP_GROUP_BOX ); } } if ( ztp_script:ztp_grp_exists($ZTP_GROUP_STAGE_2) ) { <apply-groups> $ZTP_GROUP_STAGE_2; } else { expr jcs:syslog( $SYSLOG, $APPNAME _ ": WARNING: No configuration group for Phase 2 found in global template. STOP at this point."); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": WARNING: No configuration group for Phase 2 found in global template. STOP at this point."); } } } /* Load new configuration */ var $results_stage_1 := { call jcs:load-configuration( $action="merge", $commit-options=$options_1, $configuration=$change_1, $connection = $jnx ); } if ($results_stage_1//xnm:warning) { for-each ($results_stage_1//xnm:warning) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": commit warning: " _ message ); } } if ($results_stage_1//xnm:error) { for-each ($results_stage_1//xnm:error) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": commit error: " _ message ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Commit failed. " ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Rollback to beginning of phase 1 and exiting ztp_script now." ); var $ztd_rollback = ztp_script:rollback_cfg($nRollback); var $die = ztp_script:terminate(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuration was committed" ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTP Phase 1 completed successfully" ); var $die = ztp_script:terminate(); } /* -------------------------------------------------------------------------------- */ /* FUNCTION ztp_grp_exists VERIFIES IF configuration group name and apply-macro */ /* name EXIST IN THE CONFIGURATION and RETURNES True or False */ /* -------------------------------------------------------------------------------- */ function ztp_script:ztp_grp_exists($group_name, $macro_name = "N/A") { var $get_grp = <get-configuration> { <configuration> { <groups> { <name>; } } } /* getting variables from apply-macro */ var $got_grp = jcs:execute( $jnx, $get_grp ); mvar $grp_flag = "skip"; for-each ($got_grp/groups/name) { set $grp_flag = { if ((../name!=$group_name) and ($grp_flag!="exists")) { expr "skip"; } else { expr "exists"; } /* End if */ } } /* Verification for the apply-macro */ if ($grp_flag != "exists") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Can't find a group " _ $group_name); result false(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found a group " _ $group_name); if ( $macro_name!="N/A") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Looking for apply-macro " _ $macro_name _ " in group " _ $group_name ); /* Look for apply-macro with specified name */ var $get_mcr = <get-configuration> { <configuration> { <groups> { <name> $group_name; } } } /* geting variables from apply-macro */ var $got_mcr = jcs:execute( $jnx, $get_mcr ); mvar $mcr_flag = "skip"; for-each ($got_mcr/groups[name=$group_name]/apply-macro/name) { set $mcr_flag = { if ((../name!=$macro_name) and ($mcr_flag!="exists")) { expr "skip"; } else { expr "exists"; } /* End if */ } } /* Verification for the group */ if ($mcr_flag != "exists") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Can't find apply-macro " _ $macro_name ); result false(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found apply-macro " _ $macro_name ); result true(); } } else { result true(); } } } /* ------------------------------------------------------------------ */ /* Function: remove_old_cfg - DELETES CONFIGURATION GROUPS */ /* ------------------------------------------------------------------ */ function ztp_script:remove_old_cfg($group_name) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Removing old configuration group: " _ $group_name ); expr jcs:syslog( $SYSLOG, $APPNAME _ "Removing old configuration group: " _ $group_name ); var $get = <get-configuration> { <configuration> { <groups> { <name>; } } } /* looking for the given group-name */ var $got = jcs:execute( $jnx, $get ); mvar $delete_flag = "skip"; for-each ($got/groups/name) { set $delete_flag = { if ((../name!=$group_name) and ($delete_flag!="delete")) { expr "skip"; } else { expr "delete"; } /* End if */ } } var $options := { <commit-options> { <log> "deleting configuration group " _ $group_name;; } } var $change = { <configuration> { <groups delete="delete"> { <name> $group_name; } } } /* Deleting config for the group */ if ($delete_flag == "delete") { var $results := { call jcs:load-configuration($action="merge", $commit-options=$options, $configuration=$change, $connection = $jnx ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": group " _ $group_name _ " was deleted" ); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Group: " _ $group_name _ " was not found. Nothing to delete "); } } /* ------------------------------------------------------------------ */ /* Function: set_dhcp_to_static - GENERATES NEW STATIC CONFIGURATION */ /* ------------------------------------------------------------------ */ function ztp_script:set_dhcp_to_static($platform) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Retrieve DHCP client bindings" ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Retrieve DHCP client bindings" ); /* GET ZTP VLAN-ID */ var $get = <get-configuration> { <configuration> { <groups> { <name> $ZTP_GROUP_PLATFORM; <apply-macro> { <name> $ZTP_MACRO_NAME_PREFIX _ $platform; } } } } /* getting variables from apply-macro */ var $got = jcs:execute( $jnx, $get ); mvar $ztp_oam_vlan = "2"; mvar $ztp_host_prefix = "csr"; for-each ($got/groups[name=$ZTP_GROUP_PLATFORM]/apply-macro[name=$ZTP_MACRO_NAME_PREFIX _ $platform]/data/name) { if (../name == $ZTP_OAM_VLAN ) { set $ztp_oam_vlan = ../value; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found vlan-id for OAM plane: " _ ../value ); } if (../name == $ZTP_HOSTNAME ) { set $ztp_host_prefix = ../value; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found host name prefix: " _ ../value ); } } /* GET VALUES OF THE DHCP OPTIONS */ var $get_dhcp_detail = <get-dhcp-client-binding-information> { <detail>; } var $dhcp_bind := jcs:execute( $jnx, $get_dhcp_detail ); /* - GET ZTP INTERFACE - */ var $ztp_interface = $dhcp_bind/dhcp-binding/interface-name; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": DHCP client runs on ZTP interface: " _ $ztp_interface ); /* - GET ROUTER IP ADDRESS - */ var $ztp_router = $dhcp_bind/dhcp-binding/dhcp-option-table/dhcp-option[dhcp-option-name="router"]/dhcp-option-value; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found DHCP Option for router: " _ $ztp_router ); var $post_str = { if ( contains($ztp_router, '[ ')) { expr substring-after($ztp_router, '[ '); } else { expr $ztp_router; } } /* - GET NEXT-HOP FOR DEFAULT ROUTE - */ var $ztp_next_hop = { if ( contains($post_str, ' ')) { expr substring-before($post_str, ' '); } else { expr $post_str; } } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Derived next-hop: " _ $ztp_next_hop ); /* Looling for real ip-address assigned to dhcp interface */ var $get_interface_terse = <get-interface-information> { <terse>; <interface-name> $ztp_interface; } var $interface_info := jcs:execute( $jnx, $get_interface_terse ); /* - GET DHCP IP ADDRESS - */ var $irb_ip_address = $interface_info/logical-interface/address-family[address-family-name="inet"]/interface-address/ifa-local; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": DHCP ip address found: " _ $irb_ip_address); /* Create configuration with static IP */ var $options := { <commit-options> { <log> "setting irb interface"; } } /* - CREATE CONFIGURATION - */ /* - Deletes DHCP-client configuration - Creates OAM Bridge-domain - Configures OAM vlan-bridge unit on ZTP interface - Moves OAM unit into bridge domain - Creates irb - Copies DHCP-client IP-address to static irb interface */ var $ztp_device = substring-before($ztp_interface, '.'); var $ztp_device_unit = substring-after($ztp_interface,'.'); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Parsing ZTP Interface: ifd=" _ $ztp_device _ " unit=" _ $ztp_device_unit ); var $irb_unit_num = $ztp_oam_vlan; var $ip_3_4 = substring-after(substring-after(substring-before($irb_ip_address,'/'),'.'),'.'); var $change = { <configuration> { <interfaces> { <interface> { call emit-deactivate-dhcp-client($platform, $ztp_device, $ztp_device_unit); } <interface> { <name> $ztp_device; <flexible-vlan-tagging>; <encapsulation> "flexible-ethernet-services"; <unit> { <name> $ztp_oam_vlan; <encapsulation> "vlan-bridge"; <vlan-id> $ztp_oam_vlan; } } <interface> { <name> "irb"; <unit> { <name> $irb_unit_num; <family> { <inet> { <address> $irb_ip_address; } } } } call create-nni-interfaces($platform, $ztp_oam_vlan, $got); } call emit-bridge-domain($platform, $irb_unit_num, $ztp_device, $ztp_oam_vlan, $got); <routing-options> { <static> { <route> { <name> "0.0.0.0/0"; <next-hop> $ztp_next_hop; } } } <protocols> { <vstp> { for-each ($got/groups[name=$ZTP_GROUP_PLATFORM]/apply-macro[name=$ZTP_MACRO_NAME_PREFIX _ $platform]/data/name) { if (contains(../name,"NNI" )) { <interface> { <name> ../value; } <vlan> { <name> $ztp_oam_vlan; } } } } <lldp> { for-each ($got/groups[name=$ZTP_GROUP_PLATFORM]/apply-macro[name=$ZTP_MACRO_NAME_PREFIX _ $platform]/data/name) { if (contains(../name,"NNI" )) { <interface> { <name> ../value; } } } } } call create-re0-group($platform, $ip_3_4, $ztp_host_prefix); } } /* Load configuration for group re0 */ var $results := { call jcs:load-configuration( $action="merge", $commit-options=$options, $configuration=$change, $connection = $jnx ); } result $results; } /*--------------------------------------------------------------------*/ /* Template: create-re0-group - CREATES re0 group and a host-name */ /*--------------------------------------------------------------------*/ template create-re0-group($platform, $ip_3_4, $ztp_host_prefix) { if (($platform=="acx5096") or ($platform=="acx5048")) { <groups> { <name> "member0"; <system> { <host-name> $ztp_host_prefix _ $ip_3_4 _ "-" _ $platform; } } <apply-groups> "member0"; } else { <groups> { <name> "re0"; <system> { <host-name> $ztp_host_prefix _ $ip_3_4 _ "-" _ $platform; } } <apply-groups> "re0"; } } /* -------------------------------------------------------------------- */ /* Template: create-nni-interfaces - CONFIGURES CORE-FACING INTERFACES */ /* -------------------------------------------------------------------- */ template create-nni-interfaces($platform, $ztp_oam_vlan, $got) { for-each ($got/groups[name=$ZTP_GROUP_PLATFORM]/apply-macro[name=$ZTP_MACRO_NAME_PREFIX _ $platform]/data/name) { if ( contains(../name,"NNI" )){ expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuring NNI interface: " _ ../value); <interface> { <name> ../value; <flexible-vlan-tagging>; <encapsulation> "flexible-ethernet-services"; <apply-groups> $ZTP_GROUP_NNI_TAG; <native-vlan-id> $ztp_oam_vlan; <unit> { <name> $ztp_oam_vlan; <description> "OAM VLAN ENABLES ZTP AND NMS ACCESS"; <encapsulation> "vlan-bridge"; <vlan-id> $ztp_oam_vlan; } } } } } /*---------------------------------------------------------------------- */ /* Template: emit-nni-interfaces - ADDS INTERFACES TO OSPF CONFIGURATION */ /*---------------------------------------------------------------------- */ template emit-nni-interfaces($platform, $got) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuring OSPF Interfaces "); for-each ($got/groups[name=$ZTP_GROUP_PLATFORM]/apply-macro[name=$ZTP_MACRO_NAME_PREFIX _ $platform]/data/name) { if (contains(../name,"NNI" )) { <interface> { <name> ../value _ ".0"; } } } } /*----------------------------------------------------------------- */ /* Template: emit-deactivate-dhcp-client DEACTIVATE DHCP CLIENT */ /*----------------------------------------------------------------- */ template emit-deactivate-dhcp-client($platform, $ztp_device, $ztp_device_unit) { if (($platform=="acx5096") or ($platform=="acx5048")) { <name> $ztp_device; <flexible-vlan-tagging>; <encapsulation> "flexible-ethernet-services"; <unit> { <name> $ztp_device_unit; <vlan-id> $ZTP_IP_VLAN; <family> { <inet> { <dhcp inactive="inactive">; } } } } else { <name> $ztp_device; <flexible-vlan-tagging>; <encapsulation> "flexible-ethernet-services"; <unit> { <name> $ztp_device_unit; <vlan-id> $ZTP_IP_VLAN; <family> { <inet> { <dhcp-client inactive="inactive">; } } } } } /*--------------------------------------------------------------------*/ /* Template: emit-bridge-domain - CONFIGURES BRIDGE DOMAIN WITH IRB */ /*--------------------------------------------------------------------*/ template emit-bridge-domain($platform, $irb_unit_num, $ztp_device, $ztp_oam_vlan, $got) { if (($platform=="acx5096") or ($platform=="acx5048")) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuring bridge-domain (vlans): " _ $ZTP_BD_OAM); <vlans> { <vlan> { <name> $ZTP_BD_OAM; <vlan-id> $ztp_oam_vlan; <l3-interface> "irb." _ $irb_unit_num; <interface> $ztp_device _ "." _ $ztp_oam_vlan; for-each ($got/groups[name=$ZTP_GROUP_PLATFORM]/apply-macro[name=$ZTP_MACRO_NAME_PREFIX _ $platform]/data/name) { if (contains(../name,"NNI" )) { <interface> ../value _ "." _ $ztp_oam_vlan; } } } } } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuring bridge-domain: " _ $ZTP_BD_OAM); <bridge-domains> { <domain> { <name> $ZTP_BD_OAM; <vlan-id> $ztp_oam_vlan; <routing-interface> "irb." _ $irb_unit_num; <interface> $ztp_device _ "." _ $ztp_oam_vlan; for-each ($got/groups[name=$ZTP_GROUP_PLATFORM]/apply-macro[name=$ZTP_MACRO_NAME_PREFIX _ $platform]/data/name) { if (contains(../name,"NNI" )) { <interface> ../value _ "." _ $ztp_oam_vlan; } } } } } } /* ------------------------------------------------------------------ */ /* Function: get_platform - RETURNS PLATFORM TYPE */ /* ------------------------------------------------------------------ */ function ztp_script:get_platform() { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Retrieve type of platform" ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Retrieve Platform Type" ); /* get platform */ var $chassis_software := jcs:execute( $jnx, 'get-software-information' ); var $ztp_platform = { if ( $chassis_software//product-model) { expr $chassis_software//product-model; } else { expr $chassis_software/software-information/product-model; } } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": platform = " _ $ztp_platform ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": platform = " _ $ztp_platform ); result $ztp_platform; } /* -------------------------------------------------------------------- */ /* Function: get_serial_number - RETURNES SERIAL NUMBER OF THE NODE */ /* -------------------------------------------------------------------- */ function ztp_script:get_serial_number() { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Getting box Serial Number" ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Getting box Serial Number" ); /* get our serial number */ var $chassis_hardware := jcs:execute( $jnx, 'get-chassis-inventory' ); var $serial_no = $chassis_hardware/chassis/serial-number; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": serial no = " _ $serial_no ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": serial no = " _ $serial_no ); result $serial_no; } /* --------------------------------------------------------------------- */ /* Function: set_box_specific_config - CONFIGURES fxp0/em0 and host-name */ /* --------------------------------------------------------------------- */ function ztp_script:set_box_specific_config($platform, $serial_no) { /* get the apply-macro */ expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Setting fxp0 and host-name for lab boxes" ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Setting fxp0 and host-name for lab boxes" ); var $mng_if_name = { if (($platform=="acx5096") or ($platform=="acx5048")) { expr "em0"; } else { expr "fxp0"; } /* End If */ } var $re_group_name = { if (($platform=="acx5096") or ($platform=="acx5048")) { expr "member0"; } else { expr "re0"; } /* End If */ } var $get = <get-configuration> { <configuration> { <groups> { <name> $ZTP_GROUP_BOX; <apply-macro> { <name> $serial_no; } } } } /* getting variables from apply-macro */ var $got = jcs:execute( $jnx, $get ); var $fxp_address = $got/groups[name=$ZTP_GROUP_BOX]/apply-macro[name=$serial_no]/data[name='address']/value; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Current Platform = " _ $platform ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": MNG interface name = " _ $mng_if_name ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": " _ $mng_if_name _ " ip address = " _ $fxp_address ); if ($got/groups[name=$ZTP_GROUP_BOX]/apply-macro[name=$serial_no]/data[name='host-name']/value) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": New host-name = " _ $got/groups[name=$ZTP_GROUP_BOX]/apply-macro[name=$serial_no]/data[name='host-name']/value); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": RE0 Group name = " _ $re_group_name ); /* Create configuration for group re0 */ var $options := { <commit-options> { <log> "setting fxp0 and host-name. For lab only"; } } var $unit_num = "0"; var $change = { <configuration> { <groups> { <name> $re_group_name; <interfaces> { <interface> { <name> $mng_if_name; <unit> { <name> $unit_num; <family> { <inet> { <address> $fxp_address; } } } } } if ($got/groups[name=$ZTP_GROUP_BOX]/apply-macro[name=$serial_no]/data[name='host-name']/value){ <system> { <host-name> $got/groups[name=$ZTP_GROUP_BOX]/apply-macro[name=$serial_no]/data[name='host-name']/value; } } } <apply-groups> $re_group_name; } } /* Load configuration for group re0 */ var $results := { call jcs:load-configuration( $action="merge", $commit-options=$options, $configuration=$change, $connection = $jnx ); } result $results; } /* End of the set_box_specific_config function */ /* ------------------------------------------------------------------ */ /* Function rolback_cfg($nRollback) rollback configuration to */ /* nRollback version */ /* ------------------------------------------------------------------ */ function ztp_script:rollback_cfg( $cfg_version=0, $rollback_log="Rollback configuration" ) { var $rollback_options := { <commit-options> { <full>; <log> $rollback_log; } } var $rollback_configuration := { call jcs:load-configuration( $commit-options = $rollback_options, $rollback = $cfg_version, $connection = $jnx ); } } /* ------------------------------------------------------------------ */ /* Function: ztp_rollback_phase0 - Rollbacks configuration to basic */ /* configuration template of Phase 0 */ /* ------------------------------------------------------------------ */ function ztp_script:ztp_rollback_phase0() { var $lRollback = "ZTD Phase 0"; mvar $nRollback = 0; mvar $bRollback = false(); var $got_rollback := jcs:execute( $jnx, 'get-commit-information' ); for-each ($got_rollback/commit-history/sequence-number) { if (((../client == "autoinstall") || (../log == $lRollback)) && ( not ($bRollback))) { set $bRollback = true(); set $nRollback = ../sequence-number; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Starting rollback " _ $nRollback _ " to ZTD phase 0" ); } } var $rollback = ztp_script:rollback_cfg( $nRollback, $lRollback ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": rollback " _ $nRollback _ " completed successfully" ); result $nRollback; } /* ------------------------------------------------------------------ */ /* Helper routines /* ------------------------------------------------------------------ */ function ztp_script:file-exists( $filename ) { var $ls_file = <file-list> { <path> $filename; } var $ls_got = jcs:execute( $jnx, $ls_file ); var $retval = boolean( $ls_got//file-information ); result $retval; } function ztp_script:file-delete( $filename ) { var $do_rm = <file-delete> { <path> $filename; } var $did_rm = jcs:execute( $jnx, $do_rm ); /* @@@ trap error */ result true(); } function ztp_script:only_once() { if( ztp_script:file-exists( $ZTP_LOCKFILE )) { result true(); } else { var $do_lock = <file-put> { <filename> $ZTP_LOCKFILE; <encoding> 'ascii'; <file-contents> 'locked'; } var $did_lock = jcs:execute( $jnx, $do_lock ); result false(); } } function ztp_script:terminate() { expr jcs:syslog( $SYSLOG, $APPNAME _ ": SCRIPT-TERMINATE" ); var $rm_lock = ztp_script:file-delete( $ZTP_LOCKFILE ); terminate; }
Phase 2 Script
version 1.1; /* ------------------------------------------------------------------ */ /* This program performs Zero touch provisioning for the ACX platform */ /* Script enables workflow for pull or push ZTD model depending on */ /* the parameter configured in global configuration template under */ /* configuration group GR-ZTP-SCENARIOS: */ /* Pull Model: */ /* - checks current sw image and initiate upgrade procedure */ /* - fetches for <S/N>.conf configuration file on FTP server and */ /* applies to the access node */ /* Push Model: */ /* - fetches for Space configlet file on FTP server and applies it */ /* to the access nodes */ /* - Calls home to Space network management platform */ /*--------------------------------------------------------------------*/ /* Version 1.0 User1 user1@example.com */ /* ------------------------------------------------------------------ */ /* XML namespaces */ /* ------------------------------------------------------------------ */ /* Juniper */ 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"; ns exsl extension = "http://exslt.org/common"; /* EXSLT */ ns str extension = "http://exslt.org/strings"; /* private namespace for this script */ ns ztp_script = "http://xml.juniper.com/ztp_script/1.0"; import '../import/junos.xsl'; /* ------------------------------------------------------------------ */ /* Constants */ /* ------------------------------------------------------------------ */ var $APPNAME = 'ztp_script[' _ $junos-context/pid _ ']'; var $SYSLOG = 'user.info'; var $TMPDIR = '/var/tmp'; var $CODEDIR = '/var/tmp'; var $JNPR_ZTP_SCRIPT = "ZTP Phase 2 SCRIPT"; var $ZTP_GROUP_SCENARIOS = "GR-ZTP-SCENARIOS"; var $ZTP_SCENARIO = "SCENARIO-1"; var $ZTP_METHOD = "METHOD"; var $ZTP_GROUP_NAME = "GR-ZTP"; var $ZTP_CODE_MACRO_NAME = "CODE"; var $ZTP_GROUP_PLATFORM = "GR-ZTP-PLATFORM"; var $ZTP_GROUP_BOX = "GR-ZTP-BOX"; var $ZTP_GROUP_CALLHOME = "GR-ZTP-CALLHOME"; var $ZTP_CONFIG_MACRO_NAME = "CONFIG"; var $ZTP_CALLHOME_MACRO_NAME = "CALLHOME"; var $ZTP_MACRO_NAME_PREFIX = "ZTP-"; var $ZTP_BD_OAM = "BD-ZTP-OAM"; var $ZTP_OAM_VLAN = "OAM_VLAN"; var $ZTP_LOOPBACK = "Lo0"; var $ZTP_CONFIG = "CONFIG"; var $ZTP_SPACE_CONFIGLET = "SPACE-CONFIGLET"; var $ZTP_VERSION = "VERSION"; var $ZTP_IMAGE = "IMAGE"; var $ZTP_INACTIVE_FLAG = "INACTIVE"; var $ZTP_GROUP_STAGE_1 = "GR-ZTP-STAGE-1"; var $ZTP_GROUP_STAGE_2 = "GR-ZTP-STAGE-2"; var $ZTP_GROUP_STAGE_3 = "GR-ZTP-STAGE-3"; var $ZTP_GROUP_SPACE = "GR-ZTP-SPACE"; var $ZTP_LOCKFILE = '/tmp/ztp_script.lock'; var $PATTERN = "system"; var $ZTP_GROUP_NNI_TAG = "GR-NNI-TAG"; /* Global variables */ var $jnx = jcs:open(); /* MAIN */ match / { if( not( $jnx )) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": ERROR: unable to connect to Junos API"); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to connect to Junos API"); expr jcs:output( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to connect to Junos API"); terminate; } var $running = ztp_script:only_once(); if( $running ) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": process already running, backing off" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": process already running, backing off" ); expr jcs:output( $JNPR_ZTP_SCRIPT _ ": process already running, backing off" ); terminate; } expr jcs:syslog( $SYSLOG, $APPNAME _ ": ZTP Phase 2 BEGIN" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTP Phase 2 BEGIN" ); /*-----------------------------------------------------------------*/ /* VERIFY WHAT MODEL IS USED - PULL or PUSH */ /*-----------------------------------------------------------------*/ var $ztp_method = ztp_script:ztp_get_method($ZTP_GROUP_SCENARIOS, $ZTP_SCENARIO); if ( $ztp_method == "push" ) { /* Proceed with PUSH model work flow */ expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTD Push model is in use." ); /* Check if configuration for the next ZTP STAGE exists */ if ( not( ztp_script:ztp_grp_exists($ZTP_GROUP_CALLHOME, $ZTP_CALLHOME_MACRO_NAME) ) ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": No configuration for the next ZTP phase exists. Stop at this point" ); var $die = ztp_script:terminate(); } var $get = <get-configuration> { <configuration> { <groups> { <name> $ZTP_GROUP_CALLHOME; } } } var $got = jcs:execute( $jnx, $get ); /*-----------------------------------------------------------------*/ /* Deactivate PHASE-2 Configuration group */ /* Note: Next PHASE of ZTP process will be enabled after */ /* Space NMS completes S/W upgrade and populates node */ /* into NMS in its database */ /*-----------------------------------------------------------------*/ var $options_s2 := { <commit-options> { <log> "Disables ZTP Phase 2 on completion"; } } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Next ZTP phase will be enabled by Space after completion of the call home phase" ); var $change_s2 = { <configuration> { <apply-groups delete = "delete"> $ZTP_GROUP_STAGE_2; } } /* Loading configuration */ var $results_step_3 := { call jcs:load-configuration( $action="merge", $commit-options=$options_s2, $configuration=$change_s2, $connection = $jnx ); } if ($results_step_3//xnm:warning) { for-each ($results_step_3//xnm:warning) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": apply-group commit warning: " _ message ); } } if ($results_step_3//xnm:error) { for-each ($results_step_3//xnm:error) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: apply-group commit error: " _ message ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: Script failed." ); var $die = ztp_script:terminate(); } /* get location of the configlet file */ mvar $ztp_config_src = " "; mvar $ztp_configlet = "space_configlet.conf"; for-each ($got/groups[name=$ZTP_GROUP_CALLHOME]/apply-macro[name=$ZTP_CALLHOME_MACRO_NAME]/data/name) { if (../name == $ZTP_CONFIG ) { set $ztp_config_src = ../value; } if (../name == $ZTP_SPACE_CONFIGLET ) { if (( string-length(../value) > 2 ) && (not ( contains(../value, ' ')))) { set $ztp_configlet = ../value; } } } /* Download configlet file */ var $ztp_callhome_config = $ztp_config_src _ "/" _ $ztp_configlet; /*-----------------------------------------------------------------*/ /* LOAD CONFIGURATION FROM CONFIGLET */ /*-----------------------------------------------------------------*/ if (not (ztp_script:load_config($ztp_callhome_config))) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Failed to load Space configlet."); var $nRollback = 1; var $ztp_rollback = ztp_script:rollback_cfg( $nRollback, "Rollback configuration to beginning of phase 2" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Script rollbacks to beginning of phase 2 and terminates."); var $die = ztp_script:terminate(); } expr jcs:syslog( $SYSLOG, $APPNAME _ ": Phase 2 completed successfully" ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Now calling home to continue ZTP process" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Phase 2 completed successfully" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Now calling home to continue ZTP process." ); } else { /* Proceed with ZTD PULL mode work flow */ expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTD Pull model is in use." ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Going to proceed with Junos S/W upgrade" ); /*----------------------------------------------------------------*/ /* CHECK/UPGRADE VERSION OF THE JUNOS IMAGE */ /*----------------------------------------------------------------*/ if ( not( ztp_script:ztp_grp_exists($ZTP_GROUP_NAME, $ZTP_CODE_MACRO_NAME) ) ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": No information for recommended Junos version found. Continue deployment with current version" ); } else { var $code_upgrade = ztp_script:upgrade_code(); } /*-----------------------------------------------------------------*/ /* DEACTIVATE PHASE-2 Configuration group */ /*-----------------------------------------------------------------*/ var $options_s2 := { <commit-options> { <log> "Disables configuration group for phase 2 on completion"; } } var $change_s2 = { <configuration> { <apply-groups delete = "delete"> $ZTP_GROUP_STAGE_2; } } /* Loading configuration */ var $results_step_3 := { call jcs:load-configuration( $action="merge", $commit-options=$options_s2, $configuration=$change_s2, $connection = $jnx ); } if ($results_step_3//xnm:warning) { for-each ($results_step_3//xnm:warning) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": apply-group commit warning: " _ message ); } } if ($results_step_3//xnm:error) { for-each ($results_step_3//xnm:error) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": apply-group commit error: " _ message ); } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: Script failed." ); var $die = ztp_script:terminate(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTP PHASE 2 Configuration group was deactivated" ); } /*----------------------------------------------------------------*/ /* GET LOCATION OF THE BOX SPECIFIC CONFIGURATION FILE */ /*----------------------------------------------------------------*/ if ( not( ztp_script:ztp_grp_exists($ZTP_GROUP_CALLHOME, $ZTP_CALLHOME_MACRO_NAME) ) ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": The information about site specific configuration was not found in global template." ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Stop script at this point" ); var $die = ztp_script:terminate(); } var $get = <get-configuration> { <configuration> { <groups> { <name> $ZTP_GROUP_CALLHOME; } } } var $got = jcs:execute( $jnx, $get ); /* get full url of the configuration file */ var $ztp_config_src = $got/groups[name=$ZTP_GROUP_CALLHOME]/apply-macro[name=$ZTP_CALLHOME_MACRO_NAME]/data[name=$ZTP_CONFIG]/value; var $serial_no = ztp_script:get_serial_number(); var $ztp_callhome_config = $ztp_config_src _ "/" _ $serial_no _ ".conf"; /* Load configuration file and merge to existed configuration */ if (not (ztp_script:load_config($ztp_callhome_config))) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: failed to load box specific configuration. File was not found or bad configuration."); var $nRollback = 1; var $ztp_rollback = ztp_script:rollback_cfg( $nRollback, "Rollback configuration to beginning of phase 2" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Script rollbacks to beginning of phase 2 and terminates."); var $die = ztp_script:terminate(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Box specific configuration was loaded" ); } expr jcs:syslog( $SYSLOG, $APPNAME _ ": ZTD Phase 2 completed successfully" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTD Phase 2 completed successfully" ); } /* var $delete_file = ztp_script:file-delete($filename); */ var $die = ztp_script:terminate(); } /* ------------------------------------------------------------------ */ /* LOAD CONFIGURATION FROM FILE */ /* ------------------------------------------------------------------ */ function ztp_script:load_config($config_url, $action = "merge") { mvar $load_config = true(); var $phrase = { if ($action == "merge") { expr "merged to existed configuration"; } else { if ($action == "replace") { expr " and replace existed statements"; } else { expr " be merged (default action) to existed configuration"; } } } var $new_action = { if (($action == "merge") or ($action == "replace")) { expr $action; } else { expr "merge"; } } expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Config file: " _ $config_url _ " will be loaded and " _ $phrase ); /* lock the config */ var $lock = <lock-configuration>; var $did_lock = jcs:execute( $jnx, $lock ); if ( $did_lock//self::xnm:error ) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": ERROR: unable to lock configuration" ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to lock configuration" ); set $load_config = false(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuration was locked" ); } if ($load_config) { set $load_config = false(); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Processing config url " _ $config_url ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Processing config url " _ $config_url ); /* load in new config */ var $do_load = <load-configuration action="merge" url=$config_url format="text">; var $did_load = jcs:execute( $jnx, $do_load ); if( not( $did_load/load-success )) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": ERROR: unable to load config " _ $config_url ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ERROR: unable to load config " _ $config_url ); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuration was loaded" ); var $commit = <commit-configuration> { <full>; <synchronize>; <force-synchronize>; <log> "Initial config load"; } var $did_commit = jcs:execute( $jnx, $commit ); if ( $did_commit//self::xnm:error ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Commit Failed" ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Commit Failed" ); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Configuration was committed" ); var $unlock = <unlock-configuration>; var $did_unlock = jcs:execute( $jnx, $unlock ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": release config lock" ); set $load_config = true(); /*var $die = ztp_script:terminate();*/ } } } /* end of foreach config_url */ if (not($load_config)) { /* if we make it here, we failed to load the config */ var $unlock = <unlock-configuration>; var $did_unlock = jcs:execute( $jnx, $unlock ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": release config lock" ); } result $load_config; } /* ------------------------------------------------------------------ */ /* Function ztp_grp_exists verifies if configuration group and */ /* apply-macro (optional) name exist. */ /* ------------------------------------------------------------------ */ function ztp_script:ztp_grp_exists($group_name, $macro_name = "N/A") { var $get_grp = <get-configuration> { <configuration> { <groups> { <name>; } } } /* geting variables from apply-macro */ var $got_grp = jcs:execute( $jnx, $get_grp ); mvar $grp_flag = "skip"; for-each ($got_grp/groups/name) { set $grp_flag = { if ((../name!=$group_name) and ($grp_flag!="exists")) { expr "skip"; } else { expr "exists"; } /* End if */ } } /* Verification for the apply-macro */ if ($grp_flag != "exists") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Can't find a group " _ $group_name); result false(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found a group " _ $group_name); if ( $macro_name!="N/A") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Looking for apply-macro " _ $macro_name _ " in group " _ $group_name ); /* Look for apply-macro with specified name */ var $get_mcr = <get-configuration> { <configuration> { <groups> { <name> $group_name; } } } /* geting variables from apply-macro */ var $got_mcr = jcs:execute( $jnx, $get_mcr ); mvar $mcr_flag = "skip"; for-each ($got_mcr/groups[name=$group_name]/apply-macro/name) { set $mcr_flag = { if ((../name!=$macro_name) and ($mcr_flag!="exists")) { expr "skip"; } else { expr "exists"; } /* End if */ } } /* Verification for the group */ if ($mcr_flag != "exists") { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Can't find apply-macro " _ $macro_name ); result false(); } else { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Found apply-macro " _ $macro_name ); result true(); } } else { result true(); } } } /* ------------------------------------------------------------------ */ /* Function ztp_get_method returns ZTP METHOD: "pull" or "push" */ /* ------------------------------------------------------------------ */ function ztp_script:ztp_get_method($group_name, $macro_name) { mvar $ztd_method = "pull"; if ( not( ztp_script:ztp_grp_exists($group_name, $macro_name) ) ) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": ZTD model not specified in global template. Use pull method by default" ); } else { var $get_grp = <get-configuration> { <configuration> { <groups> { <name> $group_name; } } } /* getting variables from apply-macro */ var $got_grp = jcs:execute( $jnx, $get_grp ); for-each ($got_grp/groups[name=$group_name]/apply-macro[name=$macro_name]/data/name) { if (../name == $ZTP_METHOD ) { set $ztd_method = ../value; } } } result $ztd_method; } /* ------------------------------------------------------------------ */ /* Function upgrade_code() checks the currently running Junos version */ /* and upgrades the code */ /* ------------------------------------------------------------------ */ function ztp_script:upgrade_code() { /* get the apply-macro */ var $get = <get-configuration> { <configuration> { <version>; <groups> { <name> $ZTP_GROUP_NAME; <apply-macro> { <name> $ZTP_CODE_MACRO_NAME; } } } } var $got = jcs:execute( $jnx, $get ); var $running_version = $got/version; var $production_version = $got/groups[name=$ZTP_GROUP_NAME]/apply-macro[name=$ZTP_CODE_MACRO_NAME]/data[name=$ZTP_VERSION]/value; expr jcs:syslog( $SYSLOG, $APPNAME _ ": running_version = " _ $running_version); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": running_version = " _ $running_version); expr jcs:syslog( $SYSLOG, $APPNAME _ ": production_version = " _ $production_version); expr jcs:progress($JNPR_ZTP_SCRIPT _ ": production_version = " _ $production_version); if ($running_version == $production_version) { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Code is up to date, no upgrade required"); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Code is up to date, no upgrade required"); result false(); } else { expr jcs:progress($JNPR_ZTP_SCRIPT _ ": upgrade required"); var $image_file = $got/groups[name=$ZTP_GROUP_NAME]/apply-macro[name=$ZTP_CODE_MACRO_NAME]/data[name=$ZTP_IMAGE]/value; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Processing " _ $image_file ); /* Check s/w upgrade flag in basic template. If flag set to inactive skip upgrade procedure */ mvar $ztd_inactive = "active"; for-each ($got/groups[name=$ZTP_GROUP_NAME]/apply-macro[name=$ZTP_CODE_MACRO_NAME]/data/name) { if (../name == $ZTP_INACTIVE_FLAG ) { set $ztd_inactive = ../value; } } if ( $ztd_inactive == "inactive" ) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": Skip software upgrade due to Upgrade flag in basic template set to inactive" ); expr jcs:progress($JNPR_ZTP_SCRIPT _ ": Skip software upgrade due to Upgrade flag in basic template set to inactive" ); } else { /* request system software add ... */ expr jcs:syslog( $SYSLOG, $APPNAME _ ": installing image" ); var $do_install := <request-package-add> { <no-validate>; <force>; <reboot>; <package-name> $image_file ; } var $install_results = jcs:execute( $jnx, $do_install ); for-each( $install_results/../output ) { expr jcs:syslog( $SYSLOG, $APPNAME _ ": Install Error: ", output ); expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Install error: " _ output ); } if ($install_results/../package-result == 0) { /* successfully installed package -- terminate script and wait for reboot */ expr jcs:syslog( $SYSLOG, $APPNAME _ ": software installed" ); expr jcs:progress($JNPR_ZTP_SCRIPT _ ": software installed" ); var $die = ztp_script:terminate(); } } } /* else */ } /* end function */ /* ------------------------------------------------------------------ */ /* Function rolback_cfg($nRollback) rollback configuration to */ /* nRollback version */ /* ------------------------------------------------------------------ */ function ztp_script:rollback_cfg( $cfg_version=0, $rollback_log="Rollback configuration" ) { var $rollback_options := { <commit-options> { <full>; <log> $rollback_log; } } var $rollback_configuration := { call jcs:load-configuration( $commit-options = $rollback_options, $rollback = $cfg_version, $connection = $jnx ); } } /* ------------------------------------------------------------------ */ /* Helper routines /* ------------------------------------------------------------------ */ function ztp_script:file-copy( $source, $filename, $destination ) { var $copy_get = <file-copy> { <source> $source _ "/" _ $filename; <destination> $destination _ "/" _ $filename; <staging-directory> $TMPDIR; } var $copy_got = jcs:execute( $jnx, $copy_get ); if ( contains($copy_got,"failed")) { result false(); } else { result true(); } } function ztp_script:file-exists( $filename ) { var $ls_file = <file-list> { <path> $filename; } var $ls_got = jcs:execute( $jnx, $ls_file ); var $retval = boolean( $ls_got//file-information ); result $retval; } function ztp_script:file-delete( $filename ) { var $do_rm = <file-delete> { <path> $filename; } var $did_rm = jcs:execute( $jnx, $do_rm ); /* @@@ trap error */ result true(); } function ztp_script:only_once() { if( ztp_script:file-exists( $ZTP_LOCKFILE )) { result true(); } else { var $do_lock = <file-put> { <filename> $ZTP_LOCKFILE; <encoding> 'ascii'; <file-contents> 'locked'; } var $did_lock = jcs:execute( $jnx, $do_lock ); result false(); } } function ztp_script:terminate() { expr jcs:syslog( $SYSLOG, $APPNAME _ ": SCRIPT-TERMINATE" ); var $rm_lock = ztp_script:file-delete( $ZTP_LOCKFILE ); terminate; } /* ------------------------------------------------------------------ */ /* GET SERIAL NUMBER */ /* ------------------------------------------------------------------ */ function ztp_script:get_serial_number() { expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": Getting box Serial Number" ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": Getting box Serial Number" ); /* get our serial number */ var $chassis_hardware := jcs:execute( $jnx, 'get-chassis-inventory' ); var $serial_no = $chassis_hardware/chassis/serial-number; expr jcs:progress( $JNPR_ZTP_SCRIPT _ ": serial no = " _ $serial_no ); expr jcs:syslog( $SYSLOG, $APPNAME _ ": serial no = " _ $serial_no ); result $serial_no; }