diff options
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | func.spec | 1 | ||||
-rw-r--r-- | func/minion/modules/filetracker.py | 197 | ||||
-rwxr-xr-x | func/minion/modules/virt.py | 11 | ||||
-rw-r--r-- | setup.py | 2 |
5 files changed, 212 insertions, 2 deletions
@@ -11,7 +11,8 @@ func is written by (alphabetically) ... Additional patches and contributions by ... + Vito Laurenza <vitolaurenza@gmail.com> ... - [ send in patches to get your name here ] + [ send in patches (or modules!) to get your name here ] @@ -50,6 +50,7 @@ rm -fr $RPM_BUILD_ROOT %dir %{_sysconfdir}/%{name} %dir %{_sysconfdir}/%{name}/minion-acl.d/ %dir %{_sysconfdir}/pki/%{name} +%dir /etc/func/modules/ %config(noreplace) /etc/func/minion.conf %config(noreplace) /etc/func/certmaster.conf %config(noreplace) /etc/logrotate.d/func_rotate diff --git a/func/minion/modules/filetracker.py b/func/minion/modules/filetracker.py new file mode 100644 index 0000000..efcc31c --- /dev/null +++ b/func/minion/modules/filetracker.py @@ -0,0 +1,197 @@ +#!/usr/bin/python + +## func +## +## filetracker +## maintains a manifest of files of which to keep track +## provides file meta-data (and optionally full data) to func-inventory +## +## (C) Vito Laurenza <vitolaurenza@gmail.com> +## +## This software may be freely redistributed under the terms of the GNU +## general public license. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + +# func modules +from modules import func_module + +# other modules +# import ConfigParser +from stat import * +import os +import sys +import md5 + +# defaults +CONFIG_FILE='/etc/func/modules/filetracker.conf' + +class FileTracker(func_module.FuncModule): + + def __init__(self): + self.methods = { + "track" : self.track, + "untrack" : self.untrack, + "info" : self.inventory, + "inventory" : self.inventory, + } + func_module.FuncModule.__init__(self) + + #========================================================== + + def __load(self): + """ + Parse file and return data structure. + """ + + filehash = {} + if os.path.exists(CONFIG_FILE): + config = open(CONFIG_FILE, "r") + data = config.read() + lines = data.split("\n") + for line in lines: + tokens = line.split(None) + if len(tokens) < 2: + continue + scan_mode = tokens[0] + path = " ".join(tokens[1:]) + if str(scan_mode).lower() == "0": + scan_mode = 0 + else: + scan_mode = 1 + filehash[path] = scan_mode + return filehash + + #========================================================== + + def __save(self, filehash): + """ + Write data structure to file. + """ + + config = open(CONFIG_FILE, "w+") + for (path, scan_mode) in filehash.iteritems(): + config.write("%s %s\n" % (scan_mode, path)) + config.close() + + #========================================================== + + def track(self, file_name, full_scan=0): + """ + Adds files to keep track of. + full_scan implies tracking the full contents of the file, defaults to off + """ + + filehash = self.__load() + filehash[file_name] = full_scan + self.__save(filehash) + return 1 + + #========================================================== + + def untrack(self, file_name): + """ + Stop keeping track of a file. + This routine is tolerant of most errors since we're forgetting about the file anyway. + """ + + filehash = self.__load() + print "DEBUG: deleting: %s" % file_name + print "DEBUG: keys: %s" % filehash + if file_name in filehash.keys(): + del filehash[file_name] + self.__save(filehash) + return 1 + + #========================================================== + + def inventory(self, flatten=1, checksum_enabled=1): + """ + Returns information on all tracked files + By default, 'flatten' is passed in as True, which makes printouts very clean in diffs + for use by func-inventory. If you are writting another software application, using flatten=False will + prevent the need to parse the returns. + """ + + # XMLRPC feeds us strings from the CLI when it shouldn't + flatten = int(flatten) + checksum_enabled = int(checksum_enabled) + + filehash = self.__load() + + # we'll either return a very flat string (for clean diffs) + # or a data structure + if flatten: + results = "" + else: + results = [] + + for (file_name, scan_type) in filehash.iteritems(): + + if not os.path.exists(file_name): + if flatten: + results = results + "%s: does not exist\n" % file_name + else: + results.append("%s: does not exist\n" % file_name) + continue + + this_result = [] + + # ----- always process metadata + filestat = os.stat(file_name) + mode = filestat[ST_MODE] + mtime = filestat[ST_MTIME] + uid = filestat[ST_UID] + gid = filestat[ST_GID] + if not os.path.isdir(file_name) and checksum_enabled: + sum_handle = open(file_name) + hash = self.sumfile(sum_handle) + sum_handle.close() + else: + hash = "N/A" + + # ------ what we return depends on flatten + if flatten: + this_result = "%s: mode=%s mtime=%s uid=%s gid=%s md5sum=%s\n" % (file_name,mode,mtime,uid,gid,hash) + else: + this_result = [file_name,mode,mtime,uid,gid,hash] + + # ------ add on file data only if requested + if scan_type != 0 and os.path.isfile(file_name): + tracked_file = open(file_name) + data = tracked_file.read() + if flatten: + this_result = this_result + "*** DATA *******\n" + data + "\n*** END DATA ***\n\n" + else: + this_result.append(data) + tracked_file.close() + + if flatten: + results = results + "\n" + this_result + else: + results.append(this_result) + + + return results + + #========================================================== + + def sumfile(self, fobj): + """ + Returns an md5 hash for an object with read() method. + credit: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266486 + """ + + m = md5.new() + while True: + d = fobj.read(8096) + if not d: + break + m.update(d) + return m.hexdigest() + +methods = FileTracker() +register_rpc = methods.register_rpc diff --git a/func/minion/modules/virt.py b/func/minion/modules/virt.py index 7dc5697..3e7fc2d 100755 --- a/func/minion/modules/virt.py +++ b/func/minion/modules/virt.py @@ -22,7 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # other modules import os import sub_process -import libvirt +# import libvirt # our modules import codes @@ -42,6 +42,13 @@ class FuncLibvirtConnection(object): def __init__(self): + self.loaded = False + + try: + import libvirt + self.loaded = True + except: + return cmd = sub_process.Popen("uname -r", shell=True, stdout=sub_process.PIPE) output = cmd.communicate()[0] @@ -147,6 +154,8 @@ class Virt(func_module.FuncModule): def get_conn(self): self.conn = FuncLibvirtConnection() + if not self.conn.loaded: + return False return self.conn def info(self): @@ -15,6 +15,7 @@ if __name__ == "__main__": manpath = "share/man/man1/" etcpath = "/etc/%s" % NAME + etcmodpath = "/etc/%s/modules" % NAME initpath = "/etc/init.d/" logpath = "/var/log/%s/" % NAME pkipath = "/etc/pki/%s" % NAME @@ -45,6 +46,7 @@ if __name__ == "__main__": (initpath, ["init-scripts/certmaster"]), (etcpath, ["etc/minion.conf"]), (etcpath, ["etc/certmaster.conf"]), + (etcmodpath, []), (manpath, ["docs/func.1.gz"]), (manpath, ["docs/func-inventory.1.gz"]), (manpath, ["docs/funcd.1.gz"]), |