cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
13143
Views
30
Helpful
18
Replies

TCL Script to replace text in a file stored in flash

smolz
Level 4
Level 4

here is what i am trying to do.  I have a 2900 router with the ucs-e blade in it.  I am trying to automate the deployment of hundreds of routers with this setup.

 

So far I have gotten Cisco Prime Infrastructure up and running with the ability to push a new IOS to the router as well as a configuration built on a template.

As part of this I have an eem script that runs to clean up some configuration before sending the routers off to customer sites.  

I would like to have the eem script run the command "ucse 1 imc config save flash:imc.cfg" which would dump the cimc config to a text file.  Then i would like to be able to parse the file and replace some of the configuration items in there (hostname, dns servers, etc.) and then restore the CIMC config.  This way I wouldn't need to actually log into the CIMC to do this minor configuration step.

18 Replies 18

OK, i did just find there was a period at the end of the while "}."

i removed the period and re-ran the script manually.  It does make it all of the way through now:

000337: Aug  7 14:02:42.842 EDT: BUILDSCRIPT: Reading UCSE CIMC Config
000338: Aug  7 14:02:42.850 EDT: BUILDSCRIPT: Replacing CIMC Config hostname with MediaGen.CIMC.ems.net
000339: Aug  7 14:02:42.854 EDT: BUILDSCRIPT: Replacing CIMC Config DNS Address with 10.41.0.49
000340: Aug  7 14:02:42.862 EDT: BUILDSCRIPT: Deleting Original UCSE CIMC config file
000341: Aug  7 14:02:42.862 EDT: BUILDSCRIPT: Writing new UCSE CIMC config file
000342: Aug  7 14:02:43.366 EDT: BUILDSCRIPT: Configuration Complete !!

However, when i look at the file (cimc.cfg) in flash. It still shows the original hostname and dns?

Robert Radford
Level 1
Level 1

I have update the script and replied to the first item in the discussion as the flow of the discussion was getting a bit hard to follow.

The update includes some changes to allow the use of the path and filename variables throughout the script and provides some better explaination of the reason for each item.

I have also updated some of the variables so that there is not the potential for conflict and means it is easier to read if looking at this for the first time.

 

Good luck and I hope it helps.

 

Scrip below.

######################################################################################################
#
# Scrip to collect the configuration of CIMC configuration,
# modify the configuration, and write the modifications back to the flash file.
#
# Modified entries are for hostname and preferred DNS server. The new values of these entries are sent
# to the script when called.
#
# Certain procedures and methods have been implemented to overcome IOS specific issues in 15.2(4)M6a
# 2 key issues in this IOS are:
#   - the operation of the action_syslog command under tclsh, and
#   - the exec command "ucse 1 imc config save" causing the router to lockup when called from tclsh.
#
# These issues have been resolved in the script by:
#   1. writing to syslog direct, and
#   2. calling the exec command from config mode using the do prefix from within an applet.
#
# call the script "tclsh flash:cimc.tcl newhostname 8.8.8.8"
#
######################################################################################################


# Define variables
set configfile "cimc.cfg"
set path "flash"
set filecheck "$path:$configfile"

set HostName [lindex $argv 0]
set DnsServer [lindex $argv 1]

# Create procedure for sending to syslog to overcome potential issue with action_syslog in 15.2(4)M6a
proc SendSyslog { msg } {
    set syslog [open "syslog: " w+]
    puts $syslog "$msg"
    close $syslog
}

# Create procedure that writes to the file defined in the open path statement
proc WriteToFileProc {cmd} {
    global path
    set writetofile [open $path:eventapplet.txt w+]
    foreach a_cmd $cmd {
        puts $writetofile [set a_cmd]
    }
close $writetofile
}

# Define a procedure that when called will use the WriteFileProc to write the APPLET strings to the file
# doing this in a procedure removes potential buffer overrun if the applet is long and you are pasting directly into the tclsh
# This also allows for different applets to be constructed and called with a simple call.
#
# Note - when the applet contains a " you must prepend as \" so that it is written to the file
proc BuildApplet1Proc { } {
    global configfile
    global path    
    lappend  APPLET  "event manager applet CIMCSAVE"
    lappend  APPLET  "event none"
    lappend  APPLET  "action 1 cli command \"en\""
    lappend  APPLET  "action 2 cli command \"conf t\""
    lappend  APPLET  "action 3 cli command \"do ucse 1 imc config save $path:$configfile\""
    lappend  APPLET  "action 4 cli command \"end\""
    lappend  APPLET  "action 5 cli command \"exit\""
    lappend  APPLET  "!"
    lappend  APPLET  "end"
    WriteToFileProc $APPLET
}

