Merge "Tox: add a pep8 target"
[yardstick.git] / yardstick / network_services / vnf_generic / vnf / base.py
index 955f9f0..8ed754d 100644 (file)
 # limitations under the License.
 """ Base class implementation for generic vnf implementation """
 
-from __future__ import absolute_import
+import abc
+
 import logging
+import six
+
+from yardstick.network_services.helpers.samplevnf_helper import PortPairs
+
 
 LOG = logging.getLogger(__name__)
 
@@ -59,6 +64,12 @@ class QueueFileWrapper(object):
 
 class VnfdHelper(dict):
 
+    def __init__(self, *args, **kwargs):
+        super(VnfdHelper, self).__init__(*args, **kwargs)
+        self.port_pairs = PortPairs(self['vdu'][0]['external-interface'])
+        # port num is not present until binding so we have to memoize
+        self._port_num_map = {}
+
     @property
     def mgmt_interface(self):
         return self["mgmt-interface"]
@@ -85,16 +96,54 @@ class VnfdHelper(dict):
             virtual_intf = interface["virtual-interface"]
             if virtual_intf[key] == value:
                 return interface
+        raise KeyError()
 
     def find_interface(self, **kwargs):
         key, value = next(iter(kwargs.items()))
         for interface in self.interfaces:
             if interface[key] == value:
                 return interface
+        raise KeyError()
+
+    # hide dpdk_port_num key so we can abstract
+    def find_interface_by_port(self, port):
+        for interface in self.interfaces:
+            virtual_intf = interface["virtual-interface"]
+            # we have to convert to int to compare
+            if int(virtual_intf['dpdk_port_num']) == port:
+                return interface
+        raise KeyError()
+
+    def port_num(self, port):
+        # we need interface name -> DPDK port num (PMD ID) -> LINK ID
+        # LINK ID -> PMD ID is governed by the port mask
+        """
+
+        :rtype: int
+        :type port: str
+        """
+        if isinstance(port, dict):
+            intf = port
+        else:
+            intf = self.find_interface(name=port)
+        return self._port_num_map.setdefault(intf["name"],
+                                             int(intf["virtual-interface"]["dpdk_port_num"]))
+
+    def port_nums(self, intfs):
+        return [self.port_num(i) for i in intfs]
+
+    def ports_iter(self):
+        for port_name in self.port_pairs.all_ports:
+            port_num = self.port_num(port_name)
+            yield port_name, port_num
 
 
 class VNFObject(object):
 
+    # centralize network naming convention
+    UPLINK = PortPairs.UPLINK
+    DOWNLINK = PortPairs.DOWNLINK
+
     def __init__(self, name, vnfd):
         super(VNFObject, self).__init__()
         self.name = name
@@ -130,6 +179,13 @@ class GenericVNF(VNFObject):
         """
         raise NotImplementedError()
 
+    def wait_for_instantiate(self):
+        """ Wait for VNF to start
+
+        :return: True/False
+        """
+        raise NotImplementedError()
+
     def terminate(self):
         """ Kill all VNF processes
 
@@ -154,6 +210,7 @@ class GenericVNF(VNFObject):
         raise NotImplementedError()
 
 
+@six.add_metaclass(abc.ABCMeta)
 class GenericTrafficGen(GenericVNF):
     """ Class providing file-like API for generic traffic generator """
 
@@ -162,18 +219,29 @@ class GenericTrafficGen(GenericVNF):
         self.runs_traffic = True
         self.traffic_finished = False
 
+    @abc.abstractmethod
     def run_traffic(self, traffic_profile):
-        """ Generate traffic on the wire according to the given params.
-        Method is non-blocking, returns immediately when traffic process
+        """Generate traffic on the wire according to the given params.
+
+        This method is non-blocking, returns immediately when traffic process
         is running. Mandatory.
 
         :param traffic_profile:
         :return: True/False
         """
-        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def terminate(self):
+        """After this method finishes, all traffic processes should stop.
+
+        Mandatory.
+
+        :return: True/False
+        """
 
     def listen_traffic(self, traffic_profile):
-        """ Listen to traffic with the given parameters.
+        """Listen to traffic with the given parameters.
+
         Method is non-blocking, returns immediately when traffic process
         is running. Optional.
 
@@ -183,16 +251,20 @@ class GenericTrafficGen(GenericVNF):
         pass
 
     def verify_traffic(self, traffic_profile):
-        """ Verify captured traffic after it has ended. Optional.
+        """Verify captured traffic after it has ended.
+
+        Optional.
 
         :param traffic_profile:
         :return: dict
         """
         pass
 
-    def terminate(self):
-        """ After this method finishes, all traffic processes should stop. Mandatory.
+    def wait_for_instantiate(self):
+        """Wait for an instance to load.
+
+        Optional.
 
         :return: True/False
         """
-        raise NotImplementedError()
+        pass