diff options
author | opensource-tnbt <sridhar.rao@spirent.com> | 2020-11-25 15:11:47 +0530 |
---|---|---|
committer | opensource-tnbt <sridhar.rao@spirent.com> | 2020-11-25 15:23:55 +0530 |
commit | 5be0a76d76aefbfc7b0555482df2dada7a6e5a08 (patch) | |
tree | 003daa1e3c97d6ff75522b672fecee2568d8efbd | |
parent | 092de71ff79b23ab05d013ceb417b4f0b48dcc55 (diff) |
Kubernetes: Infrastructure For K8S Net testing.
This patch adds necessary code to perform K8S Networking performance
benchmarking.
Signed-off-by: Sridhar K. N. Rao <sridhar.rao@spirent.com>
Change-Id: I059ddd2e9ad3ee7c05e4620c64401f81474be195
-rw-r--r-- | conf/12_k8s.conf | 41 | ||||
-rw-r--r-- | conf/kubernetes/01_testcases.conf | 12 | ||||
-rw-r--r-- | core/component_factory.py | 15 | ||||
-rwxr-xr-x | core/loader/loader.py | 37 | ||||
-rw-r--r-- | core/pod_controller.py | 93 | ||||
-rw-r--r-- | core/vswitch_controller_p2p.py | 5 | ||||
-rw-r--r-- | pods/__init__.py | 19 | ||||
-rw-r--r-- | pods/papi/__init__.py | 19 | ||||
-rw-r--r-- | pods/papi/papi.py | 143 | ||||
-rw-r--r-- | pods/pod/__init__.py | 18 | ||||
-rw-r--r-- | pods/pod/pod.py | 63 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | testcases/__init__.py | 1 | ||||
-rw-r--r-- | testcases/k8s_performance.py | 39 | ||||
-rw-r--r-- | testcases/testcase.py | 57 | ||||
-rwxr-xr-x | vsperf | 21 | ||||
-rw-r--r-- | vswitches/vpp_dpdk_vhost.py | 2 |
17 files changed, 580 insertions, 6 deletions
diff --git a/conf/12_k8s.conf b/conf/12_k8s.conf new file mode 100644 index 00000000..5cfac966 --- /dev/null +++ b/conf/12_k8s.conf @@ -0,0 +1,41 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +# Information about the Master Node. + +POD_DIR=os.path.join(ROOT_DIR, 'pods/') +POD='Papi' + +MASTER_IP = '10.10.120.22' +MASTER_LOGIN = 'opnfv' +MASTER_PASSWD = 'opnfv' + +K8S_CONFIG_FILEPATH = '/home/opnfv/sridhar/k8sconfig' + +# Information about the Worker Node. Default is Localhost. +WORKER_IP = '10.10.120.21' +WORKER_LOGIN = 'opnfv' +WORKER_PASSWD = 'opnfv' + + +# Plugin to use. +PLUGIN = 'ovsdpdk' + +# Paths. Default location: Master Node. +NETWORK_ATTACHMENT_FILEPATH = ['/home/opnfv/sridhar/cnb/userspace/ovsdpdk/userspace-ovs-netAttach.yaml'] +POD_MANIFEST_FILEPATH = '/home/opnfv/sridhar/cnb/userspace/ovsdpdk/userspace-ovs-netapp-pod.yaml' + + +# Application pod +APP_NAME = 'l2fwd' + diff --git a/conf/kubernetes/01_testcases.conf b/conf/kubernetes/01_testcases.conf new file mode 100644 index 00000000..c5b3135c --- /dev/null +++ b/conf/kubernetes/01_testcases.conf @@ -0,0 +1,12 @@ +K8SPERFORMANCE_TESTS = [ + { + "Name": "pcp_tput", + "Deployment": "p2p", + "Description": "LTD.Throughput.RFC2544.Throughput", + "Parameters" : { + "TRAFFIC" : { + "traffic_type" : "rfc2544_throughput", + }, + }, + }, +] diff --git a/core/component_factory.py b/core/component_factory.py index 2c51a060..f13bfb5b 100644 --- a/core/component_factory.py +++ b/core/component_factory.py @@ -24,7 +24,7 @@ from core.vswitch_controller_op2p import VswitchControllerOP2P from core.vswitch_controller_ptunp import VswitchControllerPtunP from core.vnf_controller import VnfController from core.pktfwd_controller import PktFwdController - +from core.pod_controller import PodController def __init__(): """Finds and loads all the modules required. @@ -102,6 +102,19 @@ def create_vnf(deployment_scenario, vnf_class, extra_vnfs): """ return VnfController(deployment_scenario, vnf_class, extra_vnfs) +def create_pod(deployment_scenario, pod_class): + """Return a new PodController for the deployment_scenario. + + The returned controller is configured with the given POD class. + + Deployment scenarios: 'pvp', 'pvvp' + + :param deployment_scenario: The deployment scenario name + :param pod_class: Reference to pod class to be used. + :return: PodController for the deployment_scenario + """ + return PodController(deployment_scenario, pod_class) + def create_collector(collector_class, result_dir, test_name): """Return a new Collector of the given class diff --git a/core/loader/loader.py b/core/loader/loader.py index dcd77ced..45e0d5ba 100755 --- a/core/loader/loader.py +++ b/core/loader/loader.py @@ -23,6 +23,7 @@ from tools.pkt_fwd.pkt_fwd import IPktFwd from tools.pkt_gen.trafficgen import ITrafficGenerator from vswitches.vswitch import IVSwitch from vnfs.vnf.vnf import IVnf +from pods.pod.pod import IPod # pylint: disable=too-many-public-methods class Loader(object): @@ -71,6 +72,11 @@ class Loader(object): settings.getValue('PKTFWD'), IPktFwd) + self._pod_loader = LoaderServant( + settings.getValue('POD_DIR'), + settings.getValue('POD'), + IPod) + def get_trafficgen(self): """Returns a new instance configured traffic generator. @@ -220,6 +226,37 @@ class Loader(object): """ return self._vnf_loader.get_classes_printable() + def get_pod(self): + """Returns instance of currently configured pod implementation. + + :return: IPod implementation if available, None otherwise. + """ + return self._pod_loader.get_class()() + + def get_pod_class(self): + """Returns type of currently configured pod implementation. + + :return: Type of IPod implementation if available. + None otherwise. + """ + return self._pod_loader.get_class() + + def get_pods(self): + """Returns dictionary of all available pods. + + :return: Dictionary of pods. + - key: name of the class which implements IPod, + - value: Type of vnf which implements IPod. + """ + return self._pod_loader.get_classes() + + def get_pods_printable(self): + """Returns all available pods in printable format. + + :return: String containing printable list of pods. + """ + return self._pod_loader.get_classes_printable() + def get_pktfwd(self): """Returns instance of currently configured packet forwarder implementation. diff --git a/core/pod_controller.py b/core/pod_controller.py new file mode 100644 index 00000000..8bc91ec4 --- /dev/null +++ b/core/pod_controller.py @@ -0,0 +1,93 @@ +# Copyright 2020 Spirent Communications +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +""" pod Controller interface +""" + +import logging +import pexpect +#from conf import settings +from pods.pod.pod import IPod + +class PodController(): + """POD controller class + + Used to set-up and control PODs for specified scenario + + Attributes: + _pod_class: A class object representing the POD. + _deployment: A string describing the scenario to set-up in the + constructor. + _pods: A list of pods controlled by the controller. + """ + + def __init__(self, deployment, pod_class): + """Sets up the POD infrastructure based on deployment scenario + + :param pod_class: The POD class to be used. + """ + # reset POD ID counter for each testcase + IPod.reset_pod_counter() + pod_number = 0 + # setup controller with requested number of pods + self._logger = logging.getLogger(__name__) + self._pod_class = pod_class + self._deployment = deployment.lower() + self._pods = [] + if self._deployment == 'p2p': + pod_number = 1 + + if pod_number: + self._pods = [pod_class() for _ in range(pod_number)] + + self._logger.debug('Initializing the pod') + + def get_pods(self): + """Returns a list of pods controlled by this controller. + """ + self._logger.debug('get the pods') + return self._pods + + def get_pods_number(self): + """Returns a number of pods controlled by this controller. + """ + self._logger.debug('get_pods_number %s pod[s]', str(len(self._pods))) + return len(self._pods) + + def start(self): + """Boots all pods set-up by __init__. + + This is a blocking function. + """ + self._logger.debug('start the pod') + try: + for pod in self._pods: + pod.create() + except pexpect.TIMEOUT: + self.stop() + raise + + def stop(self): + """Stops all pods set-up by __init__. + + This is a blocking function. + """ + self._logger.debug('stopping the pod') + for pod in self._pods: + pod.terminate() + + def __enter__(self): + self.start() + + def __exit__(self, type_, value, traceback): + self.stop() diff --git a/core/vswitch_controller_p2p.py b/core/vswitch_controller_p2p.py index d8f22e4c..0037d484 100644 --- a/core/vswitch_controller_p2p.py +++ b/core/vswitch_controller_p2p.py @@ -45,8 +45,9 @@ class VswitchControllerP2P(IVswitchController): (port1, _) = self._vswitch.add_phy_port(self._bridge) (port2, _) = self._vswitch.add_phy_port(self._bridge) - self._vswitch.add_connection(self._bridge, port1, port2, self._traffic) - self._vswitch.add_connection(self._bridge, port2, port1, self._traffic) + if not settings.getValue('K8S'): + self._vswitch.add_connection(self._bridge, port1, port2, self._traffic) + self._vswitch.add_connection(self._bridge, port2, port1, self._traffic) except: self._vswitch.stop() diff --git a/pods/__init__.py b/pods/__init__.py new file mode 100644 index 00000000..e3ce18d9 --- /dev/null +++ b/pods/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2020 Spirent Communications +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +"""Package for POD wrappers for use with VSPERF. + +This package contains an interface the VSPERF core uses for controlling +PODs and POD-specific implementation modules of this interface. +""" diff --git a/pods/papi/__init__.py b/pods/papi/__init__.py new file mode 100644 index 00000000..16760b86 --- /dev/null +++ b/pods/papi/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2020 Spirent Communications +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +"""Package for POD wrappers for use with VSPERF. + +This package contains an implementation of the interface the VSPERF core +uses for controlling PODs using Kubernetes Python-API (PAPI) +""" diff --git a/pods/papi/papi.py b/pods/papi/papi.py new file mode 100644 index 00000000..5a21f1d6 --- /dev/null +++ b/pods/papi/papi.py @@ -0,0 +1,143 @@ +# Copyright 2020 University Of Delhi. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + + +""" +Automation of Pod Deployment with Kubernetes Python API +""" + +# import os +import logging +import json +import time +import yaml +from kubernetes import client, config +from kubernetes.client.rest import ApiException + +from conf import settings as S +from pods.pod.pod import IPod + +class Papi(IPod): + """ + Class for controlling the pod through PAPI + """ + + def __init__(self): + """ + Initialisation function. + """ + #super(Papi, self).__init__() + super().__init__() + + self._logger = logging.getLogger(__name__) + self._sriov_config = None + self._sriov_config_ns = None + config.load_kube_config(S.getValue('K8S_CONFIG_FILEPATH')) + + def create(self): + """ + Creation Process + """ + # create vswitchperf namespace + api = client.CoreV1Api() + namespace = 'default' + #namespace = 'vswitchperf' + # replace_namespace(api, namespace) + + # sriov configmap + if S.getValue('PLUGIN') == 'sriov': + configmap = load_manifest(S.getValue('CONFIGMAP_FILEPATH')) + self._sriov_config = configmap['metadata']['name'] + self._sriov_config_ns = configmap['metadata']['namespace'] + api.create_namespaced_config_map(self._sriov_config_ns, configmap) + + + # create nad(network attachent definitions) + group = 'k8s.cni.cncf.io' + version = 'v1' + kind_plural = 'network-attachment-definitions' + api = client.CustomObjectsApi() + + for nad_filepath in S.getValue('NETWORK_ATTACHMENT_FILEPATH'): + nad_manifest = load_manifest(nad_filepath) + + try: + response = api.create_namespaced_custom_object(group, version, namespace, + kind_plural, nad_manifest) + self._logger.info(str(response)) + self._logger.info("Created Network Attachment Definition: %s", nad_filepath) + except ApiException as err: + raise Exception from err + + #create pod workloads + pod_manifest = load_manifest(S.getValue('POD_MANIFEST_FILEPATH')) + api = client.CoreV1Api() + + try: + response = api.create_namespaced_pod(namespace, pod_manifest) + self._logger.info(str(response)) + self._logger.info("Created POD %d ...", self._number) + except ApiException as err: + raise Exception from err + + time.sleep(12) + + def terminate(self): + """ + Cleanup Process + """ + #self._logger.info(self._log_prefix + "Cleaning vswitchperf namespace") + self._logger.info("Terminating Pod") + api = client.CoreV1Api() + # api.delete_namespace(name="vswitchperf", body=client.V1DeleteOptions()) + + if S.getValue('PLUGIN') == 'sriov': + api.delete_namespaced_config_map(self._sriov_config, self._sriov_config_ns) + + +def load_manifest(filepath): + """ + Reads k8s manifest files and returns as string + + :param str filepath: filename of k8s manifest file to read + + :return: k8s resource definition as string + """ + with open(filepath) as handle: + data = handle.read() + + try: + manifest = json.loads(data) + except ValueError: + try: + manifest = yaml.safe_load(data) + except yaml.parser.ParserError as err: + raise Exception from err + + return manifest + +def replace_namespace(api, namespace): + """ + Creates namespace if does not exists + """ + namespaces = api.list_namespace() + for nsi in namespaces.items: + if namespace == nsi.metadata.name: + api.delete_namespace(name=namespace, + body=client.V1DeleteOptions()) + break + + time.sleep(0.5) + api.create_namespace(client.V1Namespace( + metadata=client.V1ObjectMeta(name=namespace))) diff --git a/pods/pod/__init__.py b/pods/pod/__init__.py new file mode 100644 index 00000000..b91706e2 --- /dev/null +++ b/pods/pod/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2020 Spirent Communications +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +"""POD interface and helpers. +""" + +import pods diff --git a/pods/pod/pod.py b/pods/pod/pod.py new file mode 100644 index 00000000..c25744d2 --- /dev/null +++ b/pods/pod/pod.py @@ -0,0 +1,63 @@ +# Copyright 2020 Spirent Communications, University Of Delhi. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +""" +Interface for POD +""" + +#import time +#import pexpect +from tools import tasks + +class IPod(tasks.Process): + """ + Interface for POD + + Inheriting from Process helps in managing system process. + execute a command, wait, kill, etc. + """ + _number_pods = 0 + + def __init__(self): + """ + Initialization Method + """ + self._number = IPod._number_pods + self._logger.debug('Initializing %s. Pod with index %s', + self._number + 1, self._number) + IPod._number_pods = IPod._number_pods + 1 + self._log_prefix = 'pod_%d_cmd : ' % self._number + # raise NotImplementedError() + + def create(self): + """ + Start the Pod + """ + raise NotImplementedError() + + + def terminate(self): + """ + Stop the Pod + """ + raise NotImplementedError() + + @staticmethod + def reset_pod_counter(): + """ + Reset internal POD counter + + This method is static + """ + IPod._number_pods = 0 diff --git a/requirements.txt b/requirements.txt index bd660605..92021014 100644 --- a/requirements.txt +++ b/requirements.txt @@ -40,3 +40,4 @@ PyYAML>=3.10.0 pyzmq>=16.0 six>=1.9.0 timeout-decorator>=0.4.0 +kubernetes diff --git a/testcases/__init__.py b/testcases/__init__.py index 0b6b77e4..736be883 100644 --- a/testcases/__init__.py +++ b/testcases/__init__.py @@ -17,3 +17,4 @@ from testcases.testcase import (TestCase) from testcases.performance import (PerformanceTestCase) from testcases.integration import (IntegrationTestCase) +from testcases.k8s_performance import (K8sPerformanceTestCase) diff --git a/testcases/k8s_performance.py b/testcases/k8s_performance.py new file mode 100644 index 00000000..3c31430c --- /dev/null +++ b/testcases/k8s_performance.py @@ -0,0 +1,39 @@ +# Copyright 2015-2017 Intel Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +"""PerformanceTestCase class +""" + +import logging + +from testcases.testcase import TestCase +#from tools.report import report + +class K8sPerformanceTestCase(TestCase): + """K8sPerformanceTestCase class + + In this basic form runs RFC2544 throughput test + """ + def __init__(self, cfg): + """ Testcase initialization + """ + self._type = 'k8s_performance' + super().__init__(cfg) + self._logger = logging.getLogger(__name__) + self._k8s = True + + def run_report(self): + pass + #super().run_report() + #if self._tc_results: + # report.generate(self) diff --git a/testcases/testcase.py b/testcases/testcase.py index a30558ff..51d212b4 100644 --- a/testcases/testcase.py +++ b/testcases/testcase.py @@ -73,6 +73,8 @@ class TestCase(object): self._hugepages_mounted = False self._traffic_ctl = None self._vnf_ctl = None + self._pod_ctl = None + self._pod_list = None self._vswitch_ctl = None self._collector = None self._loadgen = None @@ -81,6 +83,7 @@ class TestCase(object): self._settings_paths_modified = False self._testcast_run_time = None self._versions = [] + self._k8s = False # initialization of step driven specific members self._step_check = False # by default don't check result for step driven testcases self._step_vnf_list = {} @@ -216,6 +219,12 @@ class TestCase(object): self._vnf_list = self._vnf_ctl.get_vnfs() + self._pod_ctl = component_factory.create_pod( + self.deployment, + loader.get_pod_class()) + + self._pod_list = self._pod_ctl.get_pods() + # verify enough hugepages are free to run the testcase if not self._check_for_enough_hugepages(): raise RuntimeError('Not enough hugepages free to run test.') @@ -281,6 +290,10 @@ class TestCase(object): # Stop all VNFs started by TestSteps in case that something went wrong self.step_stop_vnfs() + if self._k8s: + self._pod_ctl.stop() + + # Cleanup any LLC-allocations if S.getValue('LLC_ALLOCATION'): self._rmd.cleanup_llc_allocation() @@ -350,15 +363,18 @@ class TestCase(object): """Run the test All setup and teardown through controllers is included. + """ # prepare test execution environment self.run_initialize() try: with self._vswitch_ctl: - with self._vnf_ctl, self._collector, self._loadgen: - if not self._vswitch_none: + with self._vnf_ctl, self._pod_ctl, self._collector, self._loadgen: + if not self._vswitch_none and not self._k8s: self._add_flows() + if self._k8s: + self._add_connections() self._versions += self._vswitch_ctl.get_vswitch().get_version() @@ -595,6 +611,43 @@ class TestCase(object): return list(result.keys()) + def _add_connections(self): + """ + Add connections for Kubernetes Usecases + """ + logging.info("Kubernetes: Adding Connections") + vswitch = self._vswitch_ctl.get_vswitch() + bridge = S.getValue('VSWITCH_BRIDGE_NAME') + if S.getValue('K8S') and 'sriov' not in S.getValue('PLUGIN'): + if 'Ovs' in S.getValue('VSWITCH'): + # Add OVS Flows + logging.info("Kubernetes: Adding OVS Connections") + flow = {'table':'0', 'in_port':'1', + 'idle_timeout':'0', 'actions': ['output:3']} + vswitch.add_flow(bridge, flow) + flow = {'table':'0', 'in_port':'3', + 'idle_timeout':'0', 'actions': ['output:1']} + vswitch.add_flow(bridge, flow) + flow = {'table':'0', 'in_port':'2', + 'idle_timeout':'0', 'actions': ['output:4']} + vswitch.add_flow(bridge, flow) + flow = {'table':'0', 'in_port':'4', + 'idle_timeout':'0', 'actions': ['output:2']} + vswitch.add_flow(bridge, flow) + elif 'vpp' in S.getValue('VSWITCH'): + phy_ports = vswitch.get_ports() + virt_port0 = 'memif1/0' + virt_port1 = 'memif2/0' + vswitch.add_connection(bridge, phy_ports[0], + virt_port0, None) + vswitch.add_connection(bridge, virt_port0, + phy_ports[0], None) + vswitch.add_connection(bridge, phy_ports[1], + virt_port1, None) + vswitch.add_connection(bridge, virt_port1, + phy_ports[1], None) + + def _add_flows(self): """Add flows to the vswitch """ @@ -40,6 +40,7 @@ import core.component_factory as component_factory from core.loader import Loader from testcases import PerformanceTestCase from testcases import IntegrationTestCase +from testcases import K8sPerformanceTestCase from tools import tasks from tools import networkcard from tools import functions @@ -179,6 +180,8 @@ def parse_arguments(): help='list all system vnfs and exit') parser.add_argument('--list-loadgens', action='store_true', help='list all background load generators') + parser.add_argument('--list-pods', action='store_true', + help='list all system pods') parser.add_argument('--list-settings', action='store_true', help='list effective settings configuration and exit') parser.add_argument('exact_test_name', nargs='*', help='Exact names of\ @@ -202,6 +205,7 @@ def parse_arguments(): group.add_argument('--verbosity', choices=list_logging_levels(), help='debug level') group.add_argument('--integration', action='store_true', help='execute integration tests') + group.add_argument('--k8s', action='store_true', help='execute Kubernetes tests') group.add_argument('--openstack', action='store_true', help='Run VSPERF with openstack') group.add_argument('--trafficgen', help='traffic generator to use') group.add_argument('--vswitch', help='vswitch implementation to use') @@ -579,6 +583,10 @@ def handle_list_options(args): print(Loader().get_loadgens_printable()) sys.exit(0) + if args['list_pods']: + print(Loader().get_pods_printable()) + sys.exit(0) + if args['list_settings']: print(str(settings)) sys.exit(0) @@ -596,6 +604,8 @@ def list_testcases(args): # configure tests if args['integration']: testcases = settings.getValue('INTEGRATION_TESTS') + elif args['k8s']: + testcases = settings.getValue('K8SPERFORMANCE_TESTS') else: testcases = settings.getValue('PERFORMANCE_TESTS') @@ -692,6 +702,8 @@ def main(): # load non performance/integration tests if args['integration']: settings.load_from_dir(os.path.join(_CURR_DIR, 'conf/integration')) + if args['k8s']: + settings.load_from_dir(os.path.join(_CURR_DIR, 'conf/kubernetes')) # load command line parameters first in case there are settings files # to be used @@ -709,6 +721,11 @@ def main(): settings.setValue('mode', args['mode']) + if args['k8s']: + settings.setValue('K8S', True) + else: + settings.setValue('K8S', False) + if args['openstack']: result = osdt.deploy_testvnf() if result: @@ -833,6 +850,8 @@ def main(): # configure tests if args['integration']: testcases = settings.getValue('INTEGRATION_TESTS') + elif args['k8s']: + testcases = settings.getValue('K8SPERFORMANCE_TESTS') else: testcases = settings.getValue('PERFORMANCE_TESTS') @@ -875,6 +894,8 @@ def main(): if args['integration']: test = IntegrationTestCase(cfg) + elif args['k8s']: + test = K8sPerformanceTestCase(cfg) else: test = PerformanceTestCase(cfg) diff --git a/vswitches/vpp_dpdk_vhost.py b/vswitches/vpp_dpdk_vhost.py index af5aca51..f88ed95e 100644 --- a/vswitches/vpp_dpdk_vhost.py +++ b/vswitches/vpp_dpdk_vhost.py @@ -462,4 +462,4 @@ class VppDpdkVhost(IVSwitch, tasks.Process): def get_ports(self, switch_name): """See IVswitch for general description """ - raise NotImplementedError() + return self._phy_ports |