# Validate that arguments have been passed to the script. This could be done with argc however
# we are using the content of the argv variables to validate
if { ($HostName == "") || ($DnsServer == "") } {
    SendSyslog "SCRIPT ERROR: Script called without arguments - exiting"
    SendSyslog "SCRIPT ERROR: usage = <scriptname> <hostname> <dnsip>"
    break
}

# Validate that the IP address of the DNS server is a valid IP construct
if {[regexp {^\d+\.\d+\.\d+\.\d+$} $DnsServer]
    && [scan $DnsServer %d.%d.%d.%d a b c d] == 4
    && 0 <= $a && $a <= 255 && 0 <= $b && $b <= 255
    && 0 <= $c && $c <= 255 && 0 <= $d && $d <= 255} {
} else {
    SendSyslog "SCRIPT ERROR: Script called with invalid DNS IP - exiting"
    SendSyslog "SCRIPT ERROR: usage = <scriptname> <hostname> <dnsip>"
    break
}

# Disable file prompting for file copy to running when loading the applet
ios_config "file prompt quiet"\
"end"

# If there is already a file on the flash - delete it first so that all instances are new when we use them.
SendSyslog "BUILDSCRIPT: Deleting any legacy files"
if { [file exists $filecheck] == 1} {  
    file delete -force $path:/$file
}
if { [file exists $path:eventapplet.txt] == 1} {  
    file delete -force $path:eventapplet.txt
}

# There is a problem is IOS for running the imc save command and hence we need to activate this via an applet from within tclsh
SendSyslog "BUILDSCRIPT: Building applet"
BuildApplet1Proc

# Copy the applet to the running config
SendSyslog "BUILDSCRIPT: Loading the applet into config"
exec "copy $path:eventapplet.txt running-config"

# Run a loop to check that the file has been created. This was created due to issues in 15.2(4)M6a where file creation was a problem
# The loop will run until proceed variable is set to a value other than 0
# the count variable is decremented each pass through the loop as to enable other functions to be called. These functions were put in place
# as under certain conditions, the cimc config could not be saved unless the UCSE module was powered.
# This may not be needed on other IOS - remove if required.
set proceed 0
set countdown 20
while {$proceed<=0} {
    after 3000
    SendSyslog "BUILDSCRIPT: Generating IMC config file"
    exec "event manager run CIMCSAVE"
    if { [file exists $filecheck] == 1} {  
        SendSyslog "BUILDSCRIPT: IMC Config file generated successfully - cleaning up"
        ios_config "no event manager applet CIMCSAVE"\
        "end"
        file delete -force $path:eventapplet.txt
        set proceed 1
    }
    if { $countdown == 15 } {
        # If countdown = 15 then open the UCSE interfaces
        ios_config "interface UCSE 1/0"\
        "no shutdown"\
        "end"
        ios_config "interface UCSE 1/1"\
        "no shutdown"\
        "end"
        puts "Configuring UCSE Interface"
    }
        # If countdown reaches 10 then start the UCSE
    if { $countdown == 10 } {
        exec "ucse 1 start"
        puts "starting UCSE"
    }
    set countdown [expr $countdown - 1]
}

# Read the config file setting the contents as a temp variable
SendSyslog "BUILDSCRIPT: Reading UCSE CIMC Config"
set configfile [exec "more $path:$configfile"]

# Replace the items in the variable "configfile" with the arguments supplied to the script
SendSyslog "BUILDSCRIPT: Replacing CIMC Config hostname with $HostName"
regsub -all -nocase {<hostname>([a-zA-Z0-9._-]*)} $configfile <hostname>$HostName configfile

SendSyslog "BUILDSCRIPT: Replacing CIMC Config DNS Address with $DnsServer"
regsub -all -nocase {<preferred-dns-server>([0-9.]*)} $configfile <preferred-dns-server>$DnsServer configfile

# Delete the original config file
SendSyslog "BUILDSCRIPT: Deleting Original UCSE CIMC config file"
file delete -force $path:/$configfile

# Create a new config file with the "configfile" information
SendSyslog "BUILDSCRIPT: Writing new UCSE CIMC config file"
set writefile [open "$path:$configfile" w+]
puts $writefile "$configfile\r"
close $writefile

# Send notification that the script has been completed
SendSyslog "BUILDSCRIPT: Configuration Complete !!"

 

smolz
Level 4
Level 4

Thank you very, very much for doing this!  Everything is working great!

My pleaseure and I hope it all goes well.

Regards,

Robert.

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: