1. marklap
  2. pyHai

Commits

marklap  committed 041c1fc

major import fixing

  • Participants
  • Parent commits 6c16c85
  • Branches default

Comments (0)

Files changed (33)

File apidocs/pyhai.apidoc.tar.gz

Binary file modified.

File apidocs/pyhai.apidoc.zip

Binary file modified.

File docs/pyhai.htmldoc.zip

Binary file modified.

File src/dist/pyhai-0.1.3.tar.bz2

Binary file added.

File src/dist/pyhai-0.1.3.tar.gz

Binary file added.

File src/dist/pyhai-0.1.3.win-amd64.tar.bz2

Binary file added.

File src/dist/pyhai-0.1.3.win-amd64.tar.gz

Binary file added.

File src/dist/pyhai-0.1.3.win-amd64.zip

Binary file added.

File src/dist/pyhai-0.1.3.zip

Binary file added.

File src/main.py

View file
 
 if __name__ == '__main__':
     import sys
+    import os
     import logging
     from pprint import pprint
-    sys.path.insert(0, '.')
-    from pyhai import pyhai
+    _here_ = os.path.dirname(os.path.abspath(__file__))
+    if _here_ not in sys.path:
+        sys.path.insert(0, _here_)
+    import pyhai
     logging.basicConfig(level=logging.DEBUG)
     print pprint(pyhai.audit(convert_date_to_iso=False))

File src/pyhai/__init__.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
+import abc
+import os
+import sys
+import datetime
+import time
+import utils
+import profilers.base
+import profilers.default
+
 import logging
-import abc
-
-
 # set some default logging behavior
 _logger = logging.getLogger(__name__)
 _logger.addHandler(logging.NullHandler())
 
+# current version
+__VERSION__ = (0, 1, 3)
+VERSION = '.'.join(map(str, __VERSION__))
 
-class AuditorPlugin(object):
+# set some default variables
+PACKAGE_PLUGIN_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'plugins')
+DEFAULT_CUSTOM_PLUGIN_PATH = os.path.join(os.path.dirname(os.path.abspath('.')), 'plugins')
+PLUGIN_LOADER_EXCLUSIONS = ('.', '..', '__init__.py', '__init__.pyc', '__init__.pyo')
+DEFAULT_PROFILER_CLASS = profilers.default.DefaultProfiler
+
+
+class Auditor(object):
     """
-    An ABC class to enforce a common plugin interface
+    Auditor class
+    
+    @ivar custom_plugin_path: The path to any custom plugins
+    @type custom_plugin_path: C{str}
+    @ivar profile: A dictionary of properties for this host
+    @type profile: C{dict}
+    @ivar architecture: The name of the architecture as is normally returned by platform.architecture()[0]
+    @type architecture: C{str}
+    @ivar plugins: A list of successfully loaded plugins
+    @type plugins: C{list}
     """
-    __metaclass__ = abc.ABCMeta
+    plugin_paths = [PACKAGE_PLUGIN_PATH]
+    profile = None
+    plugins = {}
 
