You specify the hostmask and the the command you wish to execute(-e) OR you can tell it to execute a local executable on your minions. There are a couple of behaviour switches to change up how it reports as well. The first output line is the return code followed by STDERR and STDOUT.
For example:
[root@testbox01 python]# ./func_exec.py "19002web*" -e 'echo test'
Starting run: 11/16/2009 14:53:41
Hostmask '19002web*' returns '2' host(s)
(19002web01)
0
test
(19002web01)
0
test
OR, you can tell it to execute a locally sourced executable. The script will use the func 'copyfile' module to copy the file and then the 'command' module to execute it. It will then remove the file on the remote machine when exec is completed (all of this is automatic).
For example:
[root@testbox01 python]# cat test.sh
date
echo "Hello World!"
exit 0
[root@testbox01 python]# ./func_exec.py "19002*" -f test.sh
Starting run: 11/16/2009 14:57:51
Hostmask '19002*' returns '2' host(s)
(19002mys01)
0
Mon Nov 16 14:57:50 CST 2009
Hello World!
(19002web01)
0
Mon Nov 16 14:57:50 CST 2009
Hello World!
And also you can tell it to only display the output if a certain exit code is returned. This is most useful when using yum to 'check-update'. Yum will return 0 when no updates are pending and a 100 when there are indeed pending updates along with which packages need updating.
For Example:
[root@testbox01 python]# ./func_exec.py "40000*" -e 'yum check-update' -r 100
Starting run: 11/16/2009 15:04:09
Hostmask '40000*' returns '9' host(s)
Showing '1' result(s)
(40000mys01)
100
Loaded plugins: rhnplugin
Excluding Packages in global exclude list
Finished
coreutils.x86_64 5.97-23.el5_4.1 pnl-rhel-x86_64-server-5
dbus-python.x86_64 0.70-9.el5_4 pnl-rhel-x86_64-server-5
device-mapper-multipath.x86_64 0.4.7-30.el5_4.2 pnl-rhel-x86_64-server-5
As you can see, only one box's output was displayed because that yum command returned a 100, which we specified as a command line option.
Let me know if you have any comments or questions.
-Nick Nachefski
Here is func_exec.py, it is also attached to this message.....
#!/usr/bin/python
#Written by nicholas <underscore> nachefski <at> hotmail <dot> com
#init
import func.overlord.client as fc
import getopt, sys, datetime, re, os
#subroutines
def usage():
print "Usage: %s <host mask>"%sys.argv[0]
sys.exit(2)
#get options
if len(sys.argv) < 2:
usage()
#check if file exists and is +x
def is_exe(fpath):
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
#define our remote exec function
def exec_command(hostMask, threads, exec_command):
client = fc.Client(hostMask,nforks=threads)
if client.command.exists(exec_command):
returnD = client.command.run(exec_command)
return returnD
else:
print "func 'command' module not found on remote machine"
return 1
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-r", "--return",
action="" type="int", dest="returncode",
help="only report on a specific return code")
parser.add_option("-t", "--threads",
action="" type="int", dest="threads", default=10,
help="number of treads to use (-t 10)" )
parser.add_option("-e", "--exe",
action="" type="string", dest="command",
help="command to execute (-e 'echo test')")
parser.add_option("-f", "--file",
action="" type="string", dest="xfile",
help="execute local script (-f script.sh)" )
#parse remaining args, including hostMask
(options, args) = parser.parse_args()
hostdata = args[0]
#argument santiy checking
if (not options.xfile) and (not options.command):
print "You need to tell me something to do ie: -e or -f"
sys.exit(2)
if (options.xfile) and (options.command):
print "You cannot have both -e and -f options set"
sys.exit(2)
#Start Main##############################################
def main():
hostMask = ''
hosts = []
if os.path.isfile(hostdata):
file = open(hostdata,"r")
while file:
line = file.readline()
if not line:
break
host = line.strip('\n')
hostMask = hostMask + host + ';'
file.close()
else:
hostMask = hostdata
if re.match ('.+;
, hostMask):
hostMask = hostMask.strip(';')
#if we are using xfile, transfer it now.
if options.xfile:
if is_exe(options.xfile) == True:
if re.match ('^\/.+', options.xfile):
m = re.match('.*\/(.+)
, options.xfile)
rPath = m.group(1)
else:
rPath = options.xfile
remotePath = "/tmp/" + rPath
fc.Client(hostMask,nforks=options.threads).local.copyfile.send(options.xfile, remotePath)
#set the command to be the exec file uploaded
options.command = remotePath + ' &'
#get data for report
t = datetime.datetime.now()
print "Starting run:", t.strftime("%m/%d/%Y %H:%M:%S"),
returnD = exec_command(hostMask, options.threads, options.command)
if type(returnD) == type(int()):
print "exec_command function failed!"
sys.exit(1)
if options.xfile:
delComm = "rm -rf " + remotePath
tempD = exec_command(hostMask, options.threads, delComm)
#start printing the report
print "\nHostmask '%s' returns '%d' host(s)" % (hostMask, len(returnD))
sortedD = returnD.keys()
sortedD.sort()
report_count = 0
for key in sortedD:
if type(options.returncode) == type(int()):
if returnD[key][0] == options.returncode:
report_count += 1
if type(options.returncode) == type(int()):
print "Showing '%s' results\n" % (report_count)
for key in sortedD:
if type(options.returncode) == type(int()):
if returnD[key][0] == options.returncode:
print "(%s)" % key
print returnD[key][0]
print returnD[key][1]
else:
continue
else:
print "(%s)" % key
print returnD[key][0]
print returnD[key][1]
#exit cleanly
sys.exit(0)
if __name__ == "__main__":
main()
Attachment:
func_exec.py
Description: Binary data
_______________________________________________ Func-list mailing list Func-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/func-list