user manual
[nepi.git] / doc / user_manual / ec_api.tex
1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 %
3 %    NEPI, a framework to manage network experiments
4 %    Copyright (C) 2013 INRIA
5 %
6 %    This program is free software: you can redistribute it and/or modify
7 %    it under the terms of the GNU General Public License version 2 as
8 %    published by the Free Software Foundation;
9 %
10 %    This program is distributed in the hope that it will be useful,
11 %    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 %    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 %    GNU General Public License for more details.
14 %
15 %    You should have received a copy of the GNU General Public License
16 %    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 %
18 % Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19 %
20 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21
22
23 The ExperimentController (EC) is the entity in charge of turning the 
24 experiment description into a running experiment. 
25 In order to do this the EC needs to know which resources are to be 
26 used, how they should be configured and how resources relate to one another.
27 To this purpose the EC exposes methods to register resources, specify their 
28 configuration, and register dependencies between. These methods are part of
29 the EC design API.
30 Likewise, in order to deploy and control resources, and collect data, 
31 the EC exposes another set of methods, which form the execution API. 
32 These two APIs are described in detail in the rest of this chapter.
33
34
35 \section{The experiment script}
36
37 NEPI is a Python-based language and all classes and functions can
38 be used by importing the \emph{nepi} module from a Python script.
39
40 In particular, the ExperimentController class can be imported as follows:
41
42 \begin{lstlisting}[language=Python]
43
44 from nepi.execution.ec import ExperimentController
45
46 \end{lstlisting}
47
48 Once this is done, an ExperimentController must be instantiated for
49 the experiment. The ExperimentController constructor receives
50 the optional argument \emph{exp\_id}. This argument is important because
51 it defines the experiment identity and allows to distinguish among different
52 experiments. If an experiment id is not explicitly given, NEPI will automatically
53 generate a unique id for the experiment. 
54
55 \begin{lstlisting}[language=Python]
56
57 ec = ExperimentController(exp_id="my-exp-id")
58
59 \end{lstlisting}
60
61 The experiment id can always be retrieved as follows
62
63 \begin{lstlisting}[language=Python]
64
65 exp_id = ec.exp_id 
66
67 \end{lstlisting}
68
69 Since a same experiment can be ran more than one time, and this is 
70 often desirable to obtain statistical data, the EC identifies 
71 different runs of an experiment with a same \emph{exp\_id} with  
72 another attribute, the \emph{run\_id}. The \emph{run\_id} is
73 a timestamp string value, and in combination with the \emph{exp\_id},
74 it allows to uniquely identify an experiment instance.
75
76 \begin{lstlisting}[language=Python]
77
78 run_id = ec.run_id 
79
80 \end{lstlisting}
81
82
83
84 \section{The design API}
85
86 Once an ExperimentController has been instantiated, it is possible to start
87 describing the experiment. The design API is the set of methods which
88 allow to do so.
89
90
91 \subsection{Registering resources}
92
93 Every resource supported by NEPI is controlled by a specific ResourceManager 
94 (RM). The RM instances are automatically created by the EC, and the user does 
95 not need to interact with them directly. 
96
97 Each type of RM is associated with a \emph{type\_id} which uniquely identifies 
98 a concrete kind of resource (e.g PlanetLab node, application that runs in
99 a Linux machine, etc).
100 The \emph{type\_ids} are string identifiers, and they are required  
101 to register a resource with the EC.
102
103 To discover all the available RMs and their \emph{type\_ids} we
104 can make use of the ResourceFactory class.
105 This class is a \emph{Singleton} that holds the templates and information 
106 of all the RMs supported by NEPI. We can retrieve this information as follows:
107
108 \begin{lstlisting}[language=Python]
109
110 from nepi.execution.resource import ResourceFactory
111
112 for type_id in ResourceFactory.resource_types():
113     rm_type = ResourceFactory.get_resource_type(type_id)
114     print type_id, ":", rm_type.get_help()
115
116 \end{lstlisting}
117
118 Once the \emph{type\_id} of the resource is known, the registration of a
119 new resource with the EC is simple:
120
121 \begin{lstlisting}[language=Python]
122
123 type_id = "SomeRMType"
124 guid = ec.register_resources(type_id)
125
126 \end{lstlisting}
127
128 When a resource is registered, the EC instantiates a RM of the 
129 requested \emph{type\_id} and assigns a global unique identifier 
130 (guid) to it. The guid is an incremental integer number and it 
131 is the value returned by the \emph{register\_resource} method.
132 The EC keeps internal references to all RMs, which the user can
133 reference using the corresponding guid value.
134
135
136 \subsection{Attributes}
137
138 ResourceManagers expose the configurable parameters of resources
139 through a list of attributes. An attribute can be seen as a
140 \emph{{name:value}} pair, that represents a certain aspect of
141 the resource (whether information or configuration information).
142
143 It is possible to discover the list of attributes exposed by an 
144 RM type as follows:
145
146 \begin{lstlisting}[language=Python]
147 from nepi.execution.resource import ResourceFactory
148
149 type_id = "SomeRMType"
150 rm_type = ResourceFactory.get_resource_type(type_id)
151
152 for attr in rm_type.get_attributes():
153     print "       ",  attr.name, ":", attr.help
154     
155 \end{lstlisting}
156
157 To configure or retrieve the value of a certain attribute of
158 an registered resource we can use the \emph{get} and \emph{set}
159 methods of the EC.
160
161 \begin{lstlisting}[language=Python]
162
163 old_value = ec.get(guid, "attr_name")
164 ec.set(guid, "attr_name", new_value)
165 new_value = ec.get(guid, "attr_name")
166
167 \end{lstlisting}
168
169 Since each RM type exposes the characteristics of a particular type
170 of resource, it is to be expected that different RMs will have different
171 attributes. However, there a particular attribute that is common to all RMs.
172 This is the \emph{critical} attribute, and it is meant to indicate to the EC
173 how it should behave when a failure occurs during the experiment. 
174 The \emph{critical} attribute has a default value of \emph{True}, since
175 all resources are considered critical by default. 
176 When this attribute is set to \emph{False} the EC will ignore failures on that 
177 resource and carry on with the experiment. Otherwise, the EC will immediately 
178 interrupt the experiment.
179
180
181 \subsection{Traces}
182
183 A Trace represent a stream of data collected during the experiment and associated
184 to a single resource. ResourceManagers expose a list of traces, which are identified
185 by a name. Particular traces might or might not need activation, since some traces
186 are enabled by default.
187
188 It is possible to discover the list of traces exposed by an 
189 RM type as follows:
190
191 \begin{lstlisting}[language=Python]
192 from nepi.execution.resource import ResourceFactory
193
194 type_id = "SomeRMType"
195 rm_type = ResourceFactory.get_resource_type(type_id)
196
197 for trace in rm_type.get_traces():
198     print "       ",  trace.name, ":", trace.enabled
199     
200 \end{lstlisting}
201
202 The \emph{enable\_trace} method allows to enable a specific trace for a 
203 RM instance
204
205 \begin{lstlisting}[language=Python]
206
207 ec.enable_trace(guid, "trace-name")
208
209 print ec.trace_enabled(guid, "trace-name")
210
211 \end{lstlisting}
212
213
214 \subsection{Registering connections}
215
216 In order to describe the experiment set-up, a resources need to be 
217 associated at least to one another. Through the process of connecting resources
218 the \emph{topology graph} is constructed. A certain application might
219 need to be configured and executed on a certain node, and this
220 must be indicated to the EC by connecting the application RM to the node
221 RM.
222
223 Connections are registered using the \emph{register\_connection} method,
224 which receives the guids of the two RM.
225
226 \begin{lstlisting}[language=Python]
227
228 ec.register_connection(node_guid, app_guid)
229
230 \end{lstlisting}
231
232 The order in which the guids are given is not important, since the
233 \emph{topology\_graph} is not directed, and the corresponding 
234 RMs \emph{`know'} internally how to interpret the connection 
235 relationship.
236
237
238 \subsection{Registering conditions}
239
240 All ResourceMangers must go through the same sequence of state transitions.
241 Associated to those states are the actions that trigger the transitions.
242 As an example, a RM will initially be in the state NEW. When the DEPLOY action
243 is invoked, it will transition to the DISCOVERED, then PROVISIONED, then READY
244 states. Likewise, the action START will make a RM pass from state READY to 
245 STARTED, and the action STOP will change a RM from state STARTED to STOPPED.
246
247 Using these states and actions, it is possible to specify workflow dependencies 
248 between resources. For instance, it would be possible to indicate that
249 one application should start after another application by registering a 
250 condition with the EC.
251
252 \begin{lstlisting}[language=Python]
253
254 from nepi.execution.resource import ResourceState, ResourceActions
255
256 ec.register_condition(app1_guid, ResourceAction.START, app2_guid, ResourceState.STARTED)
257
258 \end{lstlisting}
259
260 The above invocation should be read "Application 1 should START after application 2 
261 has STARTED". It is also possible to indicate a relative time from the moment a state
262 change occurs to the moment the action should be taken as follows:
263
264 \begin{lstlisting}[language=Python]
265
266 from nepi.execution.resource import ResourceState, ResourceActions
267
268 ec.register_condition(app1_guid, ResourceAction.START, app2_guid, ResourceState.STARTED, time = "5s")
269
270 \end{lstlisting}
271
272 This line should be read "Application 1 should START at least 5 seconds after 
273 application 2 has STARTED". \\
274
275 Allowed actions are: DEPLOY, START and STOP. \\
276
277 Existing states are: NEW, DISCOVERED, PROVISIONED, READY, STARTED, STOPPED, 
278 FAILED and RELEASED. \\
279
280
281
282 \section{The execution API}
283
284 After registering all the resources and connections and setting attributes and
285 traces, once the experiment we want to conduct has been described, we can
286 proceed to run it. To this purpose we make use of the \emph{execution} methods
287 exposed by the EC.
288
289
290 \subsection{Deploying an experiment}
291
292 Deploying an experiment is very easy, it only requires to invoke the 
293 \emph{deploy} method of the EC.
294
295 \begin{lstlisting}[language=Python]
296
297 ec.deploy()
298
299 \end{lstlisting}
300
301 Given the experiment description provided earlier, the EC will take care
302 of automatically performing all necessary actions to discover, provision,
303 configure and start all resources registered in the experiment. 
304
305 Furthermore, NEPI does not restrict deployment to only one time, it allows
306 to continue to register, connect and configure resources and deploy them
307 at any moment. We call this feature \emph{interactive} or \emph{dynamic}
308 deployment. 
309
310 The \emph{deploy} method can receive other optional arguments to customize
311 deployment. By default, the EC will deploy all registered RMs that are in
312 state NEW. However, it is possible to specify a subset of resources to be
313 deployed using the \emph{guids} argument.
314
315 \begin{lstlisting}[language=Python]
316
317 ec.deploy(guids=[guid1, guid2, guid3])
318
319 \end{lstlisting}
320
321 Another useful argument of the \emph{deploy} method is \emph{wait\_all\_ready}.
322 This argument has a default value of \emph{True}, and it is used as a barrier
323 to force the START action to be invoked on all RMs being deploy only after
324 they have all reached the state READY.
325
326 \begin{lstlisting}[language=Python]
327
328 ec.deploy(wait_all_ready=False)
329
330 \end{lstlisting}
331
332
333 \subsection{Getting attributes}
334
335 Attribute values can be retrieved at any moment during the experiment run, 
336 using the \emph{get} method. 
337 However, not all attributes can be modified after a resource has
338 been deployed. The possibility of changing the value of a certain attribute 
339 depends strongly on the RM and on the attribute itself. 
340 As an example, once a \emph{hostname} has been specified for a certain Node 
341 RM, it might not be possible to change it after deployment.
342
343 \begin{lstlisting}[language=Python]
344
345 attr_value = ec.get(guid, "attr-name")
346
347 \end{lstlisting}
348
349 Attributes have flags that indicate whether their values can be changed
350 and when it is possible to change them (e.g. before or after deployment, 
351 or both). These flags are \emph{NoFlags} (the attribute value can be 
352 modified always), \emph{ReadOnly} (the attribute value can never be
353 modified), \emph{ExecReadOnly} (the attribute value can only be modified
354 before deployment). The flags of a certain attribute can be validated 
355 as shown in the example below, and the value of the attribute can be
356 changed using the \emph{set} method.  
357
358 \begin{lstlisting}[language=Python]
359
360 from nepi.execution.attribute import Flags
361
362 attr = ec.get_attribute(guid, "attr-name")
363
364 if not attr.has_flag(Flags.ReadOnly):
365     ec.set(guid, "attr-name", attr_value)
366
367 \end{lstlisting}
368
369 \subsection{Quering the state}
370
371 It is possible to query the state of any resource at any moment.
372 The state of a resource is requested using the \emph{state} method.
373 This method receives the optional parameter \emph{hr} to output the
374 state in a \emph{human readable} string format instead of an integer
375 state code.
376
377 \begin{lstlisting}[language=Python]
378
379 state_id = ec.state(guid)
380
381 # Human readable state
382 state = ec.state(guid, hr = True)
383
384 \end{lstlisting}
385
386 \subsection{Getting traces}
387
388 After a ResourceManager has been deployed it is possible to get information
389 about the active traces and the trace streams of the generated data using
390 the \emph{trace} method.
391
392 Most traces are collected to a file in the host where they are generated, 
393 the total trace size and the file path in the (remote) host can be 
394 retrieved as follows.
395
396 \begin{lstlisting}[language=Python]
397
398 from nepi.execution.trace import TraceAttr
399
400 path = ec.trace(guid, "trace-name", TraceAttr.PATH)
401 size = ec.trace(guid, "trace-name", TraceAttr.SIZE)
402
403 \end{lstlisting}
404
405 The trace content can be retrieved in a stream, block by block.
406
407 \begin{lstlisting}[language=Python]
408
409 trace_block = ec.trace(guid, "trace-name", TraceAttr.STREAM, block=1, offset=0)
410
411 \end{lstlisting}
412
413 It is also possible to directly retrieve the complete trace content.
414
415 \begin{lstlisting}[language=Python]
416
417 trace_stream = ec.trace(guid, "trace-name")
418
419 \end{lstlisting}
420
421 Using the \emph{trace} method it is easy to collect all traces 
422 to the local user machine. 
423
424 \begin{lstlisting}[language=Python]
425
426 for trace in ec.get_traces(guid):
427     trace_stream = ec.trace(guid, "trace-name")
428     f = open("trace-name", "w")
429     f.write(trace_stream)
430     f.close()
431
432 \end{lstlisting}
433
434
435 % TODO: how to retrieve an application trace when the Node failed? (critical attribute)
436
437
438 % \subsection{The collector RM}
439
440 %%%%%%%%%%
441 %% TODO
442 %%%%%%%%%%%
443
444 \subsection{API reference}
445
446 Further information about classes and method signatures
447 can be found using the Python \emph{help} method.
448 For this inspection work, we recommend to instantiate an
449 ExperimentController from an IPython console. This is an
450 interactive console that allows to dynamically send input
451 to the python interpreter. 
452
453 If NEPI is not installed in the system, you will need to add the
454 NEPI sources path to the PYTHONPATH environmental variable 
455 before invoking \emph{ipython}.
456
457 \begin{lstlisting}[language=Python]
458
459 $ PYTHONPATH=$PYTHONPATH:src ipython
460 Python 2.7.3 (default, Jan  2 2013, 13:56:14) 
461 Type "copyright", "credits" or "license" for more information.
462
463
464 IPython 0.13.1 -- An enhanced Interactive Python.
465 ?         -> Introduction and overview of IPython's features.
466 %quickref -> Quick reference.
467 help      -> Python's own help system.
468 object?   -> Details about 'object', use 'object??' for extra details.
469
470 In [1]: from nepi.execution.ec import ExperimentController
471
472 In [2]: ec = ExperimentController(exp_id="test")
473
474 In [3]: help(ec.set)
475
476 \end{lstlisting}
477
478 The example above will show the following information related to the
479 \emph{set} method of the EC API.
480
481 \begin{lstlisting}[language=Python]
482
483 Help on method set in module nepi.execution.ec:
484
485 set(self, guid, name, value) method of nepi.execution.ec.ExperimentController instance
486     Modifies the value of the attribute with name 'name' on the RM with guid 'guid'.
487     
488     :param guid: Guid of the RM
489     :type guid: int
490     
491     :param name: Name of the attribute
492     :type name: str
493     
494     :param value: Value of the attribute
495
496 \end{lstlisting}
497
498