-    __profile = None
-    __results = None
-    _running_audit = None
+    def __init__(self, plugin_paths=None, **kwargs):
+        """
+        Initialize System object
+        
+        @param plugin_paths: A path (or list of paths) to a custom set of plugins
+        @type plugin_paths: C{str | list}
+        @keyword profiler_class: The name of a class that extends L{ProfilerBase} or the name of the module where the
+            L{ProfilerBase} class can be found. If supplying a module, must supply the profiler_class keyword arg
+        @type profiler_class: C{class | str}
+        @keyword enable_default_plugins: A flag to use (or suppress) the builtin plugins
+        @type enable_default_plugins: C{bool}
+        @keyword profiler_package: The name of the package that contains a class that extends L{ProfilerBase}
+        @type profiler_package: C{str} 
+        """
+        profiler_class = kwargs.get('profiler_class', DEFAULT_PROFILER_CLASS)
+        profiler_package = kwargs.get('profiler_package', None)
+        enable_default_plugins = kwargs.get('enable_default_plugins', True)
 
 
-    def __init__(self, profile, running_audit_results, *args, **kwargs):
+        if type(profiler_class) is str:
+            profiler_package = kwargs.get('profiler_package', '')
+            if profiler_package:
+                profiler_class = self.__load_module(profiler_package, profiler_class)
+            else:
+                profiler_class = self.__load_module(profiler_class)
+
+        if issubclass(profiler_class, profilers.base.ProfilerBase):
+            profiler = profiler_class()
+            if hasattr(profiler, 'profile'):
+                self.profile = profiler.profile()
+                if type(self.profile) is dict and 'pyhai_version' not in self.profile:
+                    self.profile['pyhai_version'] = VERSION
+                self.system_class = profiler.system_class()
+                self.system = profiler.system()
+                _logger.debug('Successfully loaded the profiler: %s', profiler.__class__.__name__)
+            else:
+                raise Exception('Failed to load a valid profiler: %s' % profiler.__class__.__name__)
+        else:
+            raise Exception('Arguments supplied for profiler are not valid')
+
+        if plugin_paths:
+            if type(plugin_paths) is str:
+                plugin_paths = [plugin_paths]
+
+            if enable_default_plugins:
+                for path in plugin_paths:
+                    if path not in self.plugin_paths:
+                        self.plugin_paths.append(path)
+            else:
+                self.plugin_paths = plugin_paths
+        elif not plugin_paths and not enable_default_plugins:
+            # TODO: Is there a better way to do this? Would like to stop execution and allow for exception information to
+            #    be sent to the logger.
+            try:
+                raise ValueError('Incompatible init params... plugin_paths is empty and enable_default_plugins=False')
+            except:
+                _logger.exception('Must provide a list for plugin_paths or set enable_default_plugins=True. Nothing to do.')
+                raise
+
+        for path in self.plugin_paths:
+            sys.path.insert(0, path)
+        _logger.debug('Setting plugin_paths to: ["%s"]', '", "'.join(self.plugin_paths))
+        self.__load_plugins(self.system_class, self.system)
+
+
+    def __load_profiler(self, profiler, package=''):
         """
-        You probably shouldn't overwrite this method unless you know what you're doing and
-        even then you should be careful and call Plugin.__init__.py at some point.
-        I{Swim at your own risk}
+        Loads a profiler plugin
         
-        @param profile: A dictionary containing this host's profile
-        @type profile: C{dict}
-        @param running_audit_results: A dictionary of the results of all the plugins that have run up to "now"
-        @type running_audit_results: C{dict}
-        @return: A dictionary of results from the plugin's run
+        @param profiler: The name of a class that extends L{ProfilerBase}
+        @type profiler: C{str}
+        @param package: The name of the package where the profiler exists
+        @type package: C{str}
+        """
+        return self.__load_module(profiler, package)
+
+
+    def __load_plugins(self, system_class, system, plugin_module=None):
+        """
+        Imports plugin modules and stores the list of successfully loaded plugins
+        
+        @param plugin_module: A specific plugin_module to load
+        @type plugin_module: C{str}
+        """
+        _logger.info('Loading plugins...')
+        if plugin_module:
+            raise NotImplementedError('Planned for future release')
+        else:
+            plugin_map = self.__resolve_plugin_paths(system_class, system)
+            for plugin, (path, namespace) in plugin_map.items():
+                _logger.debug('Loading plugin: %s, path: %s, package: %s', plugin, path, namespace)
+                if path not in sys.path:
+                    sys.path.insert(0, path)
+                try:
+                    plugin_class = '%s%s' % (utils._underscore_to_camel_case(plugin), 'Plugin')
+                    self.plugins[plugin] = self.__load_module(namespace, plugin_class)
+                    _logger.debug('Loaded plugin: %s [%s::%s]', plugin, namespace, plugin_class)
+                except:
+                    _logger.exception('Failed to load plugin: %s [%s::%s]', plugin, namespace, plugin_class)
+
+
+    def __load_module(self, module, cls=''):
+        """
+        Loads a module and class dynamically return a reference to the class
+        
+        @param module: The name of module to load
+        @type module: C{str}
+        @param cls: The name of a class to load
+        @type cls: C{str}
+        @return: A reference to the loaded class
+        @rtype: C{class}
+        """
+        try:
+            module_instance = __import__(module, globals(), locals(), [cls])
+            if cls and hasattr(module_instance, cls):
+                _logger.debug('Successfully loaded module: %s, class: %s', module, cls)
+                return getattr(module_instance, cls)
+        except:
+            _logger.exception('Failed to import module: %s, class: %s', module, cls)
+            raise
+
+
+    def __resolve_plugin_paths(self, system_class, system, **kwargs):
+        """
+        Checks plugin paths for validity and returns only those that are valid
+
+        @param system: The type of system
+        @type system: C{str}
+        @keyword plugin_paths: A path (or list of paths) to a custom set of plugins
+        @type plugin_paths: C{str}|C{list}
+        @return: A list of valid plugin paths
+        @rtype: C{list}
+        """
+        plugins = {}
+        plugin_paths = kwargs.get('plugin_paths', self.plugin_paths)
+        for plugin_path in plugin_paths:
+            _logger.debug('Searching plugin path: %s', plugin_path)
+            system_class_path = os.path.join(plugin_path, system_class)
+            system_path = os.path.join(system_class_path, system)
+
+            valid_plugins = self.__validate_plugins(plugin_path)
+            valid_plugins = self.__validate_plugins(system_class_path, system_class, valid_plugins)
+            valid_plugins = self.__validate_plugins(system_path, '%s.%s' % (system_class, system), valid_plugins)
+
+            if valid_plugins is not None and len(valid_plugins) > 0:
+                _logger.debug('Merging plugins dictionaries')
+                plugins = dict(plugins.items() + valid_plugins.items())
+
+        return plugins
+
+
+    def __validate_plugins(self, path, base=None, plugins=None):
+        """
+        Performs an initial sanity check on all the plugins found in a path
+        
+        @param path: The path to look for plugins
+        @type path: C{str}
+        @param base: The base of the package name if path is a subfolder of a python package
+            - I{To assist with the import, i.e. from package.module import plugin}
+        @type base: C{str}
+        """
+        if plugins is None:
+            _logger.debug('Creating plugins dict')
+            plugins = {}
+
+        if os.path.exists(path) and os.path.isdir(path):
+            for plugin_entry in os.listdir(path):
+                _logger.debug('Validating file as plugin: %s', plugin_entry)
+                if plugin_entry in PLUGIN_LOADER_EXCLUSIONS or os.path.isdir(plugin_entry) or not plugin_entry.endswith('.py') or plugin_entry.startswith('_'):
+                    continue
+
+                plugin = plugin_entry[:-3]
+                package = plugin
+
+                if base is not None:
+                    package = '%s.%s' % (base, plugin)
+                    _logger.debug('package: %s', package)
+
+                _logger.debug('File appears to be a valid plugin: %s, package: %s [%s]', plugin, package, os.path.join(path, plugin_entry))
+
+                plugins[plugin] = (path, package)
+
+        return plugins
+
+
+    def audit(self, convert_date_to_iso=True):
+        """
+        Profiles the system using the default plugins and all custom plugins, returning a dictionary of the results
+        
+        @param convert_date_to_iso: Converts the 'audit_completed' date to iso format before returning
+        @type convert_date_to_iso: C{bool}
+        @return: A dictionary representing the current state of the system
         @rtype: C{dict}
         """
