%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%    NEPI, a framework to manage network experiments
%    Copyright (C) 2013 INRIA
%
%    This program is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License version 2 as
%    published by the Free Software Foundation;
%
%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
% Author: Alina Quereilhac <alina.quereilhac@inria.fr>
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


The ExperimentController (EC) is the entity in charge of turning the 
experiment description into a running experiment. 
In order to do this the EC needs to know which resources are to be 
used, how they should be configured and how resources relate to one another.
To this purpose the EC exposes methods to register resources, specify their 
configuration, and register dependencies between. These methods are part of
the EC design API.
Likewise, in order to deploy and control resources, and collect data, 
the EC exposes another set of methods, which form the execution API. 
These two APIs are described in detail in the rest of this chapter.


\section{The experiment script}

NEPI is a Python-based language and all classes and functions can
be used by importing the \emph{nepi} module from a Python script.

In particular, the ExperimentController class can be imported as follows:

\begin{lstlisting}[language=Python]

from nepi.execution.ec import ExperimentController

\end{lstlisting}

Once this is done, an ExperimentController must be instantiated for
the experiment. The ExperimentController constructor receives
the optional argument \emph{exp\_id}. This argument is important because
it defines the experiment identity and allows to distinguish among different
experiments. If an experiment id is not explicitly given, NEPI will automatically
generate a unique id for the experiment. 

\begin{lstlisting}[language=Python]

ec = ExperimentController(exp_id="my-exp-id")

\end{lstlisting}

The experiment id can always be retrieved as follows

\begin{lstlisting}[language=Python]

exp_id = ec.exp_id 

\end{lstlisting}

Since a same experiment can be ran more than one time, and this is 
often desirable to obtain statistical data, the EC identifies 
different runs of an experiment with a same \emph{exp\_id} with  
another attribute, the \emph{run\_id}. The \emph{run\_id} is
a timestamp string value, and in combination with the \emph{exp\_id},
it allows to uniquely identify an experiment instance.

\begin{lstlisting}[language=Python]

run_id = ec.run_id 

\end{lstlisting}



\section{The design API}

Once an ExperimentController has been instantiated, it is possible to start
describing the experiment. The design API is the set of methods which
allow to do so.


\subsection{Registering resources}

Every resource supported by NEPI is controlled by a specific ResourceManager 
(RM). The RM instances are automatically created by the EC, and the user does 
not need to interact with them directly. 

Each type of RM is associated with a \emph{type\_id} which uniquely identifies 
a concrete kind of resource (e.g PlanetLab node, application that runs in
a Linux machine, etc).
The \emph{type\_ids} are string identifiers, and they are required  
to register a resource with the EC.

To discover all the available RMs and their \emph{type\_ids} we
can make use of the ResourceFactory class.
This class is a \emph{Singleton} that holds the templates and information 
of all the RMs supported by NEPI. We can retrieve this information as follows:

\begin{lstlisting}[language=Python]

from nepi.execution.resource import ResourceFactory

for type_id in ResourceFactory.resource_types():
    rm_type = ResourceFactory.get_resource_type(type_id)
    print type_id, ":", rm_type.get_help()

\end{lstlisting}

Once the \emph{type\_id} of the resource is known, the registration of a
new resource with the EC is simple:

\begin{lstlisting}[language=Python]

type_id = "SomeRMType"
guid = ec.register_resources(type_id)

\end{lstlisting}

When a resource is registered, the EC instantiates a RM of the 
requested \emph{type\_id} and assigns a global unique identifier 
(guid) to it. The guid is an incremental integer number and it 
is the value returned by the \emph{register\_resource} method.
The EC keeps internal references to all RMs, which the user can
reference using the corresponding guid value.


\subsection{Attributes}

ResourceManagers expose the configurable parameters of resources
through a list of attributes. An attribute can be seen as a
\emph{{name:value}} pair, that represents a certain aspect of
the resource (whether information or configuration information).

It is possible to discover the list of attributes exposed by an 
RM type as follows:

\begin{lstlisting}[language=Python]
from nepi.execution.resource import ResourceFactory

type_id = "SomeRMType"
rm_type = ResourceFactory.get_resource_type(type_id)

for attr in rm_type.get_attributes():
    print "       ",  attr.name, ":", attr.help
    
\end{lstlisting}

To configure or retrieve the value of a certain attribute of
an registered resource we can use the \emph{get} and \emph{set}
methods of the EC.

\begin{lstlisting}[language=Python]

old_value = ec.get(guid, "attr_name")
ec.set(guid, "attr_name", new_value)
new_value = ec.get(guid, "attr_name")

\end{lstlisting}

