Fixed missing license headers
[osm/vim-emu.git] / src / emuvim / dcemulator / node.py
index 9439eeb..77a71a0 100755 (executable)
@@ -14,7 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 
-Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
+Neither the name of the SONATA-NFV, Paderborn University
 nor the names of its contributors may be used to endorse or promote
 products derived from this software without specific prior written
 permission.
@@ -67,7 +67,7 @@ class EmulatorCompute(Docker):
             vnf_interface = str(i)
             dc_port_name = self.datacenter.net.find_connected_dc_interface(vnf_name, vnf_interface)
             # format list of tuples (name, Ip, MAC, isUp, status, dc_portname)
-            intf_dict = {'intf_name': str(i), 'ip': i.IP(), 'netmask': i.prefixLen, 'mac': i.MAC(), 'up': i.isUp(), 'status': i.status(), 'dc_portname': dc_port_name}
+            intf_dict = {'intf_name': str(i), 'ip': "{0}/{1}".format(i.IP(), i.prefixLen), 'netmask': i.prefixLen, 'mac': i.MAC(), 'up': i.isUp(), 'status': i.status(), 'dc_portname': dc_port_name}
             networkStatusList.append(intf_dict)
 
         return networkStatusList
@@ -98,6 +98,62 @@ class EmulatorCompute(Docker):
         return status
 
 
+class EmulatorExtSAP(object):
+    """
+    Emulator specific class that defines an external service access point (SAP) for the service.
+    Inherits from Containernet's OVSBridge class.
+    Represents a single OVS switch connected to a (logical)
+    data center.
+    We can add emulator specific helper functions to it.
+    """
+
+    def __init__(self, sap_name, sap_net, datacenter, **kwargs):
+
+        self.datacenter = datacenter  # pointer to current DC
+        self.net = self.datacenter.net
+        self.name = sap_name
+
+        LOG.debug("Starting ext SAP instance %r in data center %r" % (sap_name, str(self.datacenter)))
+
+        # create SAP as separate OVS switch with an assigned ip address
+        self.ip = str(sap_net[1]) + '/' + str(sap_net.prefixlen)
+        self.subnet = sap_net
+        # allow connection to the external internet through the host
+        params = dict(NAT=True)
+        self.switch = self.net.addExtSAP(sap_name, self.ip, dpid=hex(self._get_next_extSAP_dpid())[2:], **params)
+        self.switch.start()
+
+    def _get_next_extSAP_dpid(self):
+        global EXTSAPDPID_BASE
+        EXTSAPDPID_BASE += 1
+        return EXTSAPDPID_BASE
+
+    def getNetworkStatus(self):
+        """
+        Helper method to receive information about the virtual networks
+        this compute instance is connected to.
+        """
+        # get all links and find dc switch interface
+        networkStatusList = []
+        for i in self.switch.intfList():
+            vnf_name = self.name
+            vnf_interface = str(i)
+            if vnf_interface == 'lo':
+                continue
+            dc_port_name = self.datacenter.net.find_connected_dc_interface(vnf_name, vnf_interface)
+            # format list of tuples (name, Ip, MAC, isUp, status, dc_portname)
+            intf_dict = {'intf_name': str(i), 'ip': self.ip, 'netmask': i.prefixLen, 'mac': i.MAC(), 'up': i.isUp(), 'status': i.status(), 'dc_portname': dc_port_name}
+            networkStatusList.append(intf_dict)
+
+        return networkStatusList
+
+    def getStatus(self):
+        return {
+            "name": self.switch.name,
+            "datacenter": self.datacenter.name,
+            "network": self.getNetworkStatus()
+        }
+
 class Datacenter(object):
     """
     Represents a logical data center to which compute resources
@@ -124,6 +180,8 @@ class Datacenter(object):
         self.switch = None
         # keep track of running containers
         self.containers = {}
+        # keep track of attached external access points
+        self.extSAPs = {}
         # pointer to assigned resource model
         self._resource_model = None
 
@@ -135,11 +193,6 @@ class Datacenter(object):
         DCDPID_BASE += 1
         return DCDPID_BASE
 
-    def _get_next_extSAP_dpid(self):
-        global EXTSAPDPID_BASE
-        EXTSAPDPID_BASE += 1
-        return EXTSAPDPID_BASE
-
     def create(self):
         """
         Each data center is represented by a single switch to which