-        self.__profile = profile
-        self._running_audit = running_audit_results
-        try:
-            before_results = self.before(*args, **kwargs)
-            self.__set_results(self.run(*args, before_results=before_results, **kwargs))
-            self.__set_results(self.after(*args, **kwargs))
-        except Exception as exc:
-            self.fail(exc)
+        start = time.time()
+        if len(self.plugins) <= 0:
+            # TODO: Same deal as TODO in class __init__...
+            try:
+                raise ValueError('No plugins found')
+            except:
+                _logger.exception('List of plugins is empty. Nothing to do.')
+                raise
 
-    @abc.abstractmethod
-    def run(self, *args, **kwargs):
-        """
-        Will be called after the before hook.
-        This is the only "required" method for plugins
-        """
-        pass
+        results = {'profile': self.profile}
+        for plugin_name, plugin_class in self.plugins.items():
+            _logger.debug('Running plugin: %s [%s]', plugin_name, plugin_class.__name__)
+            plugin = plugin_class(self.profile, results)
+            results[plugin_name] = plugin._get_results()
+        end = time.time()
+        now = datetime.datetime.now()
+        if convert_date_to_iso:
+            results['profile']['audit_completed'] = now.isoformat()
+        else:
+            results['profile']['audit_completed'] = now
+        results['profile']['audit_took_sec'] = end - start
+        return results
 
-    def before(self, *args, **kwargs):
-        """
-        Overwrite in subclass as necessary
-        Will be called first during init
-        """
-        _logger.debug('Plugin hook "before" is not overwritten')
-        return None
 
