Changeset 476

Show
Ignore:
Timestamp:
04/24/2002 06:05:32 PM (7 years ago)
Author:
chris
Message:

Documented new Directive creation.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • eddie/trunk/doc/dev_guide.txt

    r452 r476  
    77 
    88 
    9 Logging 
     9*** The Directive API: Creating new Directives *** 
     10 
     11The Directive API has been designed so that new directives can be added with 
     12a minimal amount of work.  The summary of the steps required are: 
     13 
     14 - Create new Python module in the "lib/common/Directives/" directory; 
     15 - Sub-class the Directive base-class, creating a new directive class 
     16   definition; 
     17 - Create directive-specific methods, overriding some of the base-class 
     18   methods. 
     19 
     20 
     21** Create New Module ** 
     22 
     23Eddie directives are defined in Python modules in the "lib/common/Directives/" 
     24directory of the Eddie tree.  If an appropriate module is not already available 
     25for the new directive, a new one must be created.  E.g., 
     26    $ vi /opt/eddie/lib/common/Directives/mydirec.py 
     27 
     28At the very least the new module must import the 'directive' module. 
     29The directive module contains the Directive base-class definition, along with 
     30a few other useful definitions (like exceptions). 
     31 
     32If logging is required (it usually is) the 'log' module should be imported. 
     33See *** Logging *** in this document for more details on logging.  E.g., 
     34    import directive, log 
     35 
     36 
     37** Create New Directive Class ** 
     38 
     39The new directive class definition should have the actual directive name, and 
     40it should be created as a sub-class of the Directive class.  E.g., 
     41    class MYFS(directive.Directive): 
     42        """ 
     43        This is my new directive. 
     44        It allows filesystem checks to be performed. 
     45        """ 
     46 
     47* constructor method * 
     48 
     49The constructor method must call the base-class constructor explicitly, 
     50define any required data-collectors (optional) and perform any other 
     51directive-specific initialization if necessary. 
     52E.g., 
     53    def __init__(self, toklist): 
     54        self.need_collectors = ( ('df','dfList'), ) 
     55        apply( directive.Directive.__init__, (self, toklist) ) 
     56 
     57The toklist variable contains token information provided by the config 
     58parser and contains the name of the directive class along with 
     59(optionally) the user-defined name of the directive instance. 
     60 
     61If any data-collectors are required by this directive, the need_collectors 
     62attribute must be set as a tuple of (module,class) pairs.  If any of 
     63these required data-collectors cannot be loaded at directive initialization 
     64time, config parsing will halt at that point and an error will be displayed. 
     65See *** Data Collectors *** for more information. 
     66 
     67* tokenparser method * 
     68 
     69The tokenparser method must be created for the directive class.  It is 
     70used to parse all the directive arguments and perform any final setup 
     71tasks.  It should begin by calling the base-class tokenparser method 
     72which actually does the parsing of tokens and building a container of 
     73valid arguments.  Common directive arguments are then set before returning 
     74control back to the current tokenparser method.  This method should 
     75check the existence of required directive-specific arguments, perform 
     76any checking of argument values (type-checking, etc), set default action 
     77variables (see *** Actions ***) and finally set a unique instance ID. 
     78E.g., 
     79    def tokenparser(self, toklist, toktypes, indent): 
     80        """ 
     81        Parse directive arguments. 
     82        """ 
     83 
     84        apply( directive.Directive.tokenparser, (self, toklist, toktypes, indent) ) 
     85 
     86        # test required arguments 
     87        try: 
     88            self.args.fsname 
     89        except AttributeError: 
     90            raise ParseFailure, "Filesystem name (fsname) not specified" 
     91 
     92        try: 
     93            self.args.rule 
     94        except AttributeError: 
     95            raise ParseFailure, "Rule not specified" 
     96 
     97        # Set any directive-specific variables 
     98        self.defaultVarDict['rule'] = self.args.rule 
     99 
     100        # define the unique ID 
     101        if self.ID == None: 
     102            self.ID = '%s.FS.%s' % (log.hostname,self.args.rule) 
     103        self.state.ID = self.ID 
     104 
     105* getData method * 
     106 
     107The base-class handles all the grunt work when a directive is run: 
     108including handling re-checks (numchecks argument > 1); calling the 
     109directive-specific method to fetch the data (getData method); 
     110evaluating the rule using the data as the environment; setting the 
     111directive state (ok, fail, etc) depending on the value of the rule 
     112evaluation; calling actions appropriately; and submitting the 
     113directive back in the scheduler queue. 
     114 
     115The main part that the new directive designer needs to worry about 
     116is the part that fetches the data.  This is performed in the getData 
     117method which must be defined by each directive sub-class. 
     118 
     119The getData method must do whatever is necessary to fetch the 
     120directive-specific data (which could be as simple as calling 
     121a data-collector - see *** Data Collectors ***) and returning 
     122the data as a dictionary of name/values. 
     123 
     124The data dictionary will be used as the environment to evaluate 
     125the rule in (each data element will be a variable available for 
     126the rule).  The data will also be be inserted into the action 
     127variable dictionary (see *** Actions ***) for use by action calls 
     128and message strings, etc. 
     129 
     130If getData encounters a critical error where the directive cannot 
     131continue, and should not be re-scheduled again, it should raise 
     132a directive.DirectiveError exception. 
     133 
     134If the directive is functioning fine, but the rule should not 
     135be evaluated this time for some reason, getData should return 
     136the None object.  The directive check will end immediately and 
     137the directive will be re-scheduled as normal. 
     138 
     139E.g., 
     140 
     141    def getData(self): 
     142        """ 
     143        Called by Directive docheck() method to fetch the data required for 
     144        evaluating the directive rule. 
     145        """ 
     146 
     147        # Get filesystem statistics from dfList data-collector 
     148        df = self.data_collectors['df.dfList'][self.args.fsname] 
     149        if df == None: 
     150            # Raise an error if given filesystem is invalid 
     151            log.log( "<directive>FS.docheck(): Error, filesystem not found '%s'" % (self.args.fsname), 4 ) 
     152            raise directive.DirectiveError, "Error, filesystem not found '%s'" % (self.args.fsname) 
     153        else: 
     154            # Return dictionary of filesystem stats 
     155            return df.getHash() 
     156 
     157** Optional Methods ** 
     158 
     159There are a few more methods which can be defined for a directive 
     160if they are necessary. 
     161 
     162* addVariables * 
     163 
     164If any action variables need to be added after the rule has been evaluated 
     165(but before actions are called) an addVariables method can be defined to 
     166do just this. 
     167 
     168* postAction * 
     169 
     170If any post-action processing needs to be performed, before the directive 
     171is re-scheduled, it can be done in a postAction method. 
     172 
     173** Test New Directive Class ** 
     174 
     175Once the above steps have been completed, the new directive should be ready for 
     176use.  EDDIE will automatically pick it up.  A test rule can be added to the 
     177configuration and EDDIE restarted.  Look for errors or exceptions in the log 
     178file to see if there are problems. 
     179 
     180E.g., 
     181 
     182    MYFS test: fsname='/var/log' 
     183               rule='capac > 50' 
     184               action='email("root", "Filesystem %(mountpt)s is over 50%% full")' 
     185 
     186 
     187*** Data Collectors *** 
     188 
     189TODO 
     190 
     191 
     192 
     193*** Actions *** 
     194 
     195TODO 
     196 
     197 
     198 
     199*** Logging *** 
    10200 
    11201EDDIE logs to the logfile specified by LOGFILE in the config.  It uses the