Adding ability to wait on planetlab dependencies + examples.
[nepi.git] / src / nepi / testbeds / planetlab / metadata.py
index d099a8c..9f1d14f 100644 (file)
@@ -22,6 +22,7 @@ NODEIFACE = "NodeInterface"
 TUNIFACE = "TunInterface"
 TAPIFACE = "TapInterface"
 APPLICATION = "Application"
+CCNXDAEMON = "CCNxDaemon"
 DEPENDENCY = "Dependency"
 NEPIDEPENDENCY = "NepiDependency"
 NS3DEPENDENCY = "NS3Dependency"
@@ -29,14 +30,15 @@ INTERNET = "Internet"
 NETPIPE = "NetPipe"
 TUNFILTER = "TunFilter"
 CLASSQUEUEFILTER = "ClassQueueFilter"
+LOGGINGCLASSQUEUEFILTER = "LoggingClassQueueFilter"
 TOSQUEUEFILTER = "TosQueueFilter"
 MULTICASTFORWARDER = "MulticastForwarder"
 MULTICASTANNOUNCER = "MulticastAnnouncer"
 MULTICASTROUTER = "MulticastRouter"
 
-TUNFILTERS = (TUNFILTER, CLASSQUEUEFILTER, TOSQUEUEFILTER)
+TUNFILTERS = (TUNFILTER, CLASSQUEUEFILTER, LOGGINGCLASSQUEUEFILTER, TOSQUEUEFILTER)
 TAPFILTERS = (TUNFILTER, )
-ALLFILTERS = (TUNFILTER, CLASSQUEUEFILTER, TOSQUEUEFILTER)
+ALLFILTERS = (TUNFILTER, CLASSQUEUEFILTER, LOGGINGCLASSQUEUEFILTER, TOSQUEUEFILTER)
 
 PL_TESTBED_ID = "planetlab"
 
@@ -202,7 +204,7 @@ def connect_dep(testbed_instance, node_guid, app_guid, node=None, app=None):
     if app.depends:
         node.required_packages.update(set(
             app.depends.split() ))
-    
+   
     if app.add_to_path:
         if app.home_path and app.home_path not in node.pythonpath:
             node.pythonpath.append(app.home_path)
@@ -309,6 +311,11 @@ def create_classqueuefilter(testbed_instance, guid):
     element = testbed_instance._make_class_queue_filter(parameters)
     testbed_instance.elements[guid] = element
 
+def create_loggingclassqueuefilter(testbed_instance, guid):
+    parameters = testbed_instance._get_parameters(guid)
+    element = testbed_instance._make_logging_class_queue_filter(parameters)
+    testbed_instance.elements[guid] = element
+
 def create_tosqueuefilter(testbed_instance, guid):
     parameters = testbed_instance._get_parameters(guid)
     element = testbed_instance._make_tos_queue_filter(parameters)
@@ -323,6 +330,16 @@ def create_application(testbed_instance, guid):
     
     testbed_instance.elements[guid] = element
 
+def create_ccnxdaemon(testbed_instance, guid):
+    parameters = testbed_instance._get_parameters(guid)
+    element = testbed_instance._make_application(parameters,
+            clazz  = testbed_instance._app.CCNxDaemon )
+    
+    # Just inject configuration stuff
+    element.home_path = "nepi-ccnd-%s" % (guid,)
+    
+    testbed_instance.elements[guid] = element
+
 def create_dependency(testbed_instance, guid):
     parameters = testbed_instance._get_parameters(guid)
     element = testbed_instance._make_dependency(parameters)
@@ -389,6 +406,15 @@ def create_netpipe(testbed_instance, guid):
 
 ### Start/Stop functions ###
 
+def prestart_ccnxdaemon(testbed_instance, guid):
+    # ccnx daemon needs to start before the rest of the
+    # ccn applications
+    start_application(testbed_instance, guid)
+
+def stop_ccndaemon(testbed_instance, guid):
+    app = testbed_instance.elements[guid]
+    app.kill()
+
 def start_application(testbed_instance, guid):
     parameters = testbed_instance._get_parameters(guid)
     traces = testbed_instance._get_traces(guid)