-    def after(self, *args, **kwargs):
-        """
-        Overwrite in subclass as necessary
-        Will be called first during init
-        """
-        _logger.debug('Plugin hook "after" is not overwritten')
-        return self._get_results()
 
-    def fail(self, exc, msg=None, *args):
-        """
-        Overwrite in subclass as necessary
-        Will be called for any exceptions raised for before, run, or after methods
-        """
-        _logger.debug('Current state of results in %s: %s',)
-        _logger.exception(msg, *args)
+def audit(plugin_paths=DEFAULT_CUSTOM_PLUGIN_PATH, **kwargs):
+    """
+    Instatiates a System object and executes it's profile method
+    
+    @param plugin_paths: A path (or list of paths) to a custom set of plugins
+    @type plugin_paths: C{str}|C{list}
+    @keyword debug: Set the logging level to DEBUG
+    @type debug: C{bool}
+    """
+    debug = kwargs.pop('debug', False)
 
-    def get_profile(self, key=None):
-        """
-        Gets the entire profile dictionary, a list of items or a single key from the profile dictionary
-        
-        @param key: Providing a string returns a single value from the profile dictionary,
-            providing an array, returns a slice of the profile dictionary, omitting this param
-            returns the entire profile dictionary
-        @type key: C{list | str}
-        @return: Mixed... part or all of the profile dictionary
-        @rtype: C{dict | str}
-        """
-        if key is not None:
-            if type(key) is list:
-                return dict([(k, self.__profile[k]) for k in key if k in self.__profile])
-            elif type(key) is str and key in self.__profile:
-                return self.__profile[key]
-            else:
-                return None
-        else:
-            return self.__profile
+    if debug:
+        _logger.setLevel(logging.DEBUG)
 
-    def __set_results(self, results):
-        """
-        Ensures that only dict types are stored in the __results instance var
-        
-        @param results: The results from the plugin_hooks or the run
-            B{**MUST} be a dict or will raise an exception 
-        @type results: C{dict}
-        """
-        result_type = type(results)
-        if result_type is dict or result_type is tuple or result_type is list:
-            self.__results = results
-
-    def _get_results(self):
-        """
-        Returns results
-        
-        @return: Results of the run
-        @rtype: C{dict}
-        """
-        return self.__results
+    auditor = Auditor(plugin_paths, **kwargs)
+    return auditor.audit()

File src/pyhai/plugins/__init__.py

View file
+"""
+@copyright: 2011 Mark LaPerriere
+
+@license:
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    U{http://www.apache.org/licenses/LICENSE-2.0}
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+@summary:
+    pyHai auditor plugin base class
+
+@author: Mark LaPerriere
+@contact: pyhai@mindmind.com
+@organization: Mind Squared Design / www.mindmind.com
+@version: 0.1.0
+@date: Sep 11, 2011
+"""
+import abc
+
+import logging
+# set some default logging behavior
+_logger = logging.getLogger(__name__)
+_logger.addHandler(logging.NullHandler())
+
+
+class AuditorPlugin(object):
+    """
+    An ABC class to enforce a common plugin interface
+    """
+    __metaclass__ = abc.ABCMeta
+
+    __profile = None
+    __results = None
+    _running_audit = None
+
+
+    def __init__(self, profile, running_audit_results, *args, **kwargs):
+        """
+        You probably shouldn't overwrite this method unless you know what you're doing and
+        even then you should be careful and call Plugin.__init__.py at some point.
+        I{Swim at your own risk}
+        
+        @param profile: A dictionary containing this host's profile
+        @type profile: C{dict}
+        @param running_audit_results: A dictionary of the results of all the plugins that have run up to "now"
+        @type running_audit_results: C{dict}
+        @return: A dictionary of results from the plugin's run
+        @rtype: C{dict}
+        """
+        self.__profile = profile
+        self._running_audit = running_audit_results
+        try:
+            before_results = self.before(*args, **kwargs)
+            self.__set_results(self.run(*args, before_results=before_results, **kwargs))
+            self.__set_results(self.after(*args, **kwargs))
+        except Exception as exc:
+            self.fail(exc)
+
+    @abc.abstractmethod
+    def run(self, *args, **kwargs):
+        """
+        Will be called after the before hook.
+        This is the only "required" method for plugins
+        """
+        pass
+
+    def before(self, *args, **kwargs):
+        """
+        Overwrite in subclass as necessary
+        Will be called first during init
+        """
+        _logger.debug('Plugin hook "before" is not overwritten')
+        return None
+
+    def after(self, *args, **kwargs):
+        """
+        Overwrite in subclass as necessary
+        Will be called first during init
+        """
+        _logger.debug('Plugin hook "after" is not overwritten')
+        return self._get_results()
+
+    def fail(self, exc, msg=None, *args):
+        """
+        Overwrite in subclass as necessary
+        Will be called for any exceptions raised for before, run, or after methods
+        """
+        _logger.debug('Current state of results in %s: %s',)
+        _logger.exception(msg, *args)
+
+    def get_profile(self, key=None):
+        """
+        Gets the entire profile dictionary, a list of items or a single key from the profile dictionary
+        
+        @param key: Providing a string returns a single value from the profile dictionary,
+            providing an array, returns a slice of the profile dictionary, omitting this param
+            returns the entire profile dictionary
+        @type key: C{list | str}
+        @return: Mixed... part or all of the profile dictionary
+        @rtype: C{dict | str}
+        """
+        if key is not None:
+            if type(key) is list:
+                return dict([(k, self.__profile[k]) for k in key if k in self.__profile])
+            elif type(key) is str and key in self.__profile:
+                return self.__profile[key]
+            else:
+                return None
+        else:
+            return self.__profile
+
+    def __set_results(self, results):
+        """
+        Ensures that only dict types are stored in the __results instance var
+        
+        @param results: The results from the plugin_hooks or the run
+            B{**MUST} be a dict or will raise an exception 
+        @type results: C{dict}
+        """
+        result_type = type(results)
+        if result_type is dict or result_type is tuple or result_type is list:
+            self.__results = results
+
+    def _get_results(self):
+        """
+        Returns results
+        
+        @return: Results of the run
+        @rtype: C{dict}
+        """
+        return self.__results

