summaryrefslogtreecommitdiffstats
path: root/doc/fakplugin.1
blob: ca1d9583907a97dfc4ba5f54ab81a0c19c49135f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
.TH "FirstAidKit Plugins" "1" 
.SH "NAME" firstaidkit-plugins
.BR
.SH "DESCRIPTION"
This man page tries to describe the inner workings of the plugin system for FirstAidKit. 
It also contains useful information to develop a plugin for firstaidkit.

.SH "Plugin Suffixes"
All plugins belong to configured plugin directory. Recognized suffixes are: .py, .pyc, 
.pyo (python modules) and .so (python compatible binary module).  The plugins should be 
placed in a default location (/usr/lib/firstaidkit-plugins, the lib directory changes to 
lib64 when in a 64 bit arch).
.\"Should mention the /etc/firstaidkit.conf file.  Should include multiple plugin source dirs.\"

.SH "Plugin Model"
The building blocks of the plugins are functions and flows.  A function is a certain action 
that is taken inside the plugin.  This action is more or less independent from the rest of 
the plugin actions.  Things like fix, backup, restore... qualify as actions/functions.  
This does not mean that functions do not relate to each other.  They are related by using 
the flow structure.

A flow is the organization of functions in a directional graph that defines the "flow" of 
functions.  Understand flow here as the order in which each function is executed when the 
plugin is used.  This order/flow is specified using the function names, their return codes 
and the flow structure.  All this is contained within a dictionary (The Examples Sections 
shows how this is done.)

Please take into account as you code your plugin to set the _result and the _state values 
in your main plugin class.  These values are necessary to correctly execute the flow given 
by the flow dictionary.

.SH "Coding a Plugin"
.IP "1. Class methods and class attributes:"
The main plugin class has some class methods and some class attributes. These elements are 
used to describe the plugin and are used without actually using a instance of the plugin.  
This is important because we do not want to execute the __init__ function and cause lots of 
unnecessary  stuff to go into memory when we are querying for plugin basic information.

The class attributes are: name, version, author, initial (Initial state for all flows), final 
(Final state for all flows), flows (The flows defined by the Plugin class), default_flow (is 
the name of the flow used in automatic repair mod).

The class attributes are: info() (returns the name, version and author  in a tuple), getDeps() 
(returns list of required flags for automated mode) and getFlows() (returns a list of possible 
flow names that the plugin can execute).

.IP "2. Plugin dependencies"
You can also specify flags, which are required to be satisfied before the automated mode can 
use this plugin. The requirements should be returned as python set of strings by the getDeps() 
class method.  Setting flags is also easy. Just use the provide() method common to all plugins.

.IP "3. Default functions:"
See section "Common stuff for plugins"

.IP "4. Flows:"
If you want to redefine or add your own flows into your plugin, you must initialize the parent 
class (Plugin) in your __init__.  And begin to add your personalized flows to the flows 
variable.  The examples section shows how to add a flow.

.IP "5. self._result and self._state
These are the two variables that define the location of the plugin inside the flow dictionary.  
In each function, after it has done its intended action, the self._result variable must be 
changed to a correct value.  This value will define the next self._state value inside the plugin.  
The self._state value is change using the flow dictionary and the self._result value.

.IP "6. get_plugin()"
Each plugin must define a get_plugin function.  This function must return the main class of the 
plugin.  This is used to take out info from the plugin, and to instantiate it.  If in doubt, take a 
look at the sample plugins that come with the man FirstAidKit code base. They can give you a pretty 
good idea of what to do when using a  module, file ...

.IP "7. return values:"
For each function you code in a plugin you must use predefined return classes.  It is necessary to 
have the extra wrapper because the python native types can get messy (1==True).  Just use the ones 
provided by  the plugin system, or create your own.

.SH "Common stuff"
Each plugin, by default, should exports some steps. The mandatory ones are:
.IP "prepare" 
Initialize plugin, get environment.
.IP "backup" 
Backup everything we could touch in this plugin.
.IP "diagnose"
Get info about the investigated system and determine where the problems are.
.IP "fix" 
Auto fix the errors from diagnose step.
.IP "restore" 
Restore system from backup.
.IP "clean" 
Destroy the plugin, cleanup.
.PP
The plugin should ensure that the calling order is correct
and the system cannot end in some indeterminate state.

.SH "Python Modules:"
A plugin for the FirstAidKit must inherit from the pyfirstaidkit.Plugin class. It must also implement 
the mandatory plugin steps.  The pyfirstaidkit.Plugin parent will provide a default flow that will use 
the functions defined by the plugin developer.  Moreover, for the mandatory steps, the plugin developer 
must guarantee that the function will return a valid return  class (more on return class further on).  
In other words, the function must return one of the possible return classes included in the default 
flow.
pyfirstaidkit.Plugin defines:
.IP "nextstep()" 
This is used to return the next function that should be executed.  __iter__() is not used because there 
is no control over __iter__() in an iteration.  nextstep() allows us execution of the flow without the 
need for an iteration.  However the iteration is present in the class and can be used accordingly.
.IP "__iter__() and next()" 
Iterator protocol, works in the same way as nextstep() but end with StopIteration exception
.IP "actions()" 
Returns list of available step names
.IP "call(step)" 
Calls one specific step identified by name
.IP "info()" 
Returns tuple of strings defined as (name of plugin, version, author)
.IP "changeFlow()" 
Allows the caller to change to some other flow defined in the plugin.
.IP "getFlows()"
Returns all the possible flows that the plugin supports. And of course the steps itself. They are 
defined as methods with the same names as used in actions().
.IP "getDeps()"
Returns list of flags which are required for this plugin to operate in automated mode.
.IP "provide(flag)"
Adds flag into the pool of satisfied flags.
.IP "require(flag)"
Queries the state of flag. Returns True if set, False otherwise.

.SH "Arbitrary Executable Modules"
The current approach is to create a wrapper python plugin, which holds the meta data
and calls the binaries as necessary (see the examples).

.SH "Examples"
.IP "Flow description (Example 1):"
Consider the following flow and its dictionary:
    start->fix->end
    dict = { start:fix, 
             fix:end
           }

.IP "Flow description (Example 2):"
Consider the following flow and its dictionary:
                   ,>end
    start->diagnose
                   `>fix->end
    dict = { start:diagnose, 
             diagnose:{"goodSys":end,"badSys":fix}, 
             fix:end 
           }

This flow has a conditional after the diagnose function.  If diagnose results in a corrupt 
state of the system, then the plugin proceeds  with fix.  If all is good in the system, then 
the flow end.  Note that the next step in the diagnose case is defined buy whatever diagnose 
returned.

.IP "Adding a flow (Example 3):"
class MyPlugin(Plugin):
    flows = Flow.init(Plugin)
    flows["myflow"] = Flow({flow rules}, description="")

.SH "SEE ALSO"
http://fedorahosted.org/firstaidkit

.SH "AUTHORS"
Martin Sivak <msivak@redhat.com>
Joel Granados <jgranado@redhat.com>

.SH "BUGS"
Please search/report bugs at http://fedorahosted.org/firstaidkit/newticket