Scripts to automate creation of ns-3 RMs from metadata
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Thu, 30 Jan 2014 18:07:47 +0000 (19:07 +0100)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Thu, 30 Jan 2014 18:07:47 +0000 (19:07 +0100)
src/nepi/execution/attribute.py
src/nepi/resources/linux/ns3/simulator.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3_base.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3wrapper.py
src/nepi/resources/ns3/rm_creator.py [new file with mode: 0644]
src/nepi/resources/ns3/templates/attribute_template.txt [new file with mode: 0644]
src/nepi/resources/ns3/templates/rm_template.txt [new file with mode: 0644]
src/nepi/resources/ns3/templates/trace_template.txt [new file with mode: 0644]

index e9f4c54..a82274a 100644 (file)
@@ -37,8 +37,10 @@ class Flags:
     # Attribute is not modifiable by the user during runtime
     ExecReadOnly        = 0x02
     # Attribute is an access credential
+    # TODO REMOVE!!!
     Credential      = 0x04
     # Attribute is a filter used to discover resources
+    # TODO REMOVE!!!
     Filter      = 0x08
 
 class Attribute(object):
diff --git a/src/nepi/resources/linux/ns3/simulator.py b/src/nepi/resources/linux/ns3/simulator.py
new file mode 100644 (file)
index 0000000..82d4bca
--- /dev/null
@@ -0,0 +1,284 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.linux.node import OSType
+from nepi.util.timefuncs import tnow, tdiffsec
+from nepi.resources.ns3.simulator import NS3Simulator
+
+import os
+
+@clsinit_copy
+class LinuxNS3Simulator(LinuxApplication, NS3Simulator):
+    _rtype = "LinuxSimulator"
+
+    @classmethod
+    def _register_attributes(cls):
+        max_rte = Attribute("maxRteMicrosec",
+            "Sets the CCND_MAX_RTE_MICROSEC environmental variable. ",
+            flags = Flags.ExecReadOnly)
+
+        keystore = Attribute("keyStoreDirectory",
+            "Sets the CCND_KEYSTORE_DIRECTORY environmental variable. ",
+            flags = Flags.ExecReadOnly)
+
+        cls._register_attribute(debug)
+        cls._register_attribute(port)
+
+    @classmethod
+    def _register_traces(cls):
+        log = Trace("log", "CCND log output")
+        status = Trace("status", "ccndstatus output")
+
+        cls._register_trace(log)
+        cls._register_trace(status)
+
+    def __init__(self, ec, guid):
+        super(LinuxCCND, self).__init__(ec, guid)
+        self._home = "ccnd-%s" % self.guid
+        self._version = "ccnx"
+
+    @property
+    def version(self):
+        return self._version
+
+    @property
+    def path(self):
+        return "PATH=$PATH:${BIN}/%s/" % self.version 
+
+    def do_deploy(self):
+        if not self.node or self.node.state < ResourceState.READY:
+            self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state )
+            
+            # ccnd needs to wait until node is deployed and running
+            self.ec.schedule(reschedule_delay, self.deploy)
+        else:
+            if not self.get("command"):
+                self.set("command", self._start_command)
+            
+            if not self.get("depends"):
+                self.set("depends", self._dependencies)
+
+            if not self.get("sources"):
+                self.set("sources", self._sources)
+
+            sources = self.get("sources")
+            source = sources.split(" ")[0]
+            basename = os.path.basename(source)
+            self._version = ( basename.strip().replace(".tar.gz", "")
+                    .replace(".tar","")
+                    .replace(".gz","")
+                    .replace(".zip","") )
+
+            if not self.get("build"):
+                self.set("build", self._build)
+
+            if not self.get("install"):
+                self.set("install", self._install)
+
+            if not self.get("env"):
+                self.set("env", self._environment)
+
+            command = self.get("command")
+
+            self.info("Deploying command '%s' " % command)
+
+            self.do_discover()
+            self.do_provision()
+
+            self.debug("----- READY ---- ")
+            self.set_ready()
+
+    def upload_start_command(self):
+        command = self.get("command")
+        env = self.get("env")
+
+        # We want to make sure the ccnd is running
+        # before the experiment starts.
+        # Run the command as a bash script in background,
+        # in the host ( but wait until the command has
+        # finished to continue )
+        env = self.replace_paths(env)
+        command = self.replace_paths(command)
+
+        shfile = os.path.join(self.app_home, "start.sh")
+        self.node.run_and_wait(command, self.run_home,
+                shfile = shfile,
+                overwrite = False,
+                env = env,
+                raise_on_error = True)
+
+    def do_start(self):
+        if self.state == ResourceState.READY:
+            command = self.get("command")
+            self.info("Starting command '%s'" % command)
+
+            self.set_started()
+        else:
+            msg = " Failed to execute command '%s'" % command
+            self.error(msg, out, err)
+            raise RuntimeError, msg
+
+    def do_stop(self):
+        command = self.get('command') or ''
+        
+        if self.state == ResourceState.STARTED:
+            self.info("Stopping command '%s'" % command)
+
+            command = "ccndstop"
+            env = self.get("env") 
+
+            # replace application specific paths in the command
+            command = self.replace_paths(command)
+            env = env and self.replace_paths(env)
+
+            # Upload the command to a file, and execute asynchronously
+            shfile = os.path.join(self.app_home, "stop.sh")
+            self.node.run_and_wait(command, self.run_home,
+                        shfile = shfile,
+                        overwrite = False,
+                        env = env,
+                        pidfile = "ccndstop_pidfile", 
+                        ecodefile = "ccndstop_exitcode", 
+                        stdout = "ccndstop_stdout", 
+                        stderr = "ccndstop_stderr")
+
+            self.set_stopped()
+    
+    @property
+    def state(self):
+        # First check if the ccnd has failed
+        state_check_delay = 0.5
+        if self._state == ResourceState.STARTED and \
+                tdiffsec(tnow(), self._last_state_check) > state_check_delay:
+            (out, err), proc = self._ccndstatus()
+
+            retcode = proc.poll()
+
+            if retcode == 1 and err.find("No such file or directory") > -1:
+                # ccnd is not running (socket not found)
+                self.set_stopped()
+            elif retcode:
+                # other errors ...
+                msg = " Failed to execute command '%s'" % self.get("command")
+                self.error(msg, out, err)
+                self.fail()
+
+            self._last_state_check = tnow()
+
+        return self._state
+
+    def _ccndstatus(self):
+        env = self.get('env') or ""
+        environ = self.node.format_environment(env, inline = True)
+        command = environ + " ccndstatus"
+        command = self.replace_paths(command)
+    
+        return self.node.execute(command)
+
+    @property
+    def _start_command(self):
+        return "ccndstart"
+
+    @property
+    def _dependencies(self):
+        if self.node.use_rpm:
+            return ( " autoconf openssl-devel  expat-devel libpcap-devel "
+                " ecryptfs-utils-devel libxml2-devel automake gawk " 
+                " gcc gcc-c++ git pcre-devel make ")
+        elif self.node.use_deb:
+            return ( " autoconf libssl-dev libexpat-dev libpcap-dev "
+                " libecryptfs0 libxml2-utils automake gawk gcc g++ "
+                " git-core pkg-config libpcre3-dev make ")
+        return ""
+
+    @property
+    def _sources(self):
+        return "http://www.ccnx.org/releases/ccnx-0.7.2.tar.gz"
+
+    @property
+    def _build(self):
+        sources = self.get("sources").split(" ")[0]
+        sources = os.path.basename(sources)
+
+        return (
+            # Evaluate if ccnx binaries are already installed
+            " ( "
+                " test -f ${BIN}/%(version)s/ccnd && "
+                " echo 'binaries found, nothing to do' "
+            " ) || ( "
+            # If not, untar and build
+                " ( "
+                    " mkdir -p ${SRC}/%(version)s && "
+                    " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/%(version)s "
+                 " ) && "
+                    "cd ${SRC}/%(version)s && "
+                    # Just execute and silence warnings...
+                    " ( ./configure && make ) "
+             " )") % ({ 'sources': sources,
+                        'version': self.version
+                 })
+
+    @property
+    def _install(self):
+        return (
+            # Evaluate if ccnx binaries are already installed
+            " ( "
+                " test -f ${BIN}/%(version)s/ccnd && "
+                " echo 'binaries found, nothing to do' "
+            " ) || ( "
+            # If not, install
+                "  mkdir -p ${BIN}/%(version)s && "
+                "  mv ${SRC}/%(version)s/bin/* ${BIN}/%(version)s/ "
+            " )"
+            ) % ({ 'version': self.version
+                 })
+
+    @property
+    def _environment(self):
+        envs = dict({
+            "debug": "CCND_DEBUG",
+            "port": "CCN_LOCAL_PORT",
+            "sockname" : "CCN_LOCAL_SOCKNAME",
+            "capacity" : "CCND_CAP",
+            "mtu" : "CCND_MTU",
+            "dataPauseMicrosec" : "CCND_DATA_PAUSE_MICROSEC",
+            "defaultTimeToStale" : "CCND_DEFAULT_TIME_TO_STALE",
+            "maxTimeToStale" : "CCND_MAX_TIME_TO_STALE",
+            "maxRteMicrosec" : "CCND_MAX_RTE_MICROSEC",
+            "keyStoreDirectory" : "CCND_KEYSTORE_DIRECTORY",
+            "listenOn" : "CCND_LISTEN_ON",
+            "autoreg" : "CCND_AUTOREG",
+            "prefix" : "CCND_PREFIX",
+            })
+
+        env = self.path 
+        env += " ".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))) \
+            if self.get(k) else "", envs.keys()))
+        
+        return env            
+
+    def valid_connection(self, guid):
+        # TODO: Validate!
+        return True
+
diff --git a/src/nepi/resources/ns3/ns3_base.py b/src/nepi/resources/ns3/ns3_base.py
new file mode 100644 (file)
index 0000000..c829a4f
--- /dev/null
@@ -0,0 +1,72 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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>
+
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+
+from nepi.resources.ns3.simulator import NS3Simulator
+
+@clsinit_copy
+class NS3Base(ResourceManager):
+    _rtype = "NS3Base"
+
+    @property
+    def simulator(self):
+        simulator = self.get_connected(NS3Simulator.get_rtype())
+        if simulator: return simulator[0]
+        return None
+
+    def do_deploy(self):
+        if not self.simulator or self.simulator.state < ResourceState.READY:
+            self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.simulator.state )
+            
+            # ccnd needs to wait until node is deployed and running
+            self.ec.schedule(reschedule_delay, self.deploy)
+        else:
+            # TODO: CREATE AND CONFIGURE NS-3 C++ OBJECT
+            self.do_discover()
+            self.do_provision()
+
+            self.debug("----- READY ---- ")
+            self.set_ready()
+
+    def do_start(self):
+        if self.state == ResourceState.READY:
+            ## TODO!!!
+            self.info("Starting ...")
+
+            self.set_started()
+        else:
+            msg = " Failed "
+            self.error(msg, out, err)
+            raise RuntimeError, msg
+
+    def do_stop(self):
+        if self.state == ResourceState.STARTED:
+            self.info("Stopping command '%s'" % command)
+            ## TODO!!!
+
+            self.set_stopped()
+    
+    @property
+    def state(self):
+        # First check if the ccnd has failed
+        # TODO!!!
+        return self._state
+
index b8fa5bc..f6c063b 100644 (file)
@@ -30,6 +30,66 @@ import uuid
 
 SINGLETON = "singleton::"
 