File src/pyhai/plugins/environment.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import os
 import logging
 

File src/pyhai/plugins/hostname.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import socket
 import logging
 

File src/pyhai/plugins/linux/__init__.py

View file
 @organization: Mind Squared Design / www.mindmind.com
 """
 import abc
-from subprocess import Popen, PIPE
+import subprocess.Popen as Popen
+import subprocess.PIPE as PIPE
 import shlex
 import logging
 

File src/pyhai/plugins/linux/centos/software.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 from .. import PackageManagerRpm
 import logging
 

File src/pyhai/plugins/linux/disk.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 from subprocess import Popen, PIPE
 import shlex
 import logging

File src/pyhai/plugins/linux/memory.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import logging
 
 # set some default logging behavior

File src/pyhai/plugins/linux/network.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 from subprocess import Popen, PIPE
 import os
 import shlex

File src/pyhai/plugins/linux/processor.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import logging
 
 # set some default logging behavior

File src/pyhai/plugins/linux/system.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import platform
 try:
-    from platform import linux_distribution as distribution
-except: from platform import dist as distribution
+    import platform.linux_distribution as distribution
+except: import platform.dist as distribution
 import logging
 
 # set some default logging behavior

File src/pyhai/plugins/linux/ubuntu/software.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 from .. import PackageManagerDpkg
 import logging
 

File src/pyhai/plugins/python.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import platform
 import logging
 

File src/pyhai/plugins/windows/disk.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import logging
 
 win32api = None

File src/pyhai/plugins/windows/memory.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import logging
 
 win32api = None

File src/pyhai/plugins/windows/network.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import logging
 
 # set some default logging behavior

File src/pyhai/plugins/windows/processor.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import sys
 import logging
 

File src/pyhai/plugins/windows/software.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import logging
 
 win32com = None

File src/pyhai/plugins/windows/system.py

View file
 @version: 0.1.0
 @date: Sep 11, 2011
 """
-from pyhai import AuditorPlugin
+from pyhai.plugins import AuditorPlugin
 import platform
 import logging
 

File src/pyhai/profilers/default.py