Since each RM type exposes the characteristics of a particular type
of resource, it is to be expected that different RMs will have different
attributes. However, there a particular attribute that is common to all RMs.
This is the \emph{critical} attribute, and it is meant to indicate to the EC
how it should behave when a failure occurs during the experiment. 
The \emph{critical} attribute has a default value of \emph{True}, since
all resources are considered critical by default. 
When this attribute is set to \emph{False} the EC will ignore failures on that 
resource and carry on with the experiment. Otherwise, the EC will immediately 
interrupt the experiment.


\subsection{Traces}

A Trace represent a stream of data collected during the experiment and associated
to a single resource. ResourceManagers expose a list of traces, which are identified
by a name. Particular traces might or might not need activation, since some traces
are enabled by default.

It is possible to discover the list of traces exposed by an 
RM type as follows:

\begin{lstlisting}[language=Python]
from nepi.execution.resource import ResourceFactory

type_id = "SomeRMType"
rm_type = ResourceFactory.get_resource_type(type_id)

for trace in rm_type.get_traces():
    print "       ",  trace.name, ":", trace.enabled
    
\end{lstlisting}

The \emph{enable\_trace} method allows to enable a specific trace for a 
RM instance

\begin{lstlisting}[language=Python]

ec.enable_trace(guid, "trace-name")

print ec.trace_enabled(guid, "trace-name")

\end{lstlisting}


\subsection{Registering connections}

In order to describe the experiment set-up, a resources need to be 
associated at least to one another. Through the process of connecting resources
the \emph{topology graph} is constructed. A certain application might
need to be configured and executed on a certain node, and this
must be indicated to the EC by connecting the application RM to the node
RM.

Connections are registered using the \emph{register\_connection} method,
which receives the guids of the two RM.

\begin{lstlisting}[language=Python]

ec.register_connection(node_guid, app_guid)

\end{lstlisting}

