[NFVBENCH-62] Add support for non-openstack environments 15/50715/1
authorahothan <ahothan@cisco.com>
Tue, 16 Jan 2018 20:46:21 +0000 (12:46 -0800)
committerahothan <ahothan@cisco.com>
Tue, 16 Jan 2018 20:46:21 +0000 (12:46 -0800)
Add Unit test to validate non-openstack with dummy traffic gen

Change-Id: I359ddb7d43169f706d8262842af975d5b4675a3a
Signed-off-by: ahothan <ahothan@cisco.com>
nfvbench/cfg.default.yaml
nfvbench/chain_clients.py
nfvbench/chain_managers.py
nfvbench/nfvbench.py
nfvbench/specs.py
nfvbench/summarizer.py
nfvbench/traffic_gen/dummy.py
test/test_nfvbench.py

index bc8921d..07d48f3 100644 (file)
 # Fields that can be over-ridden at the command line are marked with the corresponding
 # option, e.g. "--interval"
 
+# The OpenStack openrc file to use (must be a valid full pathname). If running
+# in a container, this path must be valid in the container.
+#
+# The only case where this field can be empty is when measuring a system that does not run
+# OpenStack or when OpenStack APIs are not accessible or OpenStack APis use is not
+# desirable. In that case the EXT service chain must be used.
+openrc_file:
 
 # Forwarder to use in nfvbenchvm image. Available options: ['vpp', 'testpmd']
 vm_forwarder: testpmd
@@ -195,9 +202,6 @@ traffic_generator:
 # -----------------------------------------------------------------------------
 # These variables are not likely to be changed
 
-# The openrc file
-openrc_file:
-
 # Number of seconds to wait for VMs to pass traffic in both directions
 check_traffic_time_sec: 200
 
index 7106129..faf7c2a 100644 (file)
@@ -416,7 +416,8 @@ class BasicStageClient(object):
         Creates two networks and spawn a VM which act as a loop VM connected
         with the two networks.
         """
-        self._setup_openstack_clients()
+        if self.cred:
+            self._setup_openstack_clients()
 
     def dispose(self, only_vm=False):
         """
@@ -448,12 +449,15 @@ class EXTStageClient(BasicStageClient):
         super(EXTStageClient, self).setup()
 
         # Lookup two existing networks
-        for net_name in [self.config.external_networks.left, self.config.external_networks.right]:
-            net = self._lookup_network(net_name)
-            if net:
-                self.nets.append(net)
-            else:
-                raise StageClientException('Existing network {} cannot be found.'.format(net_name))
+        if self.cred:
+            for net_name in [self.config.external_networks.left,
+                             self.config.external_networks.right]:
+                net = self._lookup_network(net_name)
+                if net:
+                    self.nets.append(net)
+                else:
+                    raise StageClientException('Existing network {} cannot be found.'.
+                                               format(net_name))
 
 
 class PVPStageClient(BasicStageClient):
index 8b605aa..087c751 100644 (file)
@@ -96,11 +96,12 @@ class StatsManager(object):
             raise exc
 
     def _get_data(self):
-        return self.worker.get_data()
+        return self.worker.get_data() if self.worker else {}
 
     def _get_network(self, traffic_port, index=None, reverse=False):
         interfaces = [self.clients['traffic'].get_interface(traffic_port)]
-        interfaces.extend(self.worker.get_network_interfaces(index))
+        if self.worker:
+            interfaces.extend(self.worker.get_network_interfaces(index))
         return Network(interfaces, reverse)
 
     def _config_interfaces(self):
@@ -127,13 +128,14 @@ class StatsManager(object):
         return self.interval_collector.get() if self.interval_collector else []
 
     def get_version(self):
-        return self.worker.get_version()
+        return self.worker.get_version() if self.worker else {}
 
     def run(self):
         """
         Run analysis in both direction and return the analysis
         """
