1FirstAidKit Plugins(1) General Commands Manual FirstAidKit Plugins(1)
2
3
4
6
7
9 This man page tries to describe the inner workings of the plugin system
10 for FirstAidKit. It also contains useful information to develop a
11 plugin for firstaidkit.
12
13
15 All plugins belong to configured plugin directory. Recognized suffixes
16 are: .py, .pyc, placed in a default location
17 (/usr/{lib,lib64}/firstaidkit-plugins).
18
19
21 The building blocks of the plugins are functions and flows. A function
22 is a certain action that is taken inside the plugin. This action is
23 more or less independent from the rest of the plugin actions. Things
24 like fix, backup, restore... qualify as actions/functions. This does
25 not mean that functions do not relate to each other. They are related
26 by using the flow data structure (The data structure used for the flows
27 is a dictionary).
28
29 A flow is the organization of functions in a directional graph that
30 defines the "flow" of functions. Understand flow here as the order in
31 which functions are executed when the plugin is used. This order/flow
32 is specified using the function names, their return codes and the flow
33 data structure. All this is contained within a dictionary (The Exam‐
34 ples Sections shows how this is done.)
35
36
38 1. Class methods and class attributes:
39 The main plugin class has some class methods and some class
40 attributes. These elements are used to describe the plugin and
41 are used without actually using a instance of the plugin. This
42 is important because we do not want to execute the __init__
43 function and cause lots of unnecessary stuff to go into memory
44 when we are querying for plugin basic information.
45
46 The class attributes are: name, version, author and the defined
47 flows. For the information to be displayed correctly to the
48 user the plugin developer must include at least name, version
49 and author as class attributes. The flows attribute is not
50 necesarry if custom flows aren't present. If the plugin devel‐
51 oper is planning to create a custom flows he must declare the
52 flows dictionary for your plugin. More information of the class
53 attributes in the "Class Attribute" section.
54
55 The class methods are: info() (returns the name, version and
56 author in a tuple), getDeps() (returns list of required flags
57 for automated mode) and getFlows() (returns a list of possible
58 flow names that the plugin can execute). The plugin developer
59 doesn't really have to worry about the methods as they are
60 defined in the father class Plugin. Section "Class Methods"
61 gives more infor on each one.
62
63
64 2. Plugin dependencies
65 You can also specify flags, which are required to be satisfied
66 before the automated mode can use this plugin. The requirements
67 should be returned as python set of strings by the getDeps()
68 class method. Setting flags is also easy. Just use the pro‐
69 vide() method common to all plugins.
70
71 There is also getConflicts() method, with the very same behav‐
72 iour as getDeps(), but with the opposite meaning. Meaning, it is
73 a set of flags, which have to NOT be satisfied for the plugin to
74 be processed.
75
76
77 3. Default functions:
78 See section "Common stuff for plugins"
79
80
81 4. Flows:
82 There are two basic flows hardcoded into the system. These flows
83 may *not* be used by plugin developers. The first flow is
84 called diagnose: the intention with this flow is to give the
85 user information of the state of the system that the plugin is
86 analysing. This flow is intended to give general information
87 and needs to be very fast. If the plugin needs to do some more
88 detailed diagnose analysis, we suggest to create another flow
89 called 'detailedAnalysis'. When coding the diagnose flow,
90 remember that it will be executed when the user asks for the
91 information of *all* the plugins. The diagnose flow calls only
92 the prepare, diagnose and clean tasks. The second flow is
93 called fix: the intention with this flow is to actually fix
94 whatever is wrong with the system. We suggest this flow to be
95 as thorough as it needs to be. If there is more than one way to
96 fix the problem, this flow would be the easiest one (the plugin
97 developer can create other flow for the more complex ones). For
98 this flow to be successfull the prepare, diagnose, backup, fix,
99 restore and clean tasks must be present in the plugin. for more
100 info see section "Common stuff for plugins". Finally, to add a
101 custom flow the plugin developer must initialize a dictionary
102 named flows using flows = Flow.init(parent class) and fill it
103 with the custom flows. For more info on adding flows see the
104 "Examples" section.
105
106
107 5. self._result and self._state
108 These are the two variables that define the location of the
109 plugin inside the flow dictionary. In each function, after it
110 has done its intended action, the self._result variable must be
111 changed to a correct value. Think of the self._result as the
112 return value of each task. Before any task is executed, the
113 self._result is set to None, so we can handle exceptions as spe‐
114 cial direction in flows. The self._result usually takes a
115 firstaidkit return value (classes that define the return value).
116
117 Firstaidkit comes with predifined return value classes but the
118 plugin developer may define his own return classes. One reason
119 to define a custom return class is to have actual values be
120 passed between tasks (this is not yet implemented as the tasks
121 are in the same class and can interchange values using the class
122 variable). The self._state is the name of the task where the
123 plugin is at a certain moment. The self._state variable is of
124 no real use to the plugin developer as he must know in what task
125 the plugin is in.
126
127
128 6. get_plugin()
129 Each plugin must define a get_plugin function. This function
130 must return the main class of the plugin. This is used to take
131 out info from the plugin, and to instantiate it. If in doubt,
132 take a look at the sample plugins that come with the man
133 FirstAidKit code base. They can give you a pretty good idea of
134 what to do when using a module, file ...
135
136
137 7. return values:
138 For each function you code in a plugin you must use predefined
139 return classes. It is necessary to have the extra wrapper
140 because the python native types can get messy (1==True). Just
141 use the ones provided by the plugin system, or create your own.
142
143
145 Each plugin, by default, should exports some steps. The mandatory ones
146 are:
147
148 prepare
149 Initialize plugin, get environment.
150
151 backup Backup everything we could touch in this plugin. (Also see the
152 firstaidkit-backup manpage)
153
154 diagnose
155 Get info about the investigated system and determine where the
156 problems are.
157
158 fix Auto fix the errors from diagnose step.
159
160 restore
161 Restore system from backup.
162
163 clean Destroy the plugin, cleanup.
164
165 The plugin should ensure that the calling order is correct and the sys‐
166 tem cannot end in some indeterminate state.
167
168
170 A plugin for the FirstAidKit must inherit from the pyfirstaidkit.Plugin
171 class. It must also implement the mandatory plugin steps. The
172 pyfirstaidkit.Plugin parent will provide a default flow that will use
173 the functions defined by the plugin developer. Moreover, for the
174 mandatory steps, the plugin developer must guarantee that the function
175 will return a valid return class (see "Return Values section"). In
176 other words, the function must return one of the possible return
177 classes included in the default flow. Each plugin must have the
178 get_plugin method in order to actually be seen by the firstaidkit back‐
179 end.
180
181
183 This is how the diagnose and fix flows are coded in the backend plugin
184 system.
185 flows["diagnose"] = Flow({
186 initial : {Return: "prepare"},
187 "prepare" : {ReturnSuccess: "diagnose", None: "clean"},
188 "diagnose" : {ReturnSuccess: "clean", ReturnFailure: "clean",
189 None: "clean"},
190 "clean" : {ReturnSuccess: final, ReturnFailure: final, None:
191 final}
192 }, description="The default, fully automated, diagnose sequence")
193
194 flows["fix"] = Flow({
195 initial : {Return: "prepare"},
196 "prepare" : {ReturnSuccess: "diagnose", None: "clean"},
197 "diagnose" : {ReturnSuccess: "clean", ReturnFailure: "backup",
198 None: "clean"},
199 "backup" : {ReturnSuccess: "fix", ReturnFailure: "clean", None:
200 "clean"},
201 "fix" : {ReturnSuccess: "clean", ReturnFailure: "restore",
202 None: "restore"},
203 "restore" : {ReturnSuccess: "clean", ReturnFailure: "clean",
204 None: "clean"},
205 "clean" : {ReturnSuccess: final, ReturnFailure: final, None:
206 final}
207 }, description="The default, fully automated, fixing sequence")
208
209 Other important class attributes are: name, version, author and
210 description. They are selfexplanatory.
211
212
213
215 pyfirstaidkit.Plugin defines:
216
217 nextstep()
218 This is used to return the next function that should be exe‐
219 cuted. __iter__() is not used because there is no control over
220 __iter__() in an iteration. nextstep() allows us execution of
221 the flow without the need for an iteration. However the itera‐
222 tion is present in the class and can be used accordingly.
223
224 __iter__() and next()
225 Iterator protocol, works in the same way as nextstep() but end
226 with StopIteration exception
227
228 actions()
229 Returns list of available step names
230
231 call(step)
232 Calls one specific step identified by name
233
234 info() Returns tuple of strings defined as (name of plugin, version,
235 author)
236
237 changeFlow()
238 Allows the caller to change to some other flow defined in the
239 plugin.
240
241 getFlows()
242 Returns all the possible flows that the plugin supports. And of
243 course the steps itself. They are defined as methods with the
244 same names as used in actions().
245
246 getDeps()
247 Returns list of flags which are required for this plugin to
248 operate in automated mode.
249
250 provide(flag)
251 Adds flag into the pool of satisfied flags.
252
253 require(flag)
254 Queries the state of flag. Returns True if set, False otherwise.
255
256
258 The current approach is to create a wrapper python plugin, which holds
259 the meta data and calls the binaries as necessary (see the examples).
260
261
263 Flow description (Example 1):
264 Consider the following flow and its dictionary:
265 start->fix->end
266 dict = { start:fix,
267 fix:end
268 }
269
270
271 Flow description (Example 2):
272 Consider the following flow and its dictionary:
273 ,>end
274 start->diagnose
275 `>fix->end
276 dict = { start:diagnose,
277 diagnose:{"goodSys":end,"badSys":fix},
278 fix:end
279 }
280
281 This flow has a conditional after the diagnose function. If
282 diagnose results in a corrupt state of the system, then the
283 plugin proceeds with fix. If all is good in the system, then
284 the flow end. Note that the next step in the diagnose case is
285 defined buy whatever diagnose returned.
286
287
288 Adding a flow (Example 3):
289 class MyPlugin(Plugin):
290 flows = Flow.init(Plugin)
291 flows["myflow"] = Flow({flow rules}, description="")
292
293
295 firstaidkit-reporting manpage firstaidkit-backup manpage http://fedora‐
296 hosted.org/firstaidkit
297
298
300 Martin Sivak <msivak@redhat.com> Joel Granados <jgranado@redhat.com>
301
302
304 Please search/report bugs at http://fedorahosted.org/firstaid‐
305 kit/newticket
306
307
308
309 FirstAidKit Plugins(1)