Changed emulator design and started to create the emuvim Mininet wrapper layer.
authorpeusterm <manuel.peuster@uni-paderborn.de>
Mon, 28 Dec 2015 10:33:42 +0000 (11:33 +0100)
committerpeusterm <manuel.peuster@uni-paderborn.de>
Mon, 28 Dec 2015 10:33:42 +0000 (11:33 +0100)
dockernetrpc/example_client.py
dockernetrpc/rpc.py
emuvim/__init__.py [deleted file]
emuvim/api/__init__.py [new file with mode: 0644]
emuvim/cli/__init__.py [new file with mode: 0644]
emuvim/cli/__main__.py [new file with mode: 0644]
emuvim/dcemulator/__init__.py [new file with mode: 0644]
emuvim/dcemulator/link.py [new file with mode: 0644]
emuvim/dcemulator/net.py [new file with mode: 0644]
emuvim/dcemulator/node.py [new file with mode: 0644]
emuvim/example_topology.py [new file with mode: 0644]

index 213905c..5a5379a 100644 (file)
@@ -1,38 +1,40 @@
-import Pyro4
 import time
+import zerorpc
 
 
 def main():
     # create connection to remote Mininet instance
-    rmn = Pyro4.Proxy("PYRONAME:remote.mininet")
+    c = zerorpc.Client()
+    c.connect("tcp://127.0.0.1:4242")
 
     # do some API tests
-    h1 = rmn.addHost('h1')
-    h2 = rmn.addHost('h2')
-    d1 = rmn.addDocker('d1', ip='10.0.0.253', dimage="ubuntu")
+    h1 = c.addHost('h1')
+    h2 = c.addHost('h2')
+    d1 = c.addDocker('d1', "ubuntu", "10.0.0.253")
 
-    s1 = rmn.addSwitch("s1")
+    s1 = c.addSwitch("s1")
 
-    rmn.addLink(h1, s1)
-    rmn.addLink(h2, s1)
-    rmn.addLink(d1, s1)
+    c.addLink(h1, s1)
+    c.addLink(h2, s1)
+    c.addLink(d1, s1)
 
-    rmn.start()
+    c.start_net()
+    c.CLI()
 
     # check functionality at runtime
     """
-    d2 = rmn.addDocker('d2', dimage="ubuntu")
-    h3 = rmn.addHost('h3', ip='10.0.0.200')
-    rmn.addLink(d2, s1, params1={"ip": "10.0.0.251/8"})
+    d2 = c.addDocker('d2', dimage="ubuntu")
+    h3 = c.addHost('h3', ip='10.0.0.200')
+    c.addLink(d2, s1, params1={"ip": "10.0.0.251/8"})
 
     time.sleep(2)
-    rmn.removeLink(node1="h1", node2="s1")
-    rmn.removeHost('h1')
-    #rmn.removeHost('d1')
+    c.removeLink(node1="h1", node2="s1")
+    c.removeHost('h1')
+    #c.removeHost('d1')
     """
 
     time.sleep(2)
-    rmn.stop()
+    c.stop_net()
 
 
 if __name__ == '__main__':
index c649d77..f145b53 100644 (file)
@@ -6,47 +6,46 @@ from mininet.cli import CLI
 import mininet.log
 import logging
 import os
-import Pyro4
+import zerorpc
 
 
 class RemoteMininetNetwork(object):
 
     def __init__(self):
-        mininet.log.setLogLevel( 'debug' )
+        # set mininet loglevel
+        mininet.log.setLogLevel( 'info' )
         self.net = Mininet( controller=Controller )
         self.net.addController( 'c0' )
 
-    def start(self):
+    def start_net(self):
         self.net.start()
 
     def CLI(self):
         CLI(self.net)
 
-    def stop(self):
+    def stop_net(self):
         try:
             self.net.stop()
         except Exception as e:
             print e
 
+    def addHost(self, name, ip=None):
+        return str(self.net.addHost(name, ip=ip))
 
-    def addHost(self, name, cls=None, **params):
-        return str(self.net.addHost(name, cls=cls, **params))
+    def addDocker(self, name, dimage, ip):
+        return str(self.net.addDocker(name, dimage=dimage, ip=ip))
 