@@ -414,6 +440,15 @@ def status_application(testbed_instance, guid):
     app = testbed_instance.elements[guid]
     return app.status()
 
+def status_dependency(testbed_instance, guid):
+    if guid not in testbed_instance.elements.keys():
+        return AS.STATUS_NOT_STARTED
+    
+    dep = testbed_instance.elements[guid]
+    if dep.deployed():
+        return AS.STATUS_RUNNING
+    return AS.STATUS_FINISHED
+
 ### Configure functions ###
 
 def configure_nodeiface(testbed_instance, guid):
@@ -696,7 +731,7 @@ connections = [
     }),
     dict({
         "from": (TESTBED_ID, NODE, "apps"),
-        "to":   (TESTBED_ID, (APPLICATION, MULTICASTANNOUNCER), "node"),
+        "to":   (TESTBED_ID, (APPLICATION, CCNXDAEMON, MULTICASTANNOUNCER), "node"),
         "init_code": connect_dep,
         "can_cross": False
     }),
@@ -1022,12 +1057,25 @@ attributes = dict({
                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
                 "validation_function": validation.is_number,
             }),
-            
+     "timeframe": dict({
+                "name": "timeframe",
+                "help": "Past time period in which to check information about the node. Values are year,month, week, latest", 
+                "type": Attribute.ENUM, 
+                "value": "week",
+                "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+                "allowed": ["latest",
+                            "week",
+                            "month",
+                            "year"],
+                "validation_function": validation.is_enum,
+            }),
+           
     "up": dict({
                 "name": "up",
                 "help": "Link up",
                 "type": Attribute.BOOL,
-                "value": False,
+                "value": True,
+                "flags": Attribute.NoDefaultValue, 
                 "validation_function": validation.is_bool
             }),
     "primary": dict({
@@ -1106,7 +1154,14 @@ attributes = dict({
                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
                 "validation_function": validation.is_string
             }),
-    "sudo": dict({
+    "ccnroutes": dict({
+                "name": "ccnRoutes",
+                "help": "Route can be static (e.g. udp ip) or multicast (e.g. udp 224.0.0.204 2869). To separate different route use '|' ",
+                "type": Attribute.STRING,
+                "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+                "validation_function": validation.is_string
+            }),
+     "sudo": dict({
                 "name": "sudo",
                 "help": "Run with root privileges",
                 "type": Attribute.BOOL,
@@ -1152,6 +1207,26 @@ attributes = dict({
                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
                 "validation_function": validation.is_string
             }),
+    "ccnxversion": dict({      
+                "name": "ccnxVersion",
+                "help": "Version of ccnx source code to install in the node.",
+                "type": Attribute.ENUM, 
+                "value": "ccnx-0.6.0",
+                "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+                "allowed": ["ccnx-0.6.0",
+                            "ccnx-0.5.1"],
+                "validation_function": validation.is_enum,
+            }),
+     "ccnlocalport" : dict({
+            "name" : "ccnLocalPort", 
+            "help" : "Local port to bind the ccn daemon. (i.e. CCN_LOCAL_PORT=)",
+            "type" : Attribute.INTEGER,
+            "flags" : Attribute.DesignInvisible | \
+                    Attribute.ExecInvisible | \
+                    Attribute.ExecImmutable | \
+                    Attribute.Metadata,
+            "validation_function" : validation.is_integer,
+            }),
     "build": dict({
                 "name": "build",
                 "help": "Build commands to execute after deploying the sources. "
@@ -1307,20 +1382,29 @@ traces = dict({
                 "name": "dropped_stats",
                 "help": "Information on dropped packets on a filer or queue associated to a network interface",
             }),
+    "queue_stats_f": dict({
+                "name": "queue_stats_f",
+                "help": "Detailled, fine-grained information on egress queue state, csv format.",
+            }),
+    "queue_stats_b": dict({
+                "name": "queue_stats_b",
+                "help": "Detailled, fine-grained information on ingress queue state, csv format.",
+            }),
     })
 
 create_order = [ 
-    INTERNET, NODE, NODEIFACE, CLASSQUEUEFILTER, TOSQUEUEFILTER, 
+    INTERNET, NODE, NODEIFACE, CLASSQUEUEFILTER, LOGGINGCLASSQUEUEFILTER, TOSQUEUEFILTER, 
     MULTICASTANNOUNCER, MULTICASTFORWARDER, MULTICASTROUTER, 
     TUNFILTER, TAPIFACE, TUNIFACE, NETPIPE, 
-    NEPIDEPENDENCY, NS3DEPENDENCY, DEPENDENCY, APPLICATION ]
+    NEPIDEPENDENCY, NS3DEPENDENCY, DEPENDENCY, CCNXDAEMON, APPLICATION ]
 
 configure_order = [ 
     INTERNET, Parallel(NODE), 
     NODEIFACE, 
     Parallel(MULTICASTANNOUNCER), Parallel(MULTICASTFORWARDER), Parallel(MULTICASTROUTER), 
     Parallel(TAPIFACE), Parallel(TUNIFACE), NETPIPE, 
-    Parallel(NEPIDEPENDENCY), Parallel(NS3DEPENDENCY), Parallel(DEPENDENCY), Parallel(APPLICATION) ]
+    Parallel(NEPIDEPENDENCY), Parallel(NS3DEPENDENCY), Parallel(DEPENDENCY), Parallel(CCNXDAEMON),
+    Parallel(APPLICATION)]
 
 # Start (and prestart) node after ifaces, because the node needs the ifaces in order to set up routes
 start_order = [ INTERNET, 
@@ -1328,11 +1412,13 @@ start_order = [ INTERNET,
     Parallel(TAPIFACE), Parallel(TUNIFACE), 
     Parallel(NODE), NETPIPE, 
     Parallel(MULTICASTANNOUNCER), Parallel(MULTICASTFORWARDER), Parallel(MULTICASTROUTER), 
-    Parallel(NEPIDEPENDENCY), Parallel(NS3DEPENDENCY), Parallel(DEPENDENCY), Parallel(APPLICATION) ]
+    Parallel(NEPIDEPENDENCY), Parallel(NS3DEPENDENCY), Parallel(DEPENDENCY), Parallel(CCNXDAEMON),
+    Parallel(APPLICATION)]
 
 # cleanup order
 shutdown_order = [ 
     Parallel(APPLICATION), 
+    Parallel (CCNXDAEMON),
     Parallel(MULTICASTROUTER), Parallel(MULTICASTFORWARDER), Parallel(MULTICASTANNOUNCER), 
     Parallel(TAPIFACE), Parallel(TUNIFACE), Parallel(NETPIPE), 
     Parallel(NEPIDEPENDENCY), Parallel(NS3DEPENDENCY), Parallel(DEPENDENCY), 
@@ -1359,6 +1445,7 @@ factories_info = dict({
                 "max_load",
                 "min_cpu",
                 "max_cpu",
+                "timeframe",
                 
                 # NEPI-in-NEPI attributes
                 ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,
@@ -1464,7 +1551,7 @@ factories_info = dict({
             "connector_types": ["->fd","udp","tcp"],
         }),
     CLASSQUEUEFILTER : dict({
-            "help": "TUN classfull queue, uses a separate queue for each user-definable class.\n\n"
+            "help": "TUN classful queue, uses a separate queue for each user-definable class.\n\n"
                     "It takes two arguments, both of which have sensible defaults:\n"
                     "\tsize: the base size of each class' queue\n"
                     "\tclasses: the class definitions, which follow the following syntax:\n"
@@ -1498,6 +1585,18 @@ factories_info = dict({
             "connector_types": ["->fd","udp","tcp"],
             "traces": ["dropped_stats"],
         }),
+    LOGGINGCLASSQUEUEFILTER : dict({
+            "help": "TUN classful queue, uses a separate queue for each user-definable class.\n"
+                    "See ClassQueueFilter. This version adds detailled queue state tracing.",
+            "category": FC.CATEGORY_CHANNELS,
+            "create_function": create_loggingclassqueuefilter,
+            "box_attributes": [
+                "args",
+                "tun_proto", "tun_addr", "tun_port", "tun_key", "tun_cipher",
+            ],
+            "connector_types": ["->fd","udp","tcp"],
+            "traces": ["dropped_stats","queue_stats_f","queue_stats_b"],
+        }),
     TOSQUEUEFILTER : dict({
             "help": "TUN classfull queue that classifies according to the TOS (RFC 791) IP field.\n\n"
                     "It takes a size argument that specifies the size of each class. As TOS is a "
@@ -1526,11 +1625,27 @@ factories_info = dict({
             "traces": ["stdout", "stderr", "buildlog", "output"],
             "tags": [tags.APPLICATION],
         }),
+
+    CCNXDAEMON: dict({
+            "help": "CCNx daemon",
+            "category": FC.CATEGORY_APPLICATIONS,
+            "create_function": create_ccnxdaemon,
+            "prestart_function": prestart_ccnxdaemon,
+            "status_function": status_application,
+            "stop_function": stop_application,
+            "configure_function": configure_application,
+            "box_attributes": ["ccnroutes", "build", "ccnlocalport",
+                "install", "ccnxversion", "sources"],
+            "connector_types": ["node"],
+            "traces": ["stdout", "stderr", "buildlog", "output"],
+            "tags": [tags.APPLICATION],
+        }),
     DEPENDENCY: dict({
             "help": "Requirement for package or application to be installed on some node",
             "category": FC.CATEGORY_APPLICATIONS,
             "create_function": create_dependency,
             "preconfigure_function": configure_dependency,
+            "status_function": status_dependency,
             "box_attributes": ["depends", "build-depends", "build", "install",
                                "sources", "rpm-fusion" ],
             "connector_types": ["node"],
@@ -1621,6 +1736,20 @@ factories_info = dict({
 })
 
 testbed_attributes = dict({
+        "slice_hrn": dict({
+            "name": "sliceHrn",
+            "help": "The hierarchical Resource Name (HRN) for the PlanetLab slice.",
+            "type": Attribute.STRING,
+            "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable | Attribute.NoDefaultValue,
+            "validation_function": validation.is_string
+        }),
+        "sfa": dict({
+            "name": "sfa",
+            "help": "Activates the use of SFA for node reservation.",
+            "type": Attribute.BOOL,
+            "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable | Attribute.NoDefaultValue,
+            "validation_function": validation.is_bool
+        }),
         "slice": dict({
             "name": "slice",
             "help": "The name of the PlanetLab slice to use",
@@ -1689,7 +1818,7 @@ testbed_attributes = dict({
         "pl_log_level": dict({      
             "name": "plLogLevel",
             "help": "Verbosity of logging of planetlab events.",
-            "value": "ERROR",
+            "value": "INFO",
             "type": Attribute.ENUM, 
             "allowed": ["DEBUG",
                         "INFO",
@@ -1706,16 +1835,26 @@ testbed_attributes = dict({
             "range": (2000,30000),
             "validation_function": validation.is_integer_range(2000,30000)
         }),
-        "dedicated_slice": dict({
-            "name": "dedicatedSlice",
+        "clean_proc": dict({
+            "name": "cleanProc",
             "help": "Set to True if the slice will be dedicated to this experiment. "
-                    "NEPI will perform node and slice cleanup, making sure slices are "
+                    "NEPI will perform node and slice process cleanup, making sure slices are "
                     "in a clean, repeatable state before running the experiment.",
             "type": Attribute.BOOL,
             "value": False,
             "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
             "validation_function": validation.is_bool
         }),
+        "clean_home": dict({
+            "name": "cleanHome",
+            "help": "Set to True all preexistent directories in the home "
+                    "directory of each sliver will be removed before the "
+                    "start of the experiment.",
+            "type": Attribute.BOOL,
+            "value": False,
+            "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+            "validation_function": validation.is_bool
+        }),
     })
 
 supported_recovery_policies = [