The order in which the guids are given is not important, since the
\emph{topology\_graph} is not directed, and the corresponding 
RMs \emph{`know'} internally how to interpret the connection 
relationship.


\subsection{Registering conditions}

All ResourceMangers must go through the same sequence of state transitions.
Associated to those states are the actions that trigger the transitions.
As an example, a RM will initially be in the state NEW. When the DEPLOY action
is invoked, it will transition to the DISCOVERED, then PROVISIONED, then READY
states. Likewise, the action START will make a RM pass from state READY to 
STARTED, and the action STOP will change a RM from state STARTED to STOPPED.

Using these states and actions, it is possible to specify workflow dependencies 
between resources. For instance, it would be possible to indicate that
one application should start after another application by registering a 
condition with the EC.

\begin{lstlisting}[language=Python]

from nepi.execution.resource import ResourceState, ResourceActions

ec.register_condition(app1_guid, ResourceAction.START, app2_guid, ResourceState.STARTED)

\end{lstlisting}

The above invocation should be read "Application 1 should START after application 2 
has STARTED". It is also possible to indicate a relative time from the moment a state
change occurs to the moment the action should be taken as follows:

\begin{lstlisting}[language=Python]

from nepi.execution.resource import ResourceState, ResourceActions

ec.register_condition(app1_guid, ResourceAction.START, app2_guid, ResourceState.STARTED, time = "5s")

\end{lstlisting}

This line should be read "Application 1 should START at least 5 seconds after 
application 2 has STARTED". \\

Allowed actions are: DEPLOY, START and STOP. \\

Existing states are: NEW, DISCOVERED, PROVISIONED, READY, STARTED, STOPPED, 
FAILED and RELEASED. \\



\section{The execution API}

After registering all the resources and connections and setting attributes and
traces, once the experiment we want to conduct has been described, we can
proceed to run it. To this purpose we make use of the \emph{execution} methods
exposed by the EC.


\subsection{Deploying an experiment}

Deploying an experiment is very easy, it only requires to invoke the 
\emph{deploy} method of the EC.

\begin{lstlisting}[language=Python]

ec.deploy()

\end{lstlisting}

Given the experiment description provided earlier, the EC will take care
of automatically performing all necessary actions to discover, provision,
configure and start all resources registered in the experiment. 

Furthermore, NEPI does not restrict deployment to only one time, it allows
to continue to register, connect and configure resources and deploy them
at any moment. We call this feature \emph{interactive} or \emph{dynamic}
deployment. 

The \emph{deploy} method can receive other optional arguments to customize
deployment. By default, the EC will deploy all registered RMs that are in
state NEW. However, it is possible to specify a subset of resources to be
deployed using the \emph{guids} argument.

\begin{lstlisting}[language=Python]

ec.deploy(guids=[guid1, guid2, guid3])

\end{lstlisting}

Another useful argument of the \emph{deploy} method is \emph{wait\_all\_ready}.
This argument has a default value of \emph{True}, and it is used as a barrier
to force the START action to be invoked on all RMs being deploy only after
they have all reached the state READY.

\begin{lstlisting}[language=Python]

ec.deploy(wait_all_ready=False)

\end{lstlisting}


\subsection{Getting attributes}

Attribute values can be retrieved at any moment during the experiment run, 
using the \emph{get} method. 
However, not all attributes can be modified after a resource has
been deployed. The possibility of changing the value of a certain attribute 
depends strongly on the RM and on the attribute itself. 
As an example, once a \emph{hostname} has been specified for a certain Node 
RM, it might not be possible to change it after deployment.

\begin{lstlisting}[language=Python]

attr_value = ec.get(guid, "attr-name")

\end{lstlisting}

Attributes have flags that indicate whether their values can be changed
and when it is possible to change them (e.g. before or after deployment, 
or both). These flags are \emph{NoFlags} (the attribute value can be 
modified always), \emph{ReadOnly} (the attribute value can never be
modified), \emph{ExecReadOnly} (the attribute value can only be modified
before deployment). The flags of a certain attribute can be validated 
as shown in the example below, and the value of the attribute can be
changed using the \emph{set} method.  

\begin{lstlisting}[language=Python]

from nepi.execution.attribute import Flags

attr = ec.get_attribute(guid, "attr-name")

if not attr.has_flag(Flags.ReadOnly):
    ec.set(guid, "attr-name", attr_value)

\end{lstlisting}

\subsection{Quering the state}

It is possible to query the state of any resource at any moment.
The state of a resource is requested using the \emph{state} method.
This method receives the optional parameter \emph{hr} to output the
state in a \emph{human readable} string format instead of an integer
state code.

\begin{lstlisting}[language=Python]

state_id = ec.state(guid)

# Human readable state
state = ec.state(guid, hr = True)

\end{lstlisting}

\subsection{Getting traces}

After a ResourceManager has been deployed it is possible to get information
about the active traces and the trace streams of the generated data using
the \emph{trace} method.

Most traces are collected to a file in the host where they are generated, 
the total trace size and the file path in the (remote) host can be 
retrieved as follows.

\begin{lstlisting}[language=Python]

from nepi.execution.trace import TraceAttr

path = ec.trace(guid, "trace-name", TraceAttr.PATH)
size = ec.trace(guid, "trace-name", TraceAttr.SIZE)

\end{lstlisting}

The trace content can be retrieved in a stream, block by block.

\begin{lstlisting}[language=Python]

trace_block = ec.trace(guid, "trace-name", TraceAttr.STREAM, block=1, offset=0)

\end{lstlisting}

It is also possible to directly retrieve the complete trace content.

\begin{lstlisting}[language=Python]

trace_stream = ec.trace(guid, "trace-name")

\end{lstlisting}

Using the \emph{trace} method it is easy to collect all traces 
to the local user machine. 

\begin{lstlisting}[language=Python]

for trace in ec.get_traces(guid):
    trace_stream = ec.trace(guid, "trace-name")
    f = open("trace-name", "w")
    f.write(trace_stream)
    f.close()

\end{lstlisting}


% TODO: how to retrieve an application trace when the Node failed? (critical attribute)


% \subsection{The collector RM}

%%%%%%%%%%
%% TODO
%%%%%%%%%%%

\subsection{API reference}

Further information about classes and method signatures
can be found using the Python \emph{help} method.
For this inspection work, we recommend to instantiate an
ExperimentController from an IPython console. This is an
interactive console that allows to dynamically send input
to the python interpreter. 

If NEPI is not installed in the system, you will need to add the
NEPI sources path to the PYTHONPATH environmental variable 
before invoking \emph{ipython}.

\begin{lstlisting}[language=Python]

$ PYTHONPATH=$PYTHONPATH:src ipython
Python 2.7.3 (default, Jan  2 2013, 13:56:14) 
Type "copyright", "credits" or "license" for more information.


IPython 0.13.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: from nepi.execution.ec import ExperimentController

In [2]: ec = ExperimentController(exp_id="test")

In [3]: help(ec.set)

\end{lstlisting}

The example above will show the following information related to the
\emph{set} method of the EC API.

\begin{lstlisting}[language=Python]

Help on method set in module nepi.execution.ec:

set(self, guid, name, value) method of nepi.execution.ec.ExperimentController instance
    Modifies the value of the attribute with name 'name' on the RM with guid 'guid'.
    
    :param guid: Guid of the RM
    :type guid: int
    
    :param name: Name of the attribute
    :type name: str
    
    :param value: Value of the attribute

\end{lstlisting}