-    def addDocker(self, name, **params):
-        return str(self.net.addDocker(name, **params))
-
-    def addSwitch(self, name, **params):
+    def addSwitch(self, name):
         # we have to use OVSSwitch to be able to do link attachments
         # at runtime (switch.attach) method
-        return str(self.net.addSwitch(name, cls=OVSSwitch, **params))
+        return str(self.net.addSwitch(name, cls=OVSSwitch))
 
-    def addLink(self, node1, node2, port1=None, port2=None,
-                cls=None, **params):
+    def addLink(self, node1, node2, port1=None, port2=None):
         return str(self.net.addLink(node1, node2,
-                                    port1, port2, cls=cls, **params))
+                                    port1, port2))
 
-    def removeHost(self, name, **params):
-        return self.net.removeHost(name, **params)
+    def removeHost(self, name):
+        return self.net.removeHost(name)
 
     def removeLink(self, link=None, node1=None, node2=None):
         n1, n2 = self.net.get(node1), self.net.get(node2)
@@ -54,15 +53,6 @@ class RemoteMininetNetwork(object):
 
 
 def start_server():
-    daemon = Pyro4.Daemon()
-    # ATTENTION:
-    # we need a PyroNS instance to be running: pyro4-ns (in new terminal)
-    ns = Pyro4.locateNS()
-    uri = daemon.register(RemoteMininetNetwork())
-    # map object URI to a nice name
-    ns.register("remote.mininet", uri)
-
-    logging.info("Server URI is: %s", uri)
-
-    # Start the server...
-    daemon.requestLoop()
+    s = zerorpc.Server(RemoteMininetNetwork())
+    s.bind("tcp://0.0.0.0:4242")
+    s.run()
diff --git a/emuvim/__init__.py b/emuvim/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/emuvim/api/__init__.py b/emuvim/api/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/emuvim/cli/__init__.py b/emuvim/cli/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/emuvim/cli/__main__.py b/emuvim/cli/__main__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/emuvim/dcemulator/__init__.py b/emuvim/dcemulator/__init__.py
new file mode 100644 (file)
index 0000000..64f6616
--- /dev/null
@@ -0,0 +1,4 @@
+"""
+Distributed Cloud Emulator (dcemulator)
+(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
+"""
\ No newline at end of file
diff --git a/emuvim/dcemulator/link.py b/emuvim/dcemulator/link.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/emuvim/dcemulator/net.py b/emuvim/dcemulator/net.py
new file mode 100644 (file)
index 0000000..8ea41a7
--- /dev/null
@@ -0,0 +1,88 @@
+"""
+Distributed Cloud Emulator (dcemulator)
+(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
+"""
+import logging
+
+from mininet.net import Mininet
+from mininet.node import Controller, OVSKernelSwitch, Switch
+from mininet.cli import CLI
+from mininet.log import setLogLevel, info
+from mininet.link import TCLink, Link
+
+from node import Datacenter
+
+
+class DCNetwork(object):
+
+    def __init__(self):
+        self.dcs = {}
+        self.switches = {}
+        self.links = []
+
+        # create a Mininet/Dockernet network
+        setLogLevel('info')  # set Mininet loglevel
+        self.mnet = Mininet(controller=Controller, switch=OVSKernelSwitch)
+        self.mnet.addController('c0')
+
+    def addDatacenter(self, name):
+        """
+        Create and add a logical cloud data center to the network.
+        """
+        if name in self.dcs:
+            raise Exception("Data center name already exists: %s" % name)
+        dc = Datacenter(name)
+        dc.net = self  # set reference to network
+        self.dcs[name] = dc
+        dc.create()  # finally create the data center in our Mininet instance
+        logging.info("added data center: %s" % name)
+        return dc
+
+    def addSwitch(self, name):
+        """
+        We can also add additional SDN switches between data centers.
+        """
+        s = self.mnet.addSwitch(name)
+        self.switches[name] = s
+        logging.info("added switch: %s" % name)
+        return s
+
+    def addLink(self, node1, node2):
+        assert node1 is not None
+        assert node2 is not None
+        # ensure type of node1
+        if isinstance( node1, basestring ):
+            if node1 in self.dcs:
+                node1 = self.dcs[node1].switch
+            elif node1 in self.switches:
+                node1 = self.switches[node1]
+        if isinstance( node1, Datacenter ):
+            node1 = node1.switch
+        # ensure type of node2
+        if isinstance( node2, basestring ):
+            if node2 in self.dcs:
+                node2 = self.dcs[node2].switch
+            elif node2 in self.switches:
+                node2 = self.switches[node2]
+        if isinstance( node2, Datacenter ):
+            node2 = node2.switch
+        # create link if everything is correct
+        if (node1 is not None and isinstance(node1, OVSKernelSwitch)
+                and node2 is not None and isinstance(node2, OVSKernelSwitch)):
+            self.mnet.addLink(node1, node2)  # TODO we need TCLinks with user defined performance her
+        else:
+            raise Exception(
+                "one of the given nodes is not a Mininet switch or None")
+
+    def start(self):
+        # start
+        for dc in self.dcs.itervalues():
+            dc.start()
+        self.mnet.start()
+
+    def stop(self):
+        self.mnet.stop()
+
+    def CLI(self):
+        CLI(self.mnet)
+
diff --git a/emuvim/dcemulator/node.py b/emuvim/dcemulator/node.py
new file mode 100644 (file)
index 0000000..b12751f
--- /dev/null
@@ -0,0 +1,46 @@
+"""
+Distributed Cloud Emulator (dcemulator)
+(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
+"""
+import logging
+
+
+DCDPID_BASE = 1000  # start of switch dpid's used for data center switches
+
+
+class Datacenter(object):
+    """
+    Represents a logical data center to which compute resources
+    (Docker containers) can be added at runtime.
+    """
+
+    def __init__(self, name):
+        self.net = None  # DCNetwork to which we belong
+        self.name = name
+        self.switch = None  # first prototype assumes one "bigswitch" per DC
+
+    def _get_next_dc_dpid(self):
+        global DCDPID_BASE
+        DCDPID_BASE += 1
+        return DCDPID_BASE
+
+    def create(self):
+        """
+        Each data center is represented by a single switch to which
+        compute resources can be connected at run time.
+
+        TODO: This will be changes in the future to support multiple networks
+        per data center
+        """
+        self.switch = self.net.mnet.addSwitch(
+            "%s.s1" % self.name, dpid=hex(self._get_next_dc_dpid())[2:])
+        logging.debug("created data center switch: %s" % str(self.switch))
+
+    def start(self):
+        pass
+
+    def addCompute(self):
+        pass
+
+    def removeCompute(self):
+        pass
diff --git a/emuvim/example_topology.py b/emuvim/example_topology.py
new file mode 100644 (file)
index 0000000..f2be310
--- /dev/null
@@ -0,0 +1,43 @@
+"""
+This is an example topology for the distributed cloud emulator (dcemulator).
+(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
+
+The original Mininet API has to be completely hidden and not be used by this
+script.
+"""
+import logging
+from dcemulator.net import DCNetwork
+
+logging.basicConfig(level=logging.DEBUG)
+
+
+def create_topology1():
+    # initialize network
+    net = DCNetwork()
+
+    # add data centers
+    dc1 = net.addDatacenter("dc1")
+    dc2 = net.addDatacenter("dc2")
+    dc3 = net.addDatacenter("dc3")
+    dc4 = net.addDatacenter("dc4")
+    # add additional SDN switches to our topology
+    s1 = net.addSwitch("s1")
+    # add links between data centers
+    net.addLink(dc1, dc2)
+    net.addLink("dc1", s1)
+    net.addLink(s1, "dc3")
+    net.addLink(s1, dc4)
+    # start network
+    net.start()
+    net.CLI()  # TODO remove this when we integrate APIs?
+    net.stop()  # TODO remove this when we integrate APIs?
+    # start APIs (to access emulated cloud data centers)
+    pass  # TODO: how to reflect one API endpoint per DC?
+
+
+def main():
+    create_topology1()
+
+
+if __name__ == '__main__':
+    main()