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