+def load_ns3_module():
+    import ctypes
+    import imp
+    import re
+    import pkgutil
+
+    bindings = os.environ.get("NS3BINDINGS")
+    libdir = os.environ.get("NS3LIBRARIES")
+
+    # Load the ns-3 modules shared libraries
+    if libdir:
+        files = os.listdir(libdir)
+        regex = re.compile("(.*\.so)$")
+        libs = [m.group(1) for filename in files for m in [regex.search(filename)] if m]
+
+        libscp = list(libs)
+        while len(libs) > 0:
+            for lib in libs:
+                libfile = os.path.join(libdir, lib)
+                try:
+                    ctypes.CDLL(libfile, ctypes.RTLD_GLOBAL)
+                    libs.remove(lib)
+                except:
+                    pass
+
+            # if did not load any libraries in the last iteration break
+            # to prevent infinit loop
+            if len(libscp) == len(libs):
+                raise RuntimeError("Imposible to load shared libraries %s" % str(libs))
+            libscp = list(libs)
+
+    # import the python bindings for the ns-3 modules
+    if bindings:
+        sys.path.append(bindings)
+
+    # create a module to add all ns3 classes
+    ns3mod = imp.new_module("ns3")
+    sys.modules["ns3"] = ns3mod
+
+    # retrieve all ns3 classes and add them to the ns3 module
+    import ns
+
+    for importer, modname, ispkg in pkgutil.iter_modules(ns.__path__):
+        fullmodname = "ns.%s" % modname
+        module = __import__(fullmodname, globals(), locals(), ['*'])
+
+        for sattr in dir(module):
+            if sattr.startswith("_"):
+                continue
+
+            attr = getattr(module, sattr)
+
+            # netanim.Config and lte.Config singleton overrides ns3::Config
+            if sattr == "Config" and modname in ['netanim', 'lte']:
+                sattr = "%s.%s" % (modname, sattr)
+
+            setattr(ns3mod, sattr, attr)
+
+    return ns3mod
+
 class NS3Wrapper(object):
     def __init__(self, homedir = None):
         super(NS3Wrapper, self).__init__()