View file
 """
 import platform
 import socket
-from .base import ProfilerBase
+import base
 
-class DefaultProfiler(ProfilerBase):
+class DefaultProfiler(base.ProfilerBase):
     """
     The default profiler plugin
     """

File src/pyhai/pyhai.py

-"""
-@copyright: 2011 Mark LaPerriere
-
-@license:
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    U{http://www.apache.org/licenses/LICENSE-2.0}
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-@summary:
-    A system profiler/auditor inspired by Opscode's Ohai
-
-@author: Mark LaPerriere
-@contact: pyhai@mindmind.com
-@organization: Mind Squared Design / www.mindmind.com
-@version: 0.1.0
-@date: Sep 11, 2011
-"""
-import os
-import sys
-import datetime
-import time
-import logging
-from .utils import _underscore_to_camel_case
-from .profilers.base import ProfilerBase
-from .profilers.default import DefaultProfiler
-
-# set some default logging behavior
-_logger = logging.getLogger(__name__)
-_logger.addHandler(logging.NullHandler())
-
-# current version
-__VERSION__ = (0, 1, 2)
-VERSION = '.'.join(map(str, __VERSION__))
-
-# set some default variables
-PACKAGE_PLUGIN_PATH = os.path.join('pyhai', os.path.dirname(os.path.realpath(__file__)), 'plugins')
-DEFAULT_CUSTOM_PLUGIN_PATH = os.path.join(os.path.dirname(os.path.realpath('.')), 'plugins')
-PLUGIN_LOADER_EXCLUSIONS = ('.', '..', '__init__.py', '__init__.pyc', '__init__.pyo')
-DEFAULT_PROFILER_CLASS = DefaultProfiler
-
-
-class Auditor(object):
-    """
-    Auditor class
-    
-    @ivar custom_plugin_path: The path to any custom plugins
-    @type custom_plugin_path: C{str}
-    @ivar profile: A dictionary of properties for this host
-    @type profile: C{dict}
-    @ivar architecture: The name of the architecture as is normally returned by platform.architecture()[0]
-    @type architecture: C{str}
-    @ivar plugins: A list of successfully loaded plugins
-    @type plugins: C{list}
-    """
-    plugin_paths = [PACKAGE_PLUGIN_PATH]
-    profile = None
-    plugins = {}
-
-    def __init__(self, plugin_paths=None, **kwargs):
-        """
-        Initialize System object
-        
-        @param plugin_paths: A path (or list of paths) to a custom set of plugins
-        @type plugin_paths: C{str | list}
-        @keyword profiler_class: The name of a class that extends L{ProfilerBase} or the name of the module where the
-            L{ProfilerBase} class can be found. If supplying a module, must supply the profiler_class keyword arg
-        @type profiler_class: C{class | str}
-        @keyword enable_default_plugins: A flag to use (or suppress) the builtin plugins
-        @type enable_default_plugins: C{bool}
-        @keyword profiler_package: The name of the package that contains a class that extends L{ProfilerBase}
-        @type profiler_package: C{str} 
-        """
-        profiler_class = kwargs.get('profiler_class', DEFAULT_PROFILER_CLASS)
-        profiler_package = kwargs.get('profiler_package', None)
-        enable_default_plugins = kwargs.get('enable_default_plugins', True)
-
-
-        if type(profiler_class) is str:
-            profiler_package = kwargs.get('profiler_package', '')
-            if profiler_package:
-                profiler_class = self.__load_module(profiler_package, profiler_class)
-            else:
-                profiler_class = self.__load_module(profiler_class)
-
-        if issubclass(profiler_class, ProfilerBase):
-            profiler = profiler_class()
-            if hasattr(profiler, 'profile'):
-                self.profile = profiler.profile()
-                if type(self.profile) is dict and 'pyhai_version' not in self.profile:
-                    self.profile['pyhai_version'] = VERSION
-                self.system_class = profiler.system_class()
-                self.system = profiler.system()
-                _logger.debug('Successfully loaded the profiler: %s', profiler.__class__.__name__)
-            else:
-                raise Exception('Failed to load a valid profiler: %s' % profiler.__class__.__name__)
-        else:
-            raise Exception('Arguments supplied for profiler are not valid')
-
-        if plugin_paths:
-            if type(plugin_paths) is str:
-                plugin_paths = [plugin_paths]
-
-            if enable_default_plugins:
-                for path in plugin_paths:
-                    if path not in self.plugin_paths:
-                        self.plugin_paths.append(path)
-            else:
-                self.plugin_paths = plugin_paths
-        elif not plugin_paths and not enable_default_plugins:
-            # TODO: Is there a better way to do this? Would like to stop execution and allow for exception information to
-            #    be sent to the logger.
-            try:
-                raise ValueError('Incompatible init params... plugin_paths is empty and enable_default_plugins=False')
-            except:
-                _logger.exception('Must provide a list for plugin_paths or set enable_default_plugins=True. Nothing to do.')
-                raise
-
-        for path in self.plugin_paths:
-            sys.path.insert(0, path)
-        _logger.debug('Setting plugin_paths to: ["%s"]', '", "'.join(self.plugin_paths))
-        self.__load_plugins(self.system_class, self.system)
-
-
-    def __load_profiler(self, profiler, package=''):
-        """
-        Loads a profiler plugin
-        
-        @param profiler: The name of a class that extends L{ProfilerBase}
-        @type profiler: C{str}
-        @param package: The name of the package where the profiler exists
-        @type package: C{str}
-        """
-        return self.__load_module(profiler, package)
-
-
-    def __load_plugins(self, system_class, system, plugin_module=None):
-        """
-        Imports plugin modules and stores the list of successfully loaded plugins
-        
-        @param plugin_module: A specific plugin_module to load
-        @type plugin_module: C{str}
-        """
-        _logger.info('Loading plugins...')
-        if plugin_module:
-            raise NotImplementedError('Planned for future release')
-        else:
-            plugin_map = self.__resolve_plugin_paths(system_class, system)
-            for plugin, (path, namespace) in plugin_map.items():
-                _logger.debug('Loading plugin: %s, path: %s, package: %s', plugin, path, namespace)
-                if path not in sys.path:
-                    sys.path.insert(0, path)
-                try:
-                    plugin_class = '%s%s' % (_underscore_to_camel_case(plugin), 'Plugin')
-                    self.plugins[plugin] = self.__load_module(namespace, plugin_class)
-                    _logger.debug('Loaded plugin: %s [%s::%s]', plugin, namespace, plugin_class)
-                except:
-                    _logger.exception('Failed to load plugin: %s [%s::%s]', plugin, namespace, plugin_class)
-
-
-    def __load_module(self, module, cls=''):
-        """
-        Loads a module and class dynamically return a reference to the class
-        
-        @param module: The name of module to load
-        @type module: C{str}
-        @param cls: The name of a class to load
-        @type cls: C{str}
-        @return: A reference to the loaded class
-        @rtype: C{class}
-        """
-        try:
-            module_instance = __import__(module, globals(), locals(), [cls])
-            if cls and hasattr(module_instance, cls):
-                _logger.debug('Successfully loaded module: %s, class: %s', module, cls)
-                return getattr(module_instance, cls)
-        except:
-            _logger.exception('Failed to import module: %s, class: %s', module, cls)
-            raise
-
-
-    def __resolve_plugin_paths(self, system_class, system, **kwargs):
-        """
-        Checks plugin paths for validity and returns only those that are valid
-
-        @param system: The type of system
-        @type system: C{str}
-        @keyword plugin_paths: A path (or list of paths) to a custom set of plugins
-        @type plugin_paths: C{str}|C{list}
-        @return: A list of valid plugin paths
-        @rtype: C{list}
-        """
-        plugins = {}
-        plugin_paths = kwargs.get('plugin_paths', self.plugin_paths)
-        for plugin_path in plugin_paths:
-            _logger.debug('Searching plugin path: %s', plugin_path)
-            system_class_path = os.path.join(plugin_path, system_class)
-            system_path = os.path.join(system_class_path, system)
-
-            valid_plugins = self.__validate_plugins(plugin_path)
-            valid_plugins = self.__validate_plugins(system_class_path, system_class, valid_plugins)
-            valid_plugins = self.__validate_plugins(system_path, '%s.%s' % (system_class, system), valid_plugins)
-
-            if valid_plugins is not None and len(valid_plugins) > 0:
-                _logger.debug('Merging plugins dictionaries')
-                plugins = dict(plugins.items() + valid_plugins.items())
-
-        return plugins
-
-
-    def __validate_plugins(self, path, base=None, plugins=None):
-        """
-        Performs an initial sanity check on all the plugins found in a path
-        
-        @param path: The path to look for plugins
-        @type path: C{str}
-        @param base: The base of the package name if path is a subfolder of a python package
-            - I{To assist with the import, i.e. from package.module import plugin}
-        @type base: C{str}
-        """
-        if plugins is None:
-            _logger.debug('Creating plugins dict')
-            plugins = {}
-
-        if os.path.exists(path) and os.path.isdir(path):
-            for plugin_entry in os.listdir(path):
-                _logger.debug('Validating file as plugin: %s', plugin_entry)
-                if plugin_entry in PLUGIN_LOADER_EXCLUSIONS or os.path.isdir(plugin_entry) or not plugin_entry.endswith('.py') or plugin_entry.startswith('_'):
-                    continue
-
-                plugin = plugin_entry[:-3]
-                package = plugin
-
-                if base is not None:
-                    package = '%s.%s' % (base, plugin)
-                    _logger.debug('package: %s', package)
-
-                _logger.debug('File appears to be a valid plugin: %s, package: %s [%s]', plugin, package, os.path.join(path, plugin_entry))
-
-                plugins[plugin] = (path, package)
-
-        return plugins
-
-
-    def audit(self, convert_date_to_iso=True):
-        """
-        Profiles the system using the default plugins and all custom plugins, returning a dictionary of the results
-        
-        @param convert_date_to_iso: Converts the 'audit_completed' date to iso format before returning
-        @type convert_date_to_iso: C{bool}
-        @return: A dictionary representing the current state of the system
-        @rtype: C{dict}
-        """
-        start = time.time()
-        if len(self.plugins) <= 0:
-            # TODO: Same deal as TODO in class __init__...
-            try:
-                raise ValueError('No plugins found')
-            except:
-                _logger.exception('List of plugins is empty. Nothing to do.')
-                raise
-
-        results = {'profile': self.profile}
-        for plugin_name, plugin_class in self.plugins.items():
-            _logger.debug('Running plugin: %s [%s]', plugin_name, plugin_class.__name__)
-            plugin = plugin_class(self.profile, results)
-            results[plugin_name] = plugin._get_results()
-        end = time.time()
-        now = datetime.datetime.now()
-        if convert_date_to_iso:
-            results['profile']['audit_completed'] = now.isoformat()
-        else:
-            results['profile']['audit_completed'] = now
-        results['profile']['audit_took_sec'] = end - start
-        return results
-
-
-
-def audit(plugin_paths=DEFAULT_CUSTOM_PLUGIN_PATH, **kwargs):
-    """
-    Instatiates a System object and executes it's profile method
-    
-    @param plugin_paths: A path (or list of paths) to a custom set of plugins
-    @type plugin_paths: C{str}|C{list}
-    @keyword debug: Set the logging level to DEBUG
-    @type debug: C{bool}
-    """
-    debug = kwargs.pop('debug', False)
-
-    if debug:
-        _logger.setLevel(logging.DEBUG)
-
-    auditor = Auditor(plugin_paths, **kwargs)
-    return auditor.audit()

File src/pyhai/utils.py

View file
 @date: Sep 11, 2011
 """
 try:
-    from cStringIO import StringIO
+    import cStringIO as StringIO
 except:
-    from StringIO import StringIO
+    import StringIO
 
 def _camel_case_to_underscore(name):
     """
     if len(name) <= 1:
         return name.lower()
 
-    result = StringIO()
+    result = StringIO.StringIO()
     name_length = len(name)
     result.write(name[0].lower())
     for c in range(1, name_length):

File src/setup.py

View file
 See the License for the specific language governing permissions and
 limitations under the License.
 """
-_version = '0.1.2'
-from distutils.core import setup
+from setuptools import setup, find_packages
+from pyhai import VERSION
 
 setup(
     name='pyhai',
     license='http://www.apache.org/licenses/LICENSE-2.0',
-    version=_version,
-    packages=[
-        'pyhai',
-        'pyhai.plugins',
-        'pyhai.plugins.linux',
-        'pyhai.plugins.linux.ubuntu',
-        'pyhai.plugins.linux.centos',
-        'pyhai.plugins.windows',
-        'pyhai.profilers',
-        ],
+    version=VERSION,
+    packages=find_packages(),
     description='A system profiler/auditor written in Python that supports custom plugins.',
     long_description='A system profiler/auditor written in Python that supports custom plugins and a custom profiler. Custom plugins can superscede builtin plugins to allow for a great deal of flexibility. Plugins follow naming conventions for ease of use.',
     url='https://bitbucket.org/marklap/pyhai',
-    download_url='https://bitbucket.org/marklap/pyhai/src/tip/src/dist/pyhai-%s.tar.gz' % _version,
+    download_url='https://bitbucket.org/marklap/pyhai/src/tip/src/dist/pyhai-{0}.tar.gz'.format(VERSION),
     author='pyhai@mindmind.com',
     author_email='pyhai@mindmind.com',
     maintainer='pyhai@mindmind.com',