summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Andres Granados <jgranado@redhat.com>2008-01-02 14:32:07 +0100
committerJoel Andres Granados <jgranado@redhat.com>2008-01-02 14:32:07 +0100
commit26da06a02b8cbeea5aea9eccc2de55d33ade23bf (patch)
tree7bb10032a86f8015dcee987697c480ef24d32872
parent403519b478ffbe5b433b1fd2fb7babe12c693af2 (diff)
downloadfirstaidkit-26da06a02b8cbeea5aea9eccc2de55d33ade23bf.tar.gz
firstaidkit-26da06a02b8cbeea5aea9eccc2de55d33ade23bf.tar.xz
firstaidkit-26da06a02b8cbeea5aea9eccc2de55d33ade23bf.zip
Move from tasker to pyfirstaidkit to try to follow the standard in site-packages.
-rw-r--r--pyfirstaidkit/.placeholder0
-rw-r--r--pyfirstaidkit/FirstAidKit.py17
-rw-r--r--pyfirstaidkit/__init__.py21
-rw-r--r--pyfirstaidkit/configuration.py102
-rw-r--r--pyfirstaidkit/errors.py29
-rw-r--r--pyfirstaidkit/interpret.py84
-rw-r--r--pyfirstaidkit/log.py25
-rw-r--r--pyfirstaidkit/plugins.py352
-rw-r--r--pyfirstaidkit/reporting.py96
-rw-r--r--pyfirstaidkit/returns.py42
-rw-r--r--pyfirstaidkit/utils.py38
11 files changed, 806 insertions, 0 deletions
diff --git a/pyfirstaidkit/.placeholder b/pyfirstaidkit/.placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pyfirstaidkit/.placeholder
diff --git a/pyfirstaidkit/FirstAidKit.py b/pyfirstaidkit/FirstAidKit.py
new file mode 100644
index 0000000..44d6775
--- /dev/null
+++ b/pyfirstaidkit/FirstAidKit.py
@@ -0,0 +1,17 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
diff --git a/pyfirstaidkit/__init__.py b/pyfirstaidkit/__init__.py
new file mode 100644
index 0000000..6a31164
--- /dev/null
+++ b/pyfirstaidkit/__init__.py
@@ -0,0 +1,21 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+from interpret import Tasker
+from configuration import Config
+from log import Logger
+
diff --git a/pyfirstaidkit/configuration.py b/pyfirstaidkit/configuration.py
new file mode 100644
index 0000000..70a626e
--- /dev/null
+++ b/pyfirstaidkit/configuration.py
@@ -0,0 +1,102 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+import ConfigParser
+import os
+from cStringIO import StringIO
+from shlex import shlex
+
+if os.environ.has_key("FIRST_AID_KIT_CONF"):
+ cfgfile = os.environ["FIRST_AID_KIT_CONF"].split(":")
+else:
+ cfgfile = ["/etc/firstaidkit.conf", os.environ["HOME"]+"/.firstaidkit.conf"]
+
+defaultconfig = """
+[system]
+root = /mnt/sysimage
+
+[plugin]
+path = /usr/lib/FirstAidKit/plugins
+disabled =
+
+[operation]
+mode = auto
+help = False
+verbose = False
+gui = console
+
+[log]
+method = stdout
+"""
+
+class LockedError(Exception):
+ pass
+
+class FAKConfigSection(object):
+ """Proxy object for one configuration section"""
+
+ def __init__(self, cfg, name):
+ self.__dict__["section_name"] = name
+ self.__dict__["configuration"] = cfg
+
+ def __getattr__(self, key):
+ if not self.__dict__["configuration"].has_section(self.__dict__["section_name"]):
+ raise ConfigParser.NoSectionError(self.__dict__["section_name"])
+
+ if not self.__dict__["configuration"].has_option(self.__dict__["section_name"], key):
+ raise ConfigParser.NoOptionError(key)
+
+ return self.__dict__["configuration"].get(self.__dict__["section_name"], key)
+
+ def __setattr__(self, key, value):
+ if self.__dict__["configuration"].__dict__.has_key("_lock") and self.__dict__["configuration"].__dict__["_lock"]:
+ raise LockedError(key)
+
+ if not self.__dict__["configuration"].has_section(self.__dict__["section_name"]):
+ self.__dict__["configuration"].add_section(self.__dict__["section_name"])
+ self.__dict__["configuration"].set(self.__dict__["section_name"], key, value)
+
+ def _list(self, key):
+ l = []
+ lex = shlex(instream = StringIO(getattr(self, key)), posix = True)
+ token = lex.get_token()
+ while token!=lex.eof:
+ l.append(token)
+ token = lex.get_token()
+ return l
+
+
+class FAKConfigMixIn(object):
+ """Enhance ConfigParser so we can use it in the python way (config.section.value)"""
+
+ def __getattr__(self, section):
+ return FAKConfigSection(self, section)
+
+ def lock(self):
+ self.__dict__["_lock"] = True
+
+ def unlock(self):
+ self.__dict__["_lock"] = False
+
+class FAKConfig(ConfigParser.SafeConfigParser, FAKConfigMixIn):
+ pass
+
+Config = FAKConfig()
+Config.readfp(StringIO(defaultconfig), "<default>")
+Config.read(cfgfile)
+
+
diff --git a/pyfirstaidkit/errors.py b/pyfirstaidkit/errors.py
new file mode 100644
index 0000000..61a04be
--- /dev/null
+++ b/pyfirstaidkit/errors.py
@@ -0,0 +1,29 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+
+class InvalidFlowStateException(Exception):
+ def __init__(self, flow):
+ self.message="There appears to be an inconsistency with the %s varialbe. " % flow
+ def __str__(self):
+ return self.message
+
+class InvalidFlowNameException(Exception):
+ def __init__(self, name, flow):
+ self.message="There are no flows by the name of %s" % name
+ def __str__(self):
+ return self.message
diff --git a/pyfirstaidkit/interpret.py b/pyfirstaidkit/interpret.py
new file mode 100644
index 0000000..da5671a
--- /dev/null
+++ b/pyfirstaidkit/interpret.py
@@ -0,0 +1,84 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+from log import Logger
+from plugins import PluginSystem
+from reporting import Reports, TASKER
+import logging
+import copy
+
+class RunDependencies(object):
+ """Encapsulate flags used to control the dependencies between plugins"""
+ def __init__(self):
+ self._provide = set()
+
+ def provide(self, id):
+ """Add flag"""
+ Logger.info("Setting dependency flag %s", id)
+ self._provide.add(id)
+
+ def require(self, id):
+ """Return True if flag is present, otherwise false"""
+ return id in self._provide
+
+class Tasker:
+ """The main interpret of tasks described in Config object"""
+
+ def __init__(self, cfg):
+ self._provide = RunDependencies()
+ self._config = cfg
+ self._reporting = Reports()
+ self.pluginSystem = PluginSystem(reporting = self._reporting, dependencies = self._provide)
+
+ def reporting(self):
+ return self._reporting
+
+ def pluginsystem(self):
+ return self.pluginSystem
+
+ def end(self):
+ """Signalize end of operations to all necessary places"""
+ self._reporting.end()
+
+ def run(self):
+ pluginSystem = self.pluginSystem
+
+ if self._config.operation.mode == "auto":
+ oldlist = set()
+ actlist = set(pluginSystem.list())
+ #iterate through plugins until there is no plugin left or no action performed during whole iteration
+ while len(actlist)>0 and oldlist!=actlist:
+ oldlist = copy.copy(actlist)
+ for plugin in oldlist:
+ if pluginSystem.autorun(plugin): #False when dependencies are not met
+ actlist.remove(plugin)
+ for plugin in actlist:
+ self._reporting.info("Plugin %s was not called because of unsatisfied dependencies" % (plugin,), origin = TASKER, importance = logging.WARNING)
+ elif self._config.operation.mode == "flow":
+ try:
+ pluginSystem.autorun(self._config.operation.plugin, flow = self._config.operation.flow, dependencies = False)
+ except InvalidFlowNameException, e:
+ pass
+ elif self._config.operation.mode == "plugin":
+ pluginSystem.autorun(self._config.operation.plugin, dependencies = False)
+ elif self._config.operation.mode == "task":
+ pass
+ else:
+ Logger.error("Incorrect task specified")
+ return False
+
+ return True
diff --git a/pyfirstaidkit/log.py b/pyfirstaidkit/log.py
new file mode 100644
index 0000000..f1adb8d
--- /dev/null
+++ b/pyfirstaidkit/log.py
@@ -0,0 +1,25 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+import logging
+import sys
+
+Logger = logging.getLogger()
+Logger.setLevel(logging.DEBUG)
+
+Logger.addHandler(logging.StreamHandler(sys.stdout))
+
diff --git a/pyfirstaidkit/plugins.py b/pyfirstaidkit/plugins.py
new file mode 100644
index 0000000..8d892c8
--- /dev/null
+++ b/pyfirstaidkit/plugins.py
@@ -0,0 +1,352 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+from configuration import Config
+from returns import *
+from errors import *
+
+import FirstAidKit
+from log import Logger
+
+import imp
+import os
+import subprocess
+from cStringIO import StringIO
+
+class Flow(dict):
+ def __init__(self, rules, description="", *args, **kwargs):
+ self.description = description
+ dict.__init__(self, rules, *args, **kwargs)
+
+class Plugin(object):
+ #
+ # Some information vars.
+ #
+ name = "Plugin"
+ version = "0.0.0"
+ author = "nobody"
+ #
+ # Dictionary that holds all the flows. The keys for each flow is its
+ # name. The flow will be addressed by this name. The plugin developer
+ # Can add as many flows as he wants. The developer must use the instance.
+ # obj._flows["name"] = SomeFlow. Be aware that you can overwirhte
+ # previously added flows. This class attribute has to be overriden by
+ # each plugin.
+ #
+ flows = {}
+
+ #
+ # The initial and final states are here to give more flexibilty to the
+ # Development process. All flows will start and end with these two
+ # Variables.
+ #
+ initial = 0
+ final = 1
+
+ #
+ # The flow to use with the automated repair mode
+ #
+
+ default_flow = "defflow"
+
+ #
+ # This is the default flow that all classes deriving from plugin must
+ # have. As the initial state has no return value it will be indexed
+ # with the parent of all ReturnValue classes.
+ #
+ _defflows = {}
+ _defflows["defflow"] = Flow({
+ initial : {ReturnValue: "prepare"},
+ "prepare" : {ReturnValueTrue: "diagnose"},
+ "diagnose" : {ReturnValueTrue: "clean", ReturnValueFalse: "backup"},
+ "backup" : {ReturnValueTrue: "fix", ReturnValueFalse: "clean"},
+ "fix" : {ReturnValueTrue: "clean", ReturnValueFalse: "restore"},
+ "restore" : {ReturnValueTrue: "clean", ReturnValueFalse: "clean"},
+ "clean" : {ReturnValueTrue: final}
+ }, description="The default, fully automated, fixing sequence")
+
+ def __init__(self, flow, reporting, dependencies):
+ """ Initialize the instance.
+
+ flow -- Name of the flow to be used with this instance.
+ reporting -- object used to report information to the user
+ dependencies -- object encapsulating the inter-plugin dependency API (require, provide)
+
+ The flow is defined in the __init__ so we don't have to worry about changing it.
+ """
+ self._reporting = reporting
+ self._dependencies = dependencies
+
+ self.provide = dependencies.provide
+ self.require = dependencies.require
+
+ #
+ # state we are in.
+ #
+ self._state = Plugin.initial
+
+ #
+ # Used to hold the return value of the functions in the class.
+ #
+ self._result = None #edge from the state we are in
+
+ #
+ # Choose the flow for the instance.
+ #
+ self.defineFlow(flow)
+
+ def call(self, step):
+ """call one step from plugin"""
+ self._result = None #mark new unfinished step
+ self._state = step
+ return getattr(self, step)()
+
+ @classmethod
+ def info(cls):
+ """Returns tuple (Plugin name, Plugin version, Plugin author)"""
+ return (cls.name, cls.version, cls.author)
+
+ #
+ # The flow functions.
+ #
+ def defineFlow(self, flow):
+ """Defines the current flow to name.
+
+ flow -- Name of the flow
+ This function is to be called from the __init__ only. There will be the flows defined by the
+ Plugin class and the flows defined by the actual plugin. We will first search the Plugin
+ class and then the plugin itself for the name.
+ """
+ #
+ # The flow that will be used for the instance.
+ #
+ if flow in Plugin._defflows.keys():
+ self.cflow = Plugin._defflows[flow]
+ elif flow in self.__class__.flows.keys():
+ self.cflow = self.__class__.flows[flow]
+ else:
+ raise InvalidFlowNameException(flow)
+
+ @classmethod
+ def getFlows(cls):
+ """Return a set with the names of all possible flows."""
+ fatherf = Plugin._defflows.keys()
+ pluginf = cls.flows.keys()
+ return set(fatherf+pluginf)
+
+ @classmethod
+ def getFlow(cls, name):
+ """Return a Flow object associated with provided name"""
+ if cls.flows.has_key(name):
+ return cls.flows[name]
+ else:
+ return Plugin._defflows[name]
+
+ #dependency stuff
+ @classmethod
+ def getDeps(cls):
+ """Return list of conditions required to be set before automated run can be done"""
+ return set()
+
+ #methods available only for instance, see interpreter.py and dependency stuff there
+ #def require(self, id)
+ #def provide(self, id)
+
+ #list of all actions provided
+ def actions(self):
+ """Returns list of available actions"""
+ return set(["prepare", "backup", "diagnose", "describe", "fix", "restore", "clean"])
+
+ def nextstate(self, state=None, result=None):
+ """Returns next state when analizing self._state, self._result and the self.cflow in automode.
+
+ state -- Name of hte function.
+ result -- The return value of the previous function
+ We do not check for validity of the key in the self.cflow. If key is invalid, function will
+ Traceback. When self._state = self.final the function will traceback. This situation must
+ be handled outside this function. If an automatica iteration is needed that avoids the
+ necesity to address the self.final state, use __iter__ and next.
+ """
+ # If any of the vals are missing, we default to the current ones.
+ if state is None or result is None:
+ state=self._state
+ result=self._result
+ # The self.initial state does not have any return code.
+ # It will only work with the ReturnValue.
+ try:
+ if state == self.initial:
+ self._state = self.cflow[self.initial][ReturnValue]
+ else:
+ self._state = self.cflow[state][result]
+ return self._state
+ except KeyError:
+ raise InvalidFlowStateException(self.cflow)
+
+ #
+ #iterate protocol allows us to use loops
+ #
+ def __iter__(self):
+ self._state = self.initial
+ self._result = None
+ return self
+
+ def next(self):
+ """Iteration function.
+
+ Will return (self._state, self._result). The function that was executed and the return value.
+ """
+ func = self.nextstate()
+ if func == self.final:
+ raise StopIteration()
+ else:
+ # Execute the function.
+ getattr(self, func)()
+ return (self._state, self._result)
+
+ #
+ #default (mandatory) plugin actions
+ #
+ def prepare(self):
+ """Initial actions.
+
+ All the actions that must be done before the execution of any plugin function.
+ This function generaly addresses things that are global to the plugin.
+ """
+ #We want these functions to be overridden by the plugin developer.
+ if self.__class__ is Plugin:
+ Logger.warning("Clean is an abstract method, it should be used as such.")
+
+ def clean(self):
+ """Final actions.
+
+ All the actions that must be done after the exection of all plugin functions.
+ This function generaly addresses things that are global and need to be closed
+ off, like file descriptos, or mounted partitions....
+ """
+ #We want these functions to be overridden by the plugin developer.
+ if self.__class__ is Plugin:
+ Logger.warning("Clean is an abstract method, it should be used as such.")
+
+ def backup(self):
+ """Gather important information needed for restore."""
+ #We want these functions to be overridden by the plugin developer.
+ if self.__class__ is Plugin:
+ Logger.warning("Clean is an abstract method, it should be used as such.")
+
+ def restore(self):
+ """Try to restore the previous state described in backup."""
+ #We want these functions to be overridden by the plugin developer.
+ if self.__class__ is Plugin:
+ Logger.warning("Clean is an abstract method, it should be used as such.")
+
+ def diagnose(self):
+ """Diagnose the situation."""
+ #We want these functions to be overridden by the plugin developer.
+ if self.__class__ is Plugin:
+ Logger.warning("Clean is an abstract method, it should be used as such.")
+
+ def fix(self):
+ """Try to fix whatever is wrong in the system."""
+ #We want these functions to be overridden by the plugin developer.
+ if self.__class__ is Plugin:
+ Logger.warning("Clean is an abstract method, it should be used as such.")
+
+class PluginSystem(object):
+ """Encapsulate all plugin detection and import stuff"""
+
+ def __init__(self, reporting, dependencies, config = Config):
+ self._path = Config.plugin.path
+ self._reporting = reporting
+ self._deps = dependencies
+ self._plugins = {}
+
+ #create list of potential modules in the path
+ importlist = set()
+ for f in os.listdir(self._path):
+ fullpath = os.path.join(self._path, f)
+ Logger.debug("Processing file: %s", f)
+ if os.path.isdir(fullpath) and os.path.isfile(os.path.join(self._path, f, "__init__.py")):
+ importlist.add(f)
+ Logger.debug("Adding python module (directory): %s", f)
+ elif os.path.isfile(fullpath) and (f[-3:]==".so" or f[-3:]==".py"):
+ importlist.add(f[:-3])
+ Logger.debug("Adding python module (file): %s", f)
+ elif os.path.isfile(fullpath) and (f[-4:]==".pyc" or f[-4:]==".pyo"):
+ importlist.add(f[:-4])
+ Logger.debug("Adding python module (compiled): %s", f)
+
+ #try to import the modules as FirstAidKit.plugins.modulename
+ for m in importlist:
+ if m in Config.plugin._list("disabled"):
+ continue
+
+ imp.acquire_lock()
+ try:
+ Logger.debug("Importing module %s from %s", m, self._path)
+ moduleinfo = imp.find_module(m, [self._path])
+ module = imp.load_module(".".join([FirstAidKit.__name__, m]), *moduleinfo)
+ Logger.debug("... OK")
+ finally:
+ imp.release_lock()
+
+ self._plugins[m] = module
+
+ def list(self):
+ """Return the list of imported plugins"""
+ return self._plugins.keys()
+
+ def autorun(self, plugin, flow = None, dependencies = True):
+ """Perform automated run of plugin with condition checking
+returns - True if conditions are fully satisfied
+ False if there is something missing
+ exception when some other error happens"""
+
+ pklass = self._plugins[plugin].get_plugin() #get top level class of plugin
+ Logger.info("Plugin information...")
+ Logger.info("name:%s , version:%s , author:%s " % pklass.info())
+
+ flows = pklass.getFlows()
+ Logger.info("Provided flows : %s " % flows)
+ if flow==None:
+ flowName = pklass.default_flow
+ else:
+ flowName = flow
+
+ Logger.info("Using %s flow" % flowName)
+ if flowName not in flows:
+ Logger.error("Flow %s does not exist in plugin %s", flowName, plugin)
+ raise InvalidFlowNameException(d)
+
+ if dependencies:
+ deps = pklass.getDeps()
+ Logger.info("depends on: %s" % (", ".join(deps),))
+ for d in deps:
+ if not self._deps.require(d):
+ Logger.info("depends on usatisfied condition: %s" % (d,))
+ return False
+
+ p = pklass(flowName, reporting = self._reporting, dependencies = self._deps)
+ for (step, rv) in p: #autorun all the needed steps
+ Logger.info("Running step %s in plugin %s ...", step, plugin)
+ Logger.info("%s is current step and %s is result of that step." % (step, rv))
+
+ return True
+
+ def getplugin(self, plugin):
+ """Get instance of plugin, so we can call the steps manually"""
+ return self._plugins[plugin].get_plugin()
+
diff --git a/pyfirstaidkit/reporting.py b/pyfirstaidkit/reporting.py
new file mode 100644
index 0000000..0337340
--- /dev/null
+++ b/pyfirstaidkit/reporting.py
@@ -0,0 +1,96 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+import Queue
+import logging
+
+#semantics values
+#first the "task" levels for START and STOP
+FIRSTAIDKIT = 100
+TASKER = 90
+PLUGINSYSTEM = 80
+PLUGIN = 70
+FLOW = 60
+TASK = 50
+
+#semantics
+START = 0
+STOP = 1
+PROGRESS = 2
+INFO = 3
+ALERT = 4
+EXCEPTION = 5
+TABLE = 6 #types for arbitrary table-like organized iterables
+TREE = 7 #nested iterables organized as tree
+END = 1000 #End of operations, final message
+
+class Reports(object):
+ """Instances of this class are used as reporting mechanism by which the
+ plugins can comminucate back to whatever frontend we are using.
+
+ Message has four parts:
+ origin - who sent the message (name of the plugin, Pluginsystem, ...)
+ semantics - what action does the message describe
+ (INFO, ALERT, PROGRESS, START, STOP, DATA, END)
+ importance - how is that message important (debug, info, error, ...)
+ this must be number, possibly the same as in logging module
+ message - the message itself
+ for INFO and ALERT semantics, this is an arbitrary text
+ for PROGRESS, this is (x,y) pair denoting progress
+ (on step x from y steps) or None to hide the progress
+ for START and STOP, there is no mandatory message and the
+ importance specifies the level
+ """
+
+ def __init__(self, maxsize=-1):
+ self._queue = Queue.Queue(maxsize = maxsize)
+
+ def put(self, message, origin, semantics, importance = logging.INFO):
+ return self._queue.put((origin, semantics, importance, message))
+
+ def get(self, *args, **kwargs):
+ return self._queue.get(*args, **kwargs)
+
+
+ #There will be helper methods inspired by logging module
+ def end(self):
+ return self.put(None, None, END, importance = 1000)
+
+ def error(self, message, origin, semantics):
+ return self.put(message, origin, semantics, importance = logging.ERROR)
+
+ def start(self, message, origin, what = TASK):
+ return self.put(message, origin, START, importance = what)
+ def stop(self, message, origin, what = TASK):
+ return self.put(message, origin, START, importance = what)
+
+ def progress(self, position, maximum, origin, importance = logging.INFO):
+ return self.put((position, maximum), origin, PROGRESS, importance = importance)
+ def info(self, message, origin, importance = logging.INFO):
+ return self.put(message, origin, INFO, importance = importance)
+
+
+ def tree(self, message, origin, importance = logging.INFO):
+ return self.put(message, origin, TREE, importance = importance)
+ def table(self, message, origin, importance = logging.INFO):
+ return self.put(message, origin, TABLE, importance = importance)
+
+ def alert(self, message, origin, importance = logging.WARNING):
+ return self.put(message, origin, ALERT, importance = importance)
+ def exception(self, message, origin, importance = logging.ERROR):
+ return self.put(message, origin, EXCEPTION, importance = importance)
+
diff --git a/pyfirstaidkit/returns.py b/pyfirstaidkit/returns.py
new file mode 100644
index 0000000..c169b17
--- /dev/null
+++ b/pyfirstaidkit/returns.py
@@ -0,0 +1,42 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+
+#
+# These classes expressed here are to be the keys in the flow dictionary.
+# In most default cases the values are unimportant. They are placed there
+# for printing or other purposes.
+
+class ReturnValue:
+ """Its just a parent class for any Return class that might be create.
+
+ The parent has no value.
+ """
+ def __init__(self):
+ pass
+
+class ReturnValueTrue(ReturnValue):
+ def __init__(self):
+ self.value = True
+
+class ReturnValueFalse(ReturnValue):
+ def __init__(self):
+ self.value = False
+
+class ReturnValueNone(ReturnValue):
+ def __init__(self):
+ self.value = None
diff --git a/pyfirstaidkit/utils.py b/pyfirstaidkit/utils.py
new file mode 100644
index 0000000..139bb39
--- /dev/null
+++ b/pyfirstaidkit/utils.py
@@ -0,0 +1,38 @@
+# First Aid Kit - diagnostic and repair tool for Linux
+# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# 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.
+
+import os
+import sys
+import subprocess
+
+def spawnvch(executable, params, chroot): #returns errorcode
+ """Simpliest chroot modification of spawn
+ executable - path to binary to execute (in chroot!)
+ params - it's parameters
+ chroot - directory to chroot to
+
+Returns the error code returned by process"""
+
+ pid = os.fork()
+ if pid==0: #child
+ os.chroot(chroot)
+ os.execv(executable, params)
+ os.exit(1)
+ else:
+ res = os.waitpid(pid, 0)
+ return os.WEXITSTATUS(res)
+