@@ -68,12 +128,12 @@ class NS3Wrapper(object):
 
         # Python module to refernce all ns-3 classes and types
         self._ns3 = None
-
-        # Load ns-3 shared libraries and import modules
-        self._load_ns3_module()
         
     @property
     def ns3(self):
+        if not self._ns3:
+            self._ns3 = load_ns3_module()
+
         return self._ns3
 
     @property
@@ -337,67 +397,4 @@ class NS3Wrapper(object):
                 str(arg).startswith(SINGLETON) else arg for arg in realargs]
 
         return realargs
-    def _load_ns3_module(self):
-        if self.ns3:
-            return 
-
-        import ctypes
-        import imp
-        import re
-        import pkgutil
-
-        bindings = os.environ.get("NS3BINDINGS")
-        libdir = os.environ.get("NS3LIBRARIES")
-
-        # Load the ns-3 modules shared libraries
-        if libdir:
-            files = os.listdir(libdir)
-            regex = re.compile("(.*\.so)$")
-            libs = [m.group(1) for filename in files for m in [regex.search(filename)] if m]
-
-            libscp = list(libs)
-            while len(libs) > 0:
-                for lib in libs:
-                    libfile = os.path.join(libdir, lib)
-                    try:
-                        ctypes.CDLL(libfile, ctypes.RTLD_GLOBAL)
-                        libs.remove(lib)
-                    except:
-                        pass
-
-                # if did not load any libraries in the last iteration break
-                # to prevent infinit loop
-                if len(libscp) == len(libs):
-                    raise RuntimeError("Imposible to load shared libraries %s" % str(libs))
-                libscp = list(libs)
-
-        # import the python bindings for the ns-3 modules
-        if bindings:
-            sys.path.append(bindings)
-
-        # create a module to add all ns3 classes
-        ns3mod = imp.new_module("ns3")
-        sys.modules["ns3"] = ns3mod
-
-        # retrieve all ns3 classes and add them to the ns3 module
-        import ns
-
-        for importer, modname, ispkg in pkgutil.iter_modules(ns.__path__):
-            fullmodname = "ns.%s" % modname
-            module = __import__(fullmodname, globals(), locals(), ['*'])
-
-            for sattr in dir(module):
-                if sattr.startswith("_"):
-                    continue
-
-                attr = getattr(module, sattr)
-
-                # netanim.Config and lte.Config singleton overrides ns3::Config
-                if sattr == "Config" and modname in ['netanim', 'lte']:
-                    sattr = "%s.%s" % (modname, sattr)
-
-                setattr(ns3mod, sattr, attr)
-
-        self._ns3 = ns3mod
 