@@ -155,7 +208,7 @@ class Datacenter(object):
     def start(self):
         pass
 
-    def startCompute(self, name, image=None, command=None, network=None, flavor_name="tiny", **params):
+    def startCompute(self, name, image=None, command=None, network=None, flavor_name="tiny", properties=dict(), **params):
         """
         Create a new container as compute resource and connect it to this
         data center.
@@ -164,6 +217,7 @@ class Datacenter(object):
         :param command: command (string)
         :param network: networks list({"ip": "10.0.0.254/8"}, {"ip": "11.0.0.254/24"})
         :param flavor_name: name of the flavor for this compute container
+        :param properties: dictionary of properties (key-value) that will be passed as environment variables
         :return:
         """
         assert name is not None
@@ -187,6 +241,8 @@ class Datacenter(object):
             params['cpu_period'] = self.net.cpu_period
             params['cpu_quota'] = self.net.cpu_period * float(cpu_percentage)
 
+        env = properties
+        properties['VNF_NAME'] = name
         # create the container
         d = self.net.addDocker(
             "%s" % (name),
@@ -194,7 +250,7 @@ class Datacenter(object):
             dcmd=command,
             datacenter=self,
             flavor_name=flavor_name,
-            environment = {'VNF_NAME':name},
+            environment = env,
             **params
         )
 
@@ -255,21 +311,18 @@ class Datacenter(object):
         return True
 
     def attachExternalSAP(self, sap_name, sap_net, **params):
-        # create SAP as separate OVS switch with an assigned ip address
-        sap_ip = str(sap_net[1]) + '/' + str(sap_net.prefixlen)
-        # allow connection to the external internet through the host
-        params = dict(NAT=True, SAPNet=str(sap_net))
-        sap_switch = self.net.addExtSAP(sap_name, sap_ip, dpid=hex(self._get_next_extSAP_dpid())[2:], **params)
-        sap_switch.start()
-
+        extSAP = EmulatorExtSAP(sap_name, sap_net, self, **params)
         # link SAP to the DC switch
-        self.net.addLink(sap_switch, self.switch, cls=Link)
+        self.net.addLink(extSAP.switch, self.switch, cls=Link)
+        self.extSAPs[sap_name] = extSAP
 
-    def removeExternalSAP(self, sap_name, sap_net):
-        sap_switch = self.net.getNodeByName(sap_name)
-        # link SAP to the DC switch
+    def removeExternalSAP(self, sap_name):
+        sap_switch = self.extSAPs[sap_name].switch
+        #sap_switch = self.net.getNodeByName(sap_name)
+        # remove link of SAP to the DC switch
         self.net.removeLink(link=None, node1=sap_switch, node2=self.switch)
-        self.net.removeExtSAP(sap_name, str(sap_net))
+        self.net.removeExtSAP(sap_name)
+        del self.extSAPs[sap_name]
 
     def listCompute(self):
         """
@@ -278,18 +331,27 @@ class Datacenter(object):
         """
         return list(self.containers.itervalues())
 
+    def listExtSAPs(self):
+        """
+        Return a list of all external SAPs assigned to this
+        data center.
+        """
+        return list(self.extSAPs.itervalues())
+
     def getStatus(self):
         """
         Return a dict with status information about this DC.
         """
         container_list = [name for name in self.containers]
+        ext_saplist = [sap_name for sap_name in self.extSAPs]
         return {
             "label": self.label,
             "internalname": self.name,
             "switch": self.switch.name,
             "n_running_containers": len(self.containers),
             "metadata": self.metadata,
-            "vnf_list" : container_list
+            "vnf_list" : container_list,
+            "ext SAP list" : ext_saplist
         }
 
     def assignResourceModel(self, rm):