-        self.worker.run()
+        if self.worker:
+            self.worker.run()
 
         stats = self._generate_traffic()
         result = {
@@ -157,7 +159,7 @@ class StatsManager(object):
         return result
 
     def get_compute_nodes_bios(self):
-        return self.worker.get_compute_nodes_bios()
+        return self.worker.get_compute_nodes_bios() if self.worker else {}
 
     @staticmethod
     def get_analysis(nets):
@@ -176,7 +178,8 @@ class StatsManager(object):
         return packet_analyzer.get_analysis()
 
     def close(self):
-        self.worker.close()
+        if self.worker:
+            self.worker.close()
 
 
 class PVPStatsManager(StatsManager):
@@ -229,10 +232,13 @@ class EXTStatsManager(StatsManager):
         StatsManager.__init__(self, config, clients, specs, factory, vlans, notifier)
 
     def _setup(self):
-        WORKER_CLASS = self.factory.get_chain_worker(self.specs.openstack.encaps,
-                                                     self.config.service_chain)
-        self.worker = WORKER_CLASS(self.config, self.clients, self.specs)
-        self.worker.set_vlans(self.vlans)
+        if self.specs.openstack:
+            WORKER_CLASS = self.factory.get_chain_worker(self.specs.openstack.encaps,
+                                                         self.config.service_chain)
+            self.worker = WORKER_CLASS(self.config, self.clients, self.specs)
+            self.worker.set_vlans(self.vlans)
 
-        if not self.config.no_int_config:
-            self._config_interfaces()
+            if not self.config.no_int_config:
+                self._config_interfaces()
+        else:
+            self.worker = None
index 6f59e24..8c88248 100644 (file)
@@ -58,7 +58,8 @@ class NFVBench(object):
         self.config_plugin = config_plugin
         self.factory = factory
         self.notifier = notifier
-        self.cred = credentials.Credentials(config.openrc_file, None, False)
+        self.cred = credentials.Credentials(config.openrc_file, None, False) \
+            if config.openrc_file else None
         self.chain_runner = None
         self.specs = Specs()
         self.specs.set_openstack_spec(openstack_spec)
@@ -94,10 +95,6 @@ class NFVBench(object):
             result = {
                 "date": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                 "nfvbench_version": __version__,
-                "openstack_spec": {
-                    "vswitch": self.specs.openstack.vswitch,
-                    "encaps": self.specs.openstack.encaps
-                },
                 "config": self.config_plugin.prepare_results_config(copy.deepcopy(self.config)),
                 "benchmarks": {
                     "network": {
@@ -106,6 +103,9 @@ class NFVBench(object):
                     }
                 }
             }
+            if self.specs.openstack:
+                result['openstack_spec'] = {"vswitch": self.specs.openstack.vswitch,
+                                            "encaps": self.specs.openstack.encaps}
             result['benchmarks']['network']['versions'].update(self.config_plugin.get_version())
         except Exception:
             status = NFVBench.STATUS_ERROR
@@ -444,7 +444,6 @@ def main():
         # create config plugin for this platform
         config_plugin = factory.get_config_plugin_class()(config)
         config = config_plugin.get_config()
-        openstack_spec = config_plugin.get_openstack_spec()
 
         opts, unknown_opts = parse_opts_from_cli()
         log.set_level(debug=opts.debug)
@@ -520,6 +519,14 @@ def main():
             print json.dumps(config, sort_keys=True, indent=4)
             sys.exit(0)
 
+        # check that an empty openrc file (no OpenStack) is only allowed
+        # with EXT chain
+        if not config.openrc_file:
+            if config.service_chain == ChainType.EXT:
+                LOG.info('EXT chain with OpenStack mode disabled')
+            else:
+                raise Exception("openrc_file is empty in the configuration and is required")
+
         # update the config in the config plugin as it might have changed
         # in a copy of the dict (config plugin still holds the original dict)
         config_plugin.set_config(config)
@@ -528,6 +535,9 @@ def main():
         if config.log_file:
             log.add_file_logger(config.log_file)
 
+        openstack_spec = config_plugin.get_openstack_spec() if config.openrc_file \
+            else None
+
         nfvbench_instance = NFVBench(config, openstack_spec, config_plugin, factory)
 
         if opts.server:
index 7a24d5c..a84a55f 100644 (file)
@@ -75,7 +75,8 @@ class OpenStackSpec(object):
 
 class RunSpec(object):
     def __init__(self, no_vswitch_access, openstack_spec):
-        self.use_vswitch = (not no_vswitch_access) and openstack_spec.vswitch != "BASIC"
+        self.use_vswitch = (not no_vswitch_access) and openstack_spec \
+            and openstack_spec.vswitch != "BASIC"
 
 
 class Specs(object):
index 1676e93..0ff9c48 100644 (file)
@@ -221,18 +221,24 @@ class NFVBenchSummarizer(Summarizer):
             self.__record_init()
         self.__summarize()
 
+    def __get_openstack_spec(self, property):
+        try:
+            return self.result['openstack_spec'][property]
+        except KeyError:
+            return ''
+
     def __summarize(self):
         self._put()
         self._put('========== NFVBench Summary ==========')
         self._put('Date:', self.result['date'])
         self._put('NFVBench version', self.result['nfvbench_version'])
         self._put('Openstack Neutron:', {
-            'vSwitch': self.result['openstack_spec']['vswitch'],
-            'Encapsulation': self.result['openstack_spec']['encaps']
+            'vSwitch': self.__get_openstack_spec('vswitch'),
+            'Encapsulation': self.__get_openstack_spec('encaps')
         })
         self.__record_header_put('version', self.result['nfvbench_version'])
-        self.__record_header_put('vSwitch', self.result['openstack_spec']['vswitch'])
-        self.__record_header_put('Encapsulation', self.result['openstack_spec']['encaps'])
+        self.__record_header_put('vSwitch', self.__get_openstack_spec('vswitch'))
+        self.__record_header_put('Encapsulation', self.__get_openstack_spec('encaps'))
         self._put('Benchmarks:')
         with self._create_block():
             self._put('Networks:')
index b43030f..6f57f4d 100644 (file)
@@ -30,6 +30,7 @@ class DummyTG(AbstractTrafficGenerator):
         self.l2_frame_size = 0
         self.duration_sec = self.config.duration_sec
         self.intf_speed = config.generator_config.intf_speed
+        self.set_response_curve()
 
     def get_version(self):
         return "0.1"
@@ -154,6 +155,9 @@ class DummyTG(AbstractTrafficGenerator):
         result['total_tx_rate'] = total_tx_pps
         return result
 
+    def get_macs(self):
+        return ['00.00.00.00.00.01', '00.00.00.00.00.02']
+
     def clear_stats(self):
         pass
 
@@ -165,3 +169,9 @@ class DummyTG(AbstractTrafficGenerator):
 
     def cleanup(self):
         pass
+
+    def set_mode(self):
+        pass
+
+    def resolve_arp(self):
+        return True
index fc8174f..113ecfd 100644 (file)
@@ -13,7 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 #
-
+import json
 import logging
 import os
 import sys
@@ -429,8 +429,6 @@ from nfvbench.traffic_client import IpBlock
 from nfvbench.traffic_client import TrafficClient
 from nfvbench.traffic_client import TrafficGeneratorFactory
 
-# pylint: enable=wrong-import-position,ungrouped-imports
-
 def test_ip_block():
     ipb = IpBlock('10.0.0.0', '0.0.0.1', 256)
     assert ipb.get_ip() == '10.0.0.0'
@@ -595,16 +593,16 @@ def assert_ndr_pdr(stats, ndr, ndr_dr, pdr, pdr_dr):
     assert_equivalence(pdr, stats['pdr']['rate_percent'])
     assert_equivalence(pdr_dr, stats['pdr']['stats']['overall']['drop_percentage'])
 
-def get_traffic_client():
-    config = AttrDict({
+def get_dummy_tg_config(chain_type, rate):
+    return AttrDict({
         'traffic_generator': {'host_name': 'nfvbench_tg',
                               'default_profile': 'dummy',
                               'generator_profile': [{'name': 'dummy',
                                                      'tool': 'dummy',
                                                      'ip': '127.0.0.1',
                                                      'intf_speed': '10Gbps',
-                                                     'interfaces': [{'port': 0, 'pci': 0},
-                                                                    {'port': 1, 'pci': 0}]}],
+                                                     'interfaces': [{'port': 0, 'pci': '0.0'},
+                                                                    {'port': 1, 'pci': '0.0'}]}],
                               'ip_addrs_step': '0.0.0.1',
                               'ip_addrs': ['10.0.0.0/8', '20.0.0.0/8'],
                               'tg_gateway_ip_addrs': ['1.1.0.100', '2.2.0.100'],
@@ -613,22 +611,25 @@ def get_traffic_client():
                               'gateway_ip_addrs_step': '0.0.0.1',
                               'udp_src_port': None,
                               'udp_dst_port': None},
-        'generator_profile': 'dummy',
-        'service_chain': 'PVP',
+        'service_chain': chain_type,
         'service_chain_count': 1,
         'flow_count': 10,
         'vlan_tagging': True,
         'no_arp': False,
         'duration_sec': 1,
         'interval_sec': 1,
-        'single_run': False,
-        'ndr_run': True,
-        'pdr_run': True,
-        'rate': 'ndr_pdr',
+        'rate': rate,
         'check_traffic_time_sec': 200,
         'generic_poll_sec': 2,
         'measurement': {'NDR': 0.001, 'PDR': 0.1, 'load_epsilon': 0.1},
     })
+
+def get_traffic_client():
+    config = get_dummy_tg_config('PVP', 'ndr_pdr')
+    config['ndr_run'] = True
+    config['pdr_run'] = True
+    config['generator_profile'] = 'dummy'
+    config['single_run'] = False
     generator_factory = TrafficGeneratorFactory(config)
     config.generator_config = generator_factory.get_generator_config(config.generator_profile)
     traffic_client = TrafficClient(config, skip_sleep=True)
@@ -680,3 +681,13 @@ def test_ndr_pdr_low_cpu():
     # import pprint
     # pp = pprint.PrettyPrinter(indent=4)
     # pp.pprint(results)
+
+import nfvbench.nfvbench
+
+def test_no_openstack():
+    config = get_dummy_tg_config('EXT', '1000pps')
+    config.openrc_file = None
+    old_argv = sys.argv
+    sys.argv = [old_argv[0], '-c', json.dumps(config)]
+    nfvbench.nfvbench.main()
+    sys.argv = old_argv