diff --git a/src/nepi/resources/ns3/rm_creator.py b/src/nepi/resources/ns3/rm_creator.py
new file mode 100644 (file)
index 0000000..3b3cb8d
--- /dev/null
@@ -0,0 +1,162 @@
+#
+#    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 as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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>
+
+from nepi.resources.ns3.ns3wrapper import load_ns3_module
+
+import os
+import re
+
+def dump_ns3_rms():
+    ns3 = load_ns3_module()
+
+    type_id = ns3.TypeId()
+    
+    tid_count = type_id.GetRegisteredN()
+    base = type_id.LookupByName("ns3::Object")
+
+    # Create a .py file using the ns-3 RM template for each ns-3 TypeId
+    for i in xrange(tid_count):
+        tid = type_id.GetRegistered(i)
+        
+        if tid.MustHideFromDocumentation() or \
+                not tid.HasConstructor() or \
+                not tid.IsChildOf(base): 
+            continue
+       
+        attributes = template_attributes(ns3, tid)
+        traces = template_traces(ns3, tid)
+        ptid = tid
+        while ptid.HasParent():
+            ptid = ptid.GetParent()
+            attributes += template_attributes(ns3, ptid)
+            traces += template_traces(ns3, ptid)
+
+        attributes = "\n" + attributes if attributes else "pass"
+        traces = "\n" + traces if traces else "pass"
+
+        rtype = tid.GetName()
+        category = tid.GetGroupName()
+        classname = rtype.replace("ns3::", "NS3").replace("::","")
+        uncamm_rtype = re.sub('([a-z])([A-Z])', r'\1-\2', rtype).lower()
+        short_rtype = uncamm_rtype.replace("::","-")
+
+        d = os.path.dirname(os.path.realpath(__file__))
+        ftemp = open(os.path.join(d, "templates", "rm_template.txt"), "r")
+        template = ftemp.read()
+        ftemp.close()
+
+        template = template. \
+                replace("<CLASS_NAME>", classname). \
+                replace("<RTYPE>", rtype). \
+                replace("<ATTRIBUTES>", attributes). \
+                replace("<TRACES>", traces). \
+                replace("<SHORT-RTYPE>", short_rtype)
+
+        fname = uncamm_rtype.replace('ns3::', ''). \
+                replace('::', ''). \
+                replace("-","_").lower() + ".py"
+
+        f = open(os.path.join(d, fname), "w")
+        print os.path.join(d, fname)
+        print template
+        #f.write(template)
+        f.close()
+
+def template_attributes(ns3, tid): 
+    d = os.path.dirname(os.path.realpath(__file__))
+    ftemp = open(os.path.join(d, "templates", "attribute_template.txt"), "r")
+    template = ftemp.read()
+    ftemp.close()
+
+    attributes = ""
+
+    attr_count = tid.GetAttributeN()
+    for i in xrange(attr_count):
+        attr_info = tid.GetAttribute(i)
+        if not attr_info.accessor.HasGetter():
+            continue
+
+        attr_flags = "None"
+        flags = attr_info.flags
+        if (flags & ns3.TypeId.ATTR_SET) != ns3.TypeId.ATTR_SET:
+            attr_flags = "Types.ExecReadOnly"
+
+        attr_name = attr_info.name
+        checker = attr_info.checker
+        attr_help = attr_info.help
+        value = attr_info.initialValue
+        attr_value = value.SerializeToString(checker)
+        attr_allowed = "None"
+        attr_range = "None"
+        attr_type = "Types.STRING"
+
+        if isinstance(value, ns3.ObjectVectorValue):
+            continue
+        elif isinstance(value, ns3.PointerValue):
+            continue
+        elif isinstance(value, ns3.WaypointValue):
+            continue
+        elif isinstance(value, ns3.BooleanValue):
+            attr_type = "Types.BOOL"
+            attr_value = "True" if attr_value == "true" else "False"
+        elif isinstance(value, ns3.EnumValue):
+            attr_type = "Types.ENUM"
+            attr_allowed = "[%s]"% checker.GetUnderlyingTypeInformation().replace("|", ",")
+        elif isinstance(value, ns3.DoubleValue):
+            attr_type = "Types.DOUBLE"
+            # TODO: range
+        elif isinstance(value, ns3.UintegerValue):
+            attr_type = "Types.INTEGER"
+            # TODO: range
+
+        attr_id = attr_name.lower()
+        attributes += template.replace("<ATTR_ID>", attr_id) \
+                .replace("<ATTR_NAME>", attr_name) \
+                .replace("<ATTR_HELP>", attr_help) \
+                .replace("<ATTR_TYPE>", attr_type) \
+                .replace("<ATTR_DEFAULT>", attr_value) \
+                .replace("<ATTR_ALLOWED>", attr_allowed) \
+                .replace("<ATTR_RANGE>", attr_range) \
+                .replace("<ATTR_FLAGS>", attr_flags) 
+
+    return attributes
+
+def template_traces(ns3, tid): 
+    d = os.path.dirname(os.path.realpath(__file__))
+    ftemp = open(os.path.join(d, "templates", "trace_template.txt"), "r")
+    template = ftemp.read()
+    ftemp.close()
+
+    traces = ""
+
+    trace_count = tid.GetTraceSourceN()
+    for i in xrange(trace_count):
+        trace_info = tid.GetTraceSource(i)
+        trace_name = trace_info.name
+        trace_help = trace_info.help
+
+        trace_id = trace_name.lower()
+        traces += template.replace("<TRACE_ID>", trace_id) \
+                .replace("<TRACE_NAME>", trace_name) \
+                .replace("<TRACE_HELP>", trace_help) 
+
+    return traces
+
+if __name__ == "__main__":
+    dump_ns3_rms()
diff --git a/src/nepi/resources/ns3/templates/attribute_template.txt b/src/nepi/resources/ns3/templates/attribute_template.txt
new file mode 100644 (file)
index 0000000..f34daa3
--- /dev/null
@@ -0,0 +1,10 @@
+        <ATTR_ID> = Attribute("<ATTR_NAME>",
+            "<ATTR_HELP>",
+            type = <ATTR_TYPE>,
+            default = <ATTR_DEFAULT>, 
+            allowed = <ATTR_ALLOWED>,
+            range = <ATTR_RANGE>,    
+            flags = <ATTR_FLAGS>)
+
+        cls._register_attribute(<ATTR_ID>)
+
diff --git a/src/nepi/resources/ns3/templates/rm_template.txt b/src/nepi/resources/ns3/templates/rm_template.txt
new file mode 100644 (file)
index 0000000..08447c8
--- /dev/null
@@ -0,0 +1,46 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3_base import NS3Base
+
+@clsinit_copy
+class <CLASS_NAME>(NS3Base):
+    _rtype = "<RTYPE>"
+
+    @classmethod
+    def _register_attributes(cls):
+        <ATTRIBUTES>
+
+    @classmethod
+    def _register_traces(cls):
+        <TRACES>
+
+    def __init__(self, ec, guid):
+        super(<CLASS_NAME>, self).__init__(ec, guid)
+        self._home = "<SHORT-RTYPE>-%s" % self.guid
+        # TODO!
+        self._version = None
+
+    @property
+    def version(self):
+        return self._version
+
diff --git a/src/nepi/resources/ns3/templates/trace_template.txt b/src/nepi/resources/ns3/templates/trace_template.txt
new file mode 100644 (file)
index 0000000..9cedb1e
--- /dev/null
@@ -0,0 +1,4 @@
+        <TRACE_ID> = Trace("<TRACE_NAME>", "<TRACE_HELP>")
+
+        cls._register_trace(<TRACE_ID>)
+