Does any of this require python 2.5? I haven't tried it yet. So as long as this still works on RHEL 4, I'm ok with it. jesus -- jesus m. rodriguez | jesusr@xxxxxxxxxx sr. software engineer | irc: zeus red hat network | 919.754.4413 x44413 +-------------------------------------------+ | "Those who cannot learn from history | | are doomed to repeat it." | | -- George Santayana | +-------------------------------------------+ On Tue, Jan 15, 2008 at 06:05:19PM -0500, Luke Macken wrote: > Dear Lords of Func, > > This is a pretty significant change to the way our modules are currently > written. The result is that it makes writing modules much more simple, by > removing all hard-coded method definitions and register_rpc methods. > > Some brief testing on my end shows it to work fine, but still needs more > testing to ensure that we don't regress. > > If no one has any problems with it, I can commit it. > > luke > > === > > - Auto-detect and load all FuncModules. This obsoletes the need to have our > modules define a register_rpc method. > - Use introspection in our FuncModule to auto-register all method handlers > that do not being with an underscore. This obsoletes the need to > hardcode methods in our modules. > - Remove all __init__ methods from our modules, along with register_rpc > - Modify the func-create-module script to reflect these changes. Note that > doing 'from modules import func_module' is no longer supported in our modules, > do to some interesting path issues with our auto-detection code. Supported > methods are now: > 'import func_module' or 'from func.minion.modules import func_module' > > diff --git a/func/minion/module_loader.py b/func/minion/module_loader.py > index 6fb2a6b..f8f8f42 100755 > --- a/func/minion/module_loader.py > +++ b/func/minion/module_loader.py > @@ -19,10 +19,11 @@ import sys > from gettext import gettext > _ = gettext > > - > from func import logger > logger = logger.Logger().logger > > +from inspect import isclass > +from func.minion.modules import func_module > > def module_walker(topdir): > module_files = [] > @@ -80,13 +81,15 @@ def load_modules(blacklist=None): > continue > > try: > + # Auto-detect and load all FuncModules > blip = __import__("modules.%s" % ( mod_imp_name), globals(), locals(), [mod_imp_name]) > - if not hasattr(blip, "register_rpc"): > - errmsg = _("%(module_path)s%(modname)s module not a proper module") > - logger.warning(errmsg % {'module_path': module_file_path, 'modname':mod_imp_name}) > - bad_mods[mod_imp_name] = True > - continue > - mods[mod_imp_name] = blip > + for obj in dir(blip): > + attr = getattr(blip, obj) > + if isclass(attr): > + if issubclass(attr, func_module.FuncModule): > + logger.debug("Loading %s module" % attr) > + mods[mod_imp_name] = attr() > + > except ImportError, e: > # A module that raises an ImportError is (for now) simply not loaded. > errmsg = _("Could not load %s module: %s") > diff --git a/func/minion/modules/command.py b/func/minion/modules/command.py > index 3329927..9b93de5 100644 > --- a/func/minion/modules/command.py > +++ b/func/minion/modules/command.py > @@ -13,19 +13,11 @@ > Abitrary command execution module for func. > """ > > -from modules import func_module > - > +import func_module > import sub_process > > class Command(func_module.FuncModule): > > - def __init__(self): > - self.methods = { > - "run" : self.run, > - "exists" : self.exists, > - } > - func_module.FuncModule.__init__(self) > - > def run(self, command): > """ > Runs a command, returning the return code, stdout, and stderr as a tuple. > @@ -46,7 +38,3 @@ class Command(func_module.FuncModule): > if os.access(command, os.X_OK): > return True > return False > - > - > -methods = Command() > -register_rpc = methods.register_rpc > \ No newline at end of file > diff --git a/func/minion/modules/copyfile.py b/func/minion/modules/copyfile.py > index 6c81098..85001f8 100644 > --- a/func/minion/modules/copyfile.py > +++ b/func/minion/modules/copyfile.py > @@ -14,7 +14,7 @@ import os > import time > import shutil > > -from modules import func_module > +import func_module > > > > @@ -22,15 +22,6 @@ from modules import func_module > class CopyFile(func_module.FuncModule): > version = "0.0.1" > api_version = "0.0.2" > - > - > - > - def __init__(self): > - self.methods = { > - "copyfile" : self.copyfile, > - "checksum" : self.checksum > - } > - func_module.FuncModule.__init__(self) > > def _checksum_blob(self, blob): > CHUNK=2**16 > @@ -118,8 +109,3 @@ class CopyFile(func_module.FuncModule): > #XXX logger output here > return False > return True > - > - > - > -methods = CopyFile() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/filetracker.py b/func/minion/modules/filetracker.py > index 0aa4a49..8deb382 100644 > --- a/func/minion/modules/filetracker.py > +++ b/func/minion/modules/filetracker.py > @@ -16,7 +16,7 @@ > ## > > # func modules > -from modules import func_module > +import func_module > > # other modules > from stat import * > @@ -30,17 +30,6 @@ 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. > @@ -145,7 +134,7 @@ class FileTracker(func_module.FuncModule): > gid = filestat[ST_GID] > if not os.path.isdir(file_name) and checksum_enabled: > sum_handle = open(file_name) > - hash = self.sumfile(sum_handle) > + hash = self.__sumfile(sum_handle) > sum_handle.close() > else: > hash = "N/A" > @@ -185,7 +174,7 @@ class FileTracker(func_module.FuncModule): > > #========================================================== > > - def sumfile(self, fobj): > + def __sumfile(self, fobj): > """ > Returns an md5 hash for an object with read() method. > credit: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266486 > @@ -198,6 +187,3 @@ class FileTracker(func_module.FuncModule): > break > m.update(d) > return m.hexdigest() > - > -methods = FileTracker() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/func_module.py b/func/minion/modules/func_module.py > index 5965e24..c911b91 100644 > --- a/func/minion/modules/func_module.py > +++ b/func/minion/modules/func_module.py > @@ -10,6 +10,7 @@ > ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > ## > > +import inspect > > from func import logger > from func.config import read_config > @@ -34,7 +35,7 @@ class FuncModule(object): > "module_api_version" : self.__module_api_version, > "module_description" : self.__module_description, > "list_methods" : self.__list_methods > - } > + } > > def __init_log(self): > log = logger.Logger() > @@ -45,8 +46,11 @@ class FuncModule(object): > # can get clobbbered by subclass versions > for meth in self.__base_methods: > handlers["%s.%s" % (module_name, meth)] = self.__base_methods[meth] > - for meth in self.methods: > - handlers["%s.%s" % (module_name,meth)] = self.methods[meth] > + > + # register all methods that don't start with an underscore > + for attr in dir(self): > + if inspect.ismethod(getattr(self, attr)) and attr[0] != '_': > + handlers["%s.%s" % (module_name, attr)] = getattr(self, attr) > > def __list_methods(self): > return self.methods.keys() + self.__base_methods.keys() > @@ -59,7 +63,3 @@ class FuncModule(object): > > def __module_description(self): > return self.description > - > - > -methods = FuncModule() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/hardware.py b/func/minion/modules/hardware.py > index acf5988..5136228 100644 > --- a/func/minion/modules/hardware.py > +++ b/func/minion/modules/hardware.py > @@ -20,18 +20,11 @@ import sys > > # our modules > import sub_process > -from modules import func_module > +import func_module > > # ================================= > > class HardwareModule(func_module.FuncModule): > - def __init__(self): > - self.methods = { > - "info" : self.info, > - "inventory" : self.inventory, # for func-inventory > - "hal_info" : self.hal_info > - } > - func_module.FuncModule.__init__(self) > > def hal_info(self): > """ > @@ -131,6 +124,3 @@ def hw_info(with_devices=True): > }) > > return data > - > -methods = HardwareModule() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/mount.py b/func/minion/modules/mount.py > index e8e41ce..1b4671d 100644 > --- a/func/minion/modules/mount.py > +++ b/func/minion/modules/mount.py > @@ -13,18 +13,10 @@ > ## > > import sub_process, os > -from modules import func_module > +import func_module > > > class MountModule(func_module.FuncModule): > - def __init__(self): > - self.methods = { > - "list": self.list, > - "mount": self.mount, > - "umount": self.umount, > - "inventory": self.inventory, > - } > - func_module.FuncModule.__init__(self) > > def list(self): > cmd = sub_process.Popen(["/bin/cat", "/proc/mounts"], executable="/bin/cat", stdout=sub_process.PIPE, shell=False) > @@ -86,7 +78,3 @@ class MountModule(func_module.FuncModule): > > def inventory(self, flatten=True): > return self.list() > - > - > -methods = MountModule() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/nagios-check.py b/func/minion/modules/nagios-check.py > index a902762..80889ce 100644 > --- a/func/minion/modules/nagios-check.py > +++ b/func/minion/modules/nagios-check.py > @@ -13,18 +13,11 @@ > Abitrary command execution module for func. > """ > > -from modules import func_module > - > +import func_module > import sub_process > > class Nagios(func_module.FuncModule): > > - def __init__(self): > - self.methods = { > - "run" : self.run > - } > - func_module.FuncModule.__init__(self) > - > def run(self, check_command): > """ > Runs a nagios check returning the return code, stdout, and stderr as a tuple. > @@ -35,8 +28,3 @@ class Nagios(func_module.FuncModule): > cmdref = sub_process.Popen(command.split(),stdout=sub_process.PIPE,stderr=sub_process.PIPE, shell=False) > data = cmdref.communicate() > return (cmdref.returncode, data[0], data[1]) > - > -methods = Nagios() > -register_rpc = methods.register_rpc > - > - > diff --git a/func/minion/modules/process.py b/func/minion/modules/process.py > index 92c6d6a..18b5abe 100644 > --- a/func/minion/modules/process.py > +++ b/func/minion/modules/process.py > @@ -18,19 +18,11 @@ import sub_process > import codes > > # our modules > -from modules import func_module > +import func_module > > # ================================= > > class ProcessModule(func_module.FuncModule): > - def __init__(self): > - self.methods = { > - "info" : self.info, > - "kill" : self.kill, > - "pkill" : self.pkill, > - "mem" : self.mem > - } > - func_module.FuncModule.__init__(self) > > def info(self,flags="-auxh"): > """ > @@ -208,6 +200,3 @@ class ProcessModule(func_module.FuncModule): > # example killall("thunderbird","-9") > rc = sub_process.call(["/usr/bin/pkill", name, level], executable="/usr/bin/pkill", shell=False) > return rc > - > -methods = ProcessModule() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/reboot.py b/func/minion/modules/reboot.py > index 8772b8f..0af78f9 100644 > --- a/func/minion/modules/reboot.py > +++ b/func/minion/modules/reboot.py > @@ -8,22 +8,10 @@ > # along with this program; if not, write to the Free Software > # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > > - > -from modules import func_module > - > +import func_module > import sub_process > > class Reboot(func_module.FuncModule): > > - def __init__(self): > - self.methods = { > - "reboot" : self.reboot > - } > - func_module.FuncModule.__init__(self) > - > def reboot(self, when='now', message=''): > return sub_process.call(["/sbin/shutdown", '-r', when, message]) > - > - > -methods = Reboot() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/rpms.py b/func/minion/modules/rpms.py > index 901a9d6..f73e9db 100644 > --- a/func/minion/modules/rpms.py > +++ b/func/minion/modules/rpms.py > @@ -8,18 +8,11 @@ > # along with this program; if not, write to the Free Software > # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > > -from modules import func_module > +import func_module > import rpm > > class RpmModule(func_module.FuncModule): > > - def __init__(self): > - self.methods = { > - "inventory" : self.inventory, > - "info" : self.inventory > - } > - func_module.FuncModule.__init__(self) > - > def inventory(self, flatten=True): > """ > Returns information on all installed packages. > @@ -43,6 +36,3 @@ class RpmModule(func_module.FuncModule): > else: > results.append([name,epoch,version,release,arch]) > return results > - > -methods = RpmModule() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/service.py b/func/minion/modules/service.py > index d088907..d1170a8 100644 > --- a/func/minion/modules/service.py > +++ b/func/minion/modules/service.py > @@ -13,26 +13,13 @@ > ## > > import codes > -from modules import func_module > +import func_module > > import sub_process > import os > > class Service(func_module.FuncModule): > > - def __init__(self): > - self.methods = { > - "start" : self.start, > - "stop" : self.stop, > - "restart" : self.restart, > - "reload" : self.reload, > - "status" : self.status, > - "get_enabled" : self.get_enabled, > - "get_running" : self.get_running, > - "inventory" : self.inventory, > - } > - func_module.FuncModule.__init__(self) > - > def __command(self, service_name, command): > > filename = os.path.join("/etc/rc.d/init.d/",service_name) > @@ -95,6 +82,3 @@ class Service(func_module.FuncModule): > tokens = line.split() > results.append((tokens[0], tokens[-1].replace("...",""))) > return results > - > -methods = Service() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/smart.py b/func/minion/modules/smart.py > index e85b90c..ff7afd9 100644 > --- a/func/minion/modules/smart.py > +++ b/func/minion/modules/smart.py > @@ -17,17 +17,11 @@ > import sub_process > > # our modules > -from modules import func_module > +import func_module > > # ================================= > > class SmartModule(func_module.FuncModule): > - def __init__(self): > - self.methods = { > - "info" : self.info, > - "inventory" : self.info, # for func-inventory > - } > - func_module.FuncModule.__init__(self) > > def info(self,flags="-q onecheck"): > """ > @@ -47,6 +41,3 @@ class SmartModule(func_module.FuncModule): > results.append(x) > > return (cmd.returncode, results) > - > -methods = SmartModule() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/snmp.py b/func/minion/modules/snmp.py > index 3144144..374821c 100644 > --- a/func/minion/modules/snmp.py > +++ b/func/minion/modules/snmp.py > @@ -13,19 +13,12 @@ > Abitrary command execution module for func. > """ > > -from modules import func_module > - > +import func_module > import sub_process > base_snmp_command = '/usr/bin/snmpget -v2c -Ov -OQ' > > class Snmp(func_module.FuncModule): > > - def __init__(self): > - self.methods = { > - "get" : self.get > - } > - func_module.FuncModule.__init__(self) > - > def get(self, oid, rocommunity, hostname='localhost'): > """ > Runs an snmpget on a specific oid returns the output of the call. > @@ -39,8 +32,3 @@ class Snmp(func_module.FuncModule): > #def walk(self, oid, rocommunity): > > #def table(self, oid, rocommunity): > - > -methods = Snmp() > -register_rpc = methods.register_rpc > - > - > diff --git a/func/minion/modules/test.py b/func/minion/modules/test.py > index 24af03e..6718fed 100644 > --- a/func/minion/modules/test.py > +++ b/func/minion/modules/test.py > @@ -1,17 +1,10 @@ > -from modules import func_module > +import func_module > import time > > class Test(func_module.FuncModule): > version = "11.11.11" > api_version = "0.0.1" > description = "Just a very simple example module" > - def __init__(self): > - self.methods = { > - "add": self.add, > - "ping": self.ping, > - "sleep": self.sleep > - } > - func_module.FuncModule.__init__(self) > > def add(self, numb1, numb2): > return numb1 + numb2 > @@ -27,6 +20,3 @@ class Test(func_module.FuncModule): > t = int(t) > time.sleep(t) > return time.time() > - > -methods = Test() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/virt.py b/func/minion/modules/virt.py > index ba888ec..3671172 100644 > --- a/func/minion/modules/virt.py > +++ b/func/minion/modules/virt.py > @@ -119,31 +119,8 @@ class FuncLibvirtConnection(object): > > class Virt(func_module.FuncModule): > > - > - def __init__(self): > - > - """ > - Constructor. Register methods and make them available. > - """ > - > - self.methods = { > - "install" : self.install, > - "shutdown" : self.shutdown, > - "destroy" : self.destroy, > - "start" : self.create, > - "pause" : self.pause, > - "unpause" : self.unpause, > - "delete" : self.undefine, > - "status" : self.get_status, > - "info" : self.info, > - "inventory" : self.info, # for func-inventory > - "list_vms" : self.list_vms, > - } > - > - func_module.FuncModule.__init__(self) > - > - def get_conn(self): > - self.conn = FuncLibvirtConnection() > + def __get_conn(self): > + self.conn = FuncLibvirtConnection() > return self.conn > > def state(self): > @@ -176,7 +153,7 @@ class Virt(func_module.FuncModule): > > > def list_vms(self): > - self.conn = self.get_conn() > + self.conn = self.__get_conn() > vms = self.conn.find_vm(-1) > results = [] > for x in vms: > @@ -195,7 +172,7 @@ class Virt(func_module.FuncModule): > # Example: > # install("bootserver.example.org", "fc7webserver", True) > > - conn = self.get_conn() > + conn = self.__get_conn() > > if conn is None: > raise codes.FuncException("no connection") > @@ -227,7 +204,7 @@ class Virt(func_module.FuncModule): > Make the machine with the given vmid stop running. > Whatever that takes. > """ > - self.get_conn() > + self.__get_conn() > self.conn.shutdown(vmid) > return 0 > > @@ -237,7 +214,7 @@ class Virt(func_module.FuncModule): > """ > Pause the machine with the given vmid. > """ > - self.get_conn() > + self.__get_conn() > self.conn.suspend(vmid) > return 0 > > @@ -248,7 +225,7 @@ class Virt(func_module.FuncModule): > Unpause the machine with the given vmid. > """ > > - self.get_conn() > + self.__get_conn() > self.conn.resume(vmid) > return 0 > > @@ -258,7 +235,7 @@ class Virt(func_module.FuncModule): > """ > Start the machine via the given mac address. > """ > - self.get_conn() > + self.__get_conn() > self.conn.create(vmid) > return 0 > > @@ -269,7 +246,7 @@ class Virt(func_module.FuncModule): > Pull the virtual power from the virtual domain, giving it virtually no > time to virtually shut down. > """ > - self.get_conn() > + self.__get_conn() > self.conn.destroy(vmid) > return 0 > > @@ -281,7 +258,7 @@ class Virt(func_module.FuncModule): > by deleting the disk image and it's configuration file. > """ > > - self.get_conn() > + self.__get_conn() > self.conn.undefine(vmid) > return 0 > > @@ -292,9 +269,5 @@ class Virt(func_module.FuncModule): > Return a state suitable for server consumption. Aka, codes.py values, not XM output. > """ > > - self.get_conn() > + self.__get_conn() > return self.conn.get_status(vmid) > - > - > -methods = Virt() > -register_rpc = methods.register_rpc > diff --git a/func/minion/modules/yumcmd.py b/func/minion/modules/yumcmd.py > index b3976fb..8bf760c 100644 > --- a/func/minion/modules/yumcmd.py > +++ b/func/minion/modules/yumcmd.py > @@ -8,8 +8,7 @@ > # along with this program; if not, write to the Free Software > # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > > - > -from modules import func_module > +import func_module > > import yum > from yum import repos > @@ -22,13 +21,6 @@ class DummyCallback(object): > > class Yum(func_module.FuncModule): > > - def __init__(self): > - self.methods = { > - "update" : self.update, > - "check_update" : self.check_update > - } > - func_module.FuncModule.__init__(self) > - > def update(self): > # XXX support updating specific rpms > ayum = yum.YumBase() > @@ -52,7 +44,3 @@ class Yum(func_module.FuncModule): > ayum.doTsSetup() > ayum.repos.enableRepo(repo) > return map(str, ayum.doPackageLists('updates').updates) > - > - > -methods = Yum() > -register_rpc = methods.register_rpc > diff --git a/scripts/func-create-module b/scripts/func-create-module > index afb4d09..7cbf9eb 100755 > --- a/scripts/func-create-module > +++ b/scripts/func-create-module > @@ -10,9 +10,7 @@ > # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > > TEMPLATE = """\ > -from modules import func_module > -# Add your imports here > -import sub_process > +import func_module > > class %s(func_module.FuncModule): > > @@ -21,17 +19,7 @@ class %s(func_module.FuncModule): > api_version = "0.0.1" > description = "%s" > > - def __init__(self): > - self.methods = { > %s > - } > - func_module.FuncModule.__init__(self) > - > -%s > - > - > -methods = %s() > -register_rpc = methods.register_rpc > """ > > > @@ -40,12 +28,9 @@ def populate_template(module_name, desc, methods): > Makes the method strings and populates the template. > """ > actual_methods = "" > - method_str_dict = "" > for method in methods: > - method_str_dict += ' "%s": self.%s,\n' % (method, method) > - actual_methods += " def self.%s(self):\n pass\n\n" % method > - return TEMPLATE % (module_name, desc, > - method_str_dict[:-1], actual_methods[:-2], module_name) > + actual_methods += " def %s(self):\n pass\n\n" % method > + return TEMPLATE % (module_name, desc, actual_methods[:-2]) > > > if __name__ == '__main__': > @@ -63,4 +48,4 @@ if __name__ == '__main__': > file_obj = open(file_name, "w") > file_obj.write(populate_template(module_name, desc, methods)) > file_obj.close() > - print "Your module is ready to be hacked on. Wrote out to %s." % file_name > \ No newline at end of file > + print "Your module is ready to be hacked on. Wrote out to %s." % file_name > -- > 1.5.3.3 > > _______________________________________________ > Func-list mailing list > Func-list@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/func-list _______________________________________________ Func-list mailing list Func-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/func-list