Remote Command Exec Client for Func Master

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I wrote a short python script that uses the func provided 'command' module to perform any remote task.  It is very useful for me when controlling my 'func' enabled RHEL5 environment(400+), so i thought i would share with the community.

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]
                print
        else:
            continue
    else:
        print "(%s)" % key
            print returnD[key][0]
            print returnD[key][1]
            print

    #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

[Index of Archives]     [Fedora Users]     [Linux Networking]     [Fedora Legacy List]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]

  Powered by Linux