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.
 
 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.
 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)
             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
             networkStatusList.append(intf_dict)
 
         return networkStatusList
@@ -98,6 +98,62 @@ class EmulatorCompute(Docker):
         return status
 
 
         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
 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 = {}
         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
 
         # pointer to assigned resource model
         self._resource_model = None
 
@@ -135,11 +193,6 @@ class Datacenter(object):
         DCDPID_BASE += 1
         return DCDPID_BASE
 
         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
     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 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.
         """
         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 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
         :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)
 
             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),
         # create the container
         d = self.net.addDocker(
             "%s" % (name),
@@ -194,7 +250,7 @@ class Datacenter(object):
             dcmd=command,
             datacenter=self,
             flavor_name=flavor_name,
             dcmd=command,
             datacenter=self,
             flavor_name=flavor_name,
-            environment = {'VNF_NAME':name},
+            environment = env,
             **params
         )
 
             **params
         )
 
@@ -255,21 +311,18 @@ class Datacenter(object):
         return True
 
     def attachExternalSAP(self, sap_name, sap_net, **params):
         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
         # 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.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):
         """
 
     def listCompute(self):
         """
@@ -278,18 +331,27 @@ class Datacenter(object):
         """
         return list(self.containers.itervalues())
 
         """
         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]
     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,
         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):
         }
 
     def assignResourceModel(self, rm):