Merge "Create Dockerfile to create a yardstick-image of docker"
authorEmma Foley <emma.l.foley@intel.com>
Fri, 20 Jul 2018 13:32:45 +0000 (13:32 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Fri, 20 Jul 2018 13:32:45 +0000 (13:32 +0000)
94 files changed:
.coveragerc
ansible/install.yaml
ansible/roles/configure_uwsgi/templates/yardstick.ini.j2
ansible/roles/download_dpdk/tasks/main.yml
ansible/roles/infra_create_vms/tasks/main.yml
ansible/roles/infra_create_vms/tasks/validate_vms.yml [new file with mode: 0644]
ansible/roles/infra_prepare_vms/tasks/main.yml
ansible/roles/install_dpdk/tasks/main.yml
ansible/roles/install_samplevnf/vars/main.yml
ansible/ubuntu_server_baremetal_deploy_samplevnfs.yml
ansible/ubuntu_server_cloudimg_modify_samplevnfs.yml
docker/Dockerfile
docker/Dockerfile.aarch64.patch
samples/ping_bottlenecks.yaml
samples/vnf_samples/nsut/acl/acl_rules.yaml.sample [moved from samples/vnf_samples/nsut/acl/acl_rules.yaml with 88% similarity]
samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_iterationipc.yaml [new file with mode: 0644]
tests/opnfv/test_cases/opnfv_yardstick_tc087.yaml
tests/opnfv/test_cases/opnfv_yardstick_tc092.yaml
tests/opnfv/test_cases/opnfv_yardstick_tc093.yaml
yardstick/benchmark/contexts/__init__.py
yardstick/benchmark/contexts/dummy.py
yardstick/benchmark/contexts/heat.py
yardstick/benchmark/contexts/kubernetes.py
yardstick/benchmark/contexts/node.py
yardstick/benchmark/contexts/standalone/ovs_dpdk.py
yardstick/benchmark/contexts/standalone/sriov.py
yardstick/benchmark/core/task.py
yardstick/benchmark/runners/base.py
yardstick/benchmark/runners/iteration_ipc.py [new file with mode: 0644]
yardstick/benchmark/scenarios/base.py
yardstick/benchmark/scenarios/networking/vnf_generic.py
yardstick/common/constants.py
yardstick/common/exceptions.py
yardstick/common/httpClient.py
yardstick/common/kubernetes_utils.py
yardstick/common/messaging/__init__.py
yardstick/common/messaging/consumer.py
yardstick/common/messaging/payloads.py
yardstick/common/messaging/producer.py
yardstick/common/utils.py
yardstick/network_services/collector/subscriber.py
yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
yardstick/network_services/vnf_generic/vnf/acl_vnf.py
yardstick/network_services/vnf_generic/vnf/base.py
yardstick/network_services/vnf_generic/vnf/cgnapt_vnf.py
yardstick/network_services/vnf_generic/vnf/prox_helpers.py
yardstick/network_services/vnf_generic/vnf/prox_vnf.py
yardstick/network_services/vnf_generic/vnf/router_vnf.py
yardstick/network_services/vnf_generic/vnf/sample_vnf.py
yardstick/network_services/vnf_generic/vnf/tg_ixload.py
yardstick/network_services/vnf_generic/vnf/tg_ping.py
yardstick/network_services/vnf_generic/vnf/tg_prox.py
yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py
yardstick/network_services/vnf_generic/vnf/tg_trex.py
yardstick/network_services/vnf_generic/vnf/udp_replay.py
yardstick/network_services/vnf_generic/vnf/vfw_vnf.py
yardstick/network_services/vnf_generic/vnf/vpe_vnf.py
yardstick/orchestrator/kubernetes.py
yardstick/tests/functional/common/messaging/test_messaging.py
yardstick/tests/functional/common/test_utils.py
yardstick/tests/functional/network_services/__init__.py [new file with mode: 0644]
yardstick/tests/functional/network_services/vnf_generic/__init__.py [new file with mode: 0644]
yardstick/tests/functional/network_services/vnf_generic/vnf/__init__.py [new file with mode: 0644]
yardstick/tests/functional/network_services/vnf_generic/vnf/test_base.py [new file with mode: 0644]
yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py
yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py
yardstick/tests/unit/benchmark/contexts/test_kubernetes.py
yardstick/tests/unit/benchmark/core/test_task.py
yardstick/tests/unit/benchmark/runner/test_base.py
yardstick/tests/unit/benchmark/runner/test_iteration_ipc.py [new file with mode: 0644]
yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py
yardstick/tests/unit/common/messaging/test_payloads.py
yardstick/tests/unit/common/messaging/test_producer.py
yardstick/tests/unit/common/test_kubernetes_utils.py [new file with mode: 0644]
yardstick/tests/unit/common/test_utils.py
yardstick/tests/unit/network_services/collector/test_subscriber.py
yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py
yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py
yardstick/tests/unit/orchestrator/test_kubernetes.py

index f678531..3ad7f68 100644 (file)
@@ -14,4 +14,4 @@ source = yardstick
 [report]
 ignore_errors = True
 precision = 3
-omit = yardstick/vTC/*
+omit = yardstick/vTC/*,yardstick/tests/functional/*
index e93232d..ae9f858 100644 (file)
@@ -88,7 +88,7 @@
     - role: install_samplevnf
       vnf_name: FW
     - role: install_samplevnf
-      vnf_name: CGNATP
+      vnf_name: CGNAPT
     # build shared DPDK for collectd only, required DPDK downloaded already
     - install_dpdk_shared
     - install_rabbitmq
index 044f42a..495febb 100644 (file)
@@ -12,7 +12,7 @@ chmod-socket = 666
 callable = app_wrapper
 enable-threads = true
 close-on-exec = 1
-daemonize = {{ log_dir }}uwsgi.log
+logto = {{ log_dir }}/uwsgi.log
 socket = {{ socket_file }}
 {# If virtual environment, we need to add:
    virtualenv = <virtual_env> #}
index bea3feb..55b466c 100644 (file)
       path: "{{ dpdk_dest }}/{{ dpdk_file }}"
       state: absent
 
+- name: find unzipped DPDK folder
+  find:
+    paths: "{{ dpdk_dest }}"
+    patterns: "^dpdk-.*{{ dpdk_version }}$"
+    file_type: directory
+    use_regex: yes
+  register: dpdk_folder_match
+
+- fail:
+    msg: "Cannot find unzipped DPDK folder or more than one found"
+  when: dpdk_folder_match.matched != 1
+
 - set_fact:
-    dpdk_path: "{{ dpdk_dest }}/{{ dpdk_unarchive }}"
+    dpdk_path: "{{ dpdk_folder_match.files[0].path }}"
 
 - set_fact:
     RTE_SDK: "{{ dpdk_path }}"
index 4d47f44..b422a92 100644 (file)
   loop_control:
     loop_var: node_item
   with_items: "{{ infra_deploy_vars.nodes }}"
+
+- name: Create list of dictionaries with vm name, ip address
+  set_fact:
+    vm_name_ip: "{{ vm_name_ip|default([]) + [{item.hostname: item.interfaces[1].ip}] }}"
+  with_items: "{{ infra_deploy_vars.nodes }}"
+
+- name: Make sure VM is reachable
+  include_tasks: validate_vms.yml
+  loop_control:
+    loop_var: name_ip
+  with_items: "{{ vm_name_ip }}"
diff --git a/ansible/roles/infra_create_vms/tasks/validate_vms.yml b/ansible/roles/infra_create_vms/tasks/validate_vms.yml
new file mode 100644 (file)
index 0000000..ce5eff2
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (c) 2018 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.
+---
+- name: Validate if VM is responding
+  wait_for:
+    host: "{{ item.value }}"
+    port: 22
+    timeout: 10
+  with_dict: "{{ name_ip }}"
+  register: result
+  ignore_errors: yes
+
+- name: Stop VM if it is not responding
+  virt:
+    name: "{{ item.key }}"
+    command: destroy
+  when: result is failed
+  with_dict: "{{ name_ip }}"
+
+- name: Wait for VM is being stopped
+  pause:
+    seconds: 10
+  when: result is failed
+
+- name: Start VM
+  virt:
+    name: "{{ item.key }}"
+    command: start
+  when: result is failed
+  with_dict: "{{ name_ip }}"
+
+- name: Validate if VM is responding
+  wait_for:
+    host: "{{ item.value }}"
+    port: 22
+    timeout: 10
+  when: result is failed
+  with_dict: "{{ name_ip }}"
+  register: result
+
+- fail:
+    msg: "FAILED on {{ name_ip }}"
+  when: result is failed
index d7ed085..4e0d9c3 100644 (file)
     secondary_ip: "{{ item.interfaces[1].ip }}"
   when: item.hostname == 'yardstickvm'
   with_items: "{{ infra_deploy_vars.nodes }}"
-
-- name: Workaround, not all VMs are ready by that time
-  pause: seconds=20
index 5bcfb50..f89a43c 100644 (file)
     path: "{{ INSTALL_BIN_PATH }}"
     state:  directory
 
+- set_fact:
+    major: "{{ dpdk_version.split('.')[0] }}"
+    minor: "{{ dpdk_version.split('.')[1] }}"
+
+- set_fact:
+    major_minor_version: "{{ major }}.{{ minor }}"
+
 - name: copy dpdk-devbind.py to correct location
   copy:
-    src: "{{ dpdk_devbind_usertools if dpdk_version|float >= 17.02 else dpdk_devbind_tools }}"
+    src: "{{ dpdk_devbind_usertools if major_minor_version|float >= 17.02 else dpdk_devbind_tools }}"
     dest: "{{ INSTALL_BIN_PATH }}/dpdk-devbind.py"
     remote_src: yes
     force: yes
index c92a9b0..e2a3737 100644 (file)
@@ -48,13 +48,11 @@ vnf_build_dirs:
   ACL: vACL
   FW: vFW
   CGNAPT: vCGNAPT
-  PE: vPE
   UDP_Replay: UDP_Replay
   PROX: DPPD-PROX
 vnf_app_names:
   ACL: vACL
   FW: vFW
   CGNAPT: vCGNAPT
-  PE: vPE
   UDP_Replay: UDP_Replay
   PROX: prox
index d858257..3a29a8a 100644 (file)
@@ -45,8 +45,6 @@
       vnf_name: FW
     - role: install_samplevnf
       vnf_name: CGNAPT
-    - role: install_samplevnf
-      vnf_name: PE
     # build shared DPDK for collectd only, required DPDK downloaded already
     - install_dpdk_shared
     - install_rabbitmq
index aab5a74..b27933b 100644 (file)
@@ -55,8 +55,6 @@
       vnf_name: FW
     - role: install_samplevnf
       vnf_name: CGNAPT
-    - role: install_samplevnf
-      vnf_name: PE
     # build shared DPDK for collectd only, required DPDK downloaded already
     - install_dpdk_shared
     - install_rabbitmq
index 097bc3c..71ce6b5 100644 (file)
@@ -51,6 +51,8 @@ EXPOSE 5000 5672
 ADD http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img ${IMAGE_DIR}
 ADD http://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-disk1.img ${IMAGE_DIR}
 
+# For developers: when `docker build ...` is running from YARDSTICK_REPO_DIR, please change
+#                 path `./exec_tests.sh` -> `./docker/exec_tests.sh``.
 COPY ./exec_tests.sh /usr/local/bin/
 
 ENV NSB_DIR="/opt/nsb_bin"
index ef41cba..472310f 100644 (file)
@@ -8,7 +8,7 @@ Signed-off-by: ting wu <ting.wu@enea.com>
  1 file changed, 6 insertions(+), 5 deletions(-)
 
 diff --git a/docker/Dockerfile b/docker/Dockerfile
-index 62ea0d0..f2f41771 100644
+index 71ce6b58..952d0f78 100644
 --- a/docker/Dockerfile
 +++ b/docker/Dockerfile
 @@ -7,9 +7,9 @@
@@ -42,6 +42,5 @@ index 62ea0d0..f2f41771 100644
 +ADD http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-disk.img ${IMAGE_DIR}
 +ADD http://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-arm64-disk1.img ${IMAGE_DIR}
 
- COPY ./exec_tests.sh /usr/local/bin/
-
-
+ # For developers: when `docker build ...` is running from YARDSTICK_REPO_DIR, please change
+ #                 path `./exec_tests.sh` -> `./docker/exec_tests.sh``.
index 625d450..096d70e 100644 (file)
@@ -19,6 +19,7 @@ run_in_parallel: true
 {% set cpu_num = cpu_num or 1 %}
 {% set ram_num = ram_num or 512 %}
 {% set disk_num = disk_num or 7 %}
+{% set dpdk_enabled = dpdk_enabled or False %}
 
 scenarios:
 {% for num in range(stack_num) %}
@@ -43,6 +44,10 @@ contexts:
     vcpus: {{cpu_num}}
     ram: {{ram_num}}
     disk: {{disk_num}}
+    {% if dpdk_enabled %}
+    extra_specs:
+      hw:mem_page_size: "large"
+    {% endif %}
   user: ubuntu
 
   placement_groups:
 ---
 access-list-entries:
   -
-    actions: [drop,count]
+    actions:
+      - count
+      - nat:
+          port: 1
+      - fwd:
+          port: 0
     matches:
       destination-ipv4-network: 152.16.40.20/24
       destination-port-range:
@@ -24,6 +29,9 @@ access-list-entries:
       source-port-range:
         lower-port: 0
         upper-port: 65535
+      protocol-mask: 255
+      protocol: 127
+      priority: 1
     rule-name: rule1588
   -
     actions: [drop,count]
diff --git a/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_iterationipc.yaml b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_iterationipc.yaml
new file mode 100644 (file)
index 0000000..184ed68
--- /dev/null
@@ -0,0 +1,96 @@
+# Copyright (c) 2016-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.
+
+---
+{% set provider = provider or none %}
+{% set physical_networks = physical_networks or ['physnet1', 'physnet2'] %}
+{% set segmentation_id = segmentation_id or none %}
+
+schema: yardstick:task:0.1
+scenarios:
+- type: NSPerf
+  traffic_profile: ../../traffic_profiles/ipv4_throughput.yaml
+  topology: vfw-tg-topology.yaml
+  nodes:
+    tg__0: trafficgen_1.yardstick
+    vnf__0: vnf.yardstick
+  options:
+    hugepages_gb: 8
+    framesize:
+      uplink: {64B: 100}
+      downlink: {64B: 100}
+    flow:
+      src_ip: [{'tg__0': 'xe0'}]
+      dst_ip: [{'tg__0': 'xe1'}]
+      count: 1
+    traffic_type: 4
+    rfc2544:
+      allowed_drop_rate: 0.0001 - 0.0001
+    vnf__0:
+      rules: acl_1rule.yaml
+      vnf_config: {lb_config: 'SW', lb_count: 1, worker_config: '1C/1T', worker_threads: 1}
+  runner:
+    type: IterationIPC
+    iterations: 10
+    timeout: 60
+context:
+  # put node context first, so we don't HEAT deploy if node has errors
+  name: yardstick
+  image: yardstick-samplevnfs
+  flavor:
+    vcpus: 10
+    ram: 12288
+    disk: 6
+    extra_specs:
+      hw:cpu_sockets: 1
+      hw:cpu_cores: 10
+      hw:cpu_threads: 1
+  user: ubuntu
+  placement_groups:
+    pgrp1:
+      policy: "availability"
+  servers:
+    vnf:
+      floating_ip: true
+      placement: "pgrp1"
+    trafficgen_1:
+      floating_ip: true
+      placement: "pgrp1"
+  networks:
+    mgmt:
+      cidr: '10.0.1.0/24'
+    xe0:
+      cidr: '10.0.2.0/24'
+      gateway_ip: 'null'
+      {% if provider %}
+      provider: {{ provider }}
+      physical_network: {{ physical_networks[0] }}
+        {% if segmentation_id %}
+      segmentation_id: {{ segmentation_id }}
+        {% endif %}
+      {% endif %}
+      port_security_enabled: False
+      enable_dhcp: 'false'
+    xe1:
+      cidr: '10.0.3.0/24'
+      gateway_ip: 'null'
+      {% if provider %}
+      provider: {{ provider }}
+      physical_network: {{ physical_networks[1] }}
+        {% if segmentation_id %}
+      segmentation_id: {{ segmentation_id }}
+        {% endif %}
+      {% endif %}
+      port_security_enabled: False
+      enable_dhcp: 'false'
index d744183..13125ad 100644 (file)
@@ -74,7 +74,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 
 -
@@ -172,7 +172,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 -
       type: "GeneralHA"
@@ -239,7 +239,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 
 contexts:
index 85ec510..f2996bc 100644 (file)
@@ -73,7 +73,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 -
       type: "GeneralHA"
@@ -170,7 +170,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 -
       type: "GeneralHA"
@@ -237,7 +237,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 
 contexts:
index a034471..27e78a4 100644 (file)
@@ -75,7 +75,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 
 -
@@ -208,7 +208,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 -
       type: "GeneralHA"
@@ -274,7 +274,7 @@ scenarios:
         type: Duration
         duration: 1
       sla:
-        action: monitor
+        action: assert
 
 
 contexts:
index e69de29..d50f08c 100644 (file)
@@ -0,0 +1,20 @@
+# Copyright (c) 2016-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.
+
+CONTEXT_DUMMY = "Dummy"
+CONTEXT_HEAT = "Heat"
+CONTEXT_KUBERNETES = "Kubernetes"
+CONTEXT_NODE = "Node"
+CONTEXT_STANDALONEOVSDPDK = "StandaloneOvsDpdk"
+CONTEXT_STANDALONESRIOV = "StandaloneSriov"
index 36e8854..9faca4c 100644 (file)
@@ -7,17 +7,18 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
-from yardstick.benchmark.contexts.base import Context
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base
 
 
-class DummyContext(Context):
+class DummyContext(base.Context):
     """Class that handle dummy info.
 
     This class is also used to test the abstract class Context because it
     provides a minimal concrete implementation of a subclass.
     """
 
-    __context_type__ = "Dummy"
+    __context_type__ = contexts.CONTEXT_DUMMY
 
     def deploy(self):
         """Don't need to deploy"""
index ac85b6f..f118ffc 100644 (file)
@@ -16,6 +16,7 @@ from collections import OrderedDict
 import ipaddress
 import pkg_resources
 
+from yardstick.benchmark import contexts
 from yardstick.benchmark.contexts.base import Context
 from yardstick.benchmark.contexts.model import Network
 from yardstick.benchmark.contexts.model import PlacementGroup, ServerGroup
@@ -47,7 +48,7 @@ def h_join(*args):
 class HeatContext(Context):
     """Class that represents a context in the logical model"""
 
-    __context_type__ = "Heat"
+    __context_type__ = contexts.CONTEXT_HEAT
 
     def __init__(self):
         self.stack = None
index 916f4b1..7534c4e 100644 (file)
@@ -7,26 +7,31 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
-from __future__ import absolute_import
+import collections
 import logging
-import time
 import pkg_resources
+import time
 
 import paramiko
 
-from yardstick.benchmark.contexts.base import Context
-from yardstick.orchestrator import kubernetes
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.benchmark.contexts import model
+from yardstick.common import constants
+from yardstick.common import exceptions
 from yardstick.common import kubernetes_utils as k8s_utils
 from yardstick.common import utils
+from yardstick.orchestrator import kubernetes
+
 
 LOG = logging.getLogger(__name__)
 BITS_LENGTH = 2048
 
 
-class KubernetesContext(Context):
+class KubernetesContext(ctx_base.Context):
     """Class that handle nodes info"""
 
-    __context_type__ = "Kubernetes"
+    __context_type__ = contexts.CONTEXT_KUBERNETES
 
     def __init__(self):
         self.ssh_key = ''
@@ -38,15 +43,21 @@ class KubernetesContext(Context):
     def init(self, attrs):
         super(KubernetesContext, self).init(attrs)
 
+        networks = attrs.get('networks', {})
         self.template = kubernetes.KubernetesTemplate(self.name, attrs)
         self.ssh_key = '{}-key'.format(self.name)
         self.key_path = self._get_key_path()
         self.public_key_path = '{}.pub'.format(self.key_path)
+        self._networks = collections.OrderedDict(
+            (net_name, model.Network(net_name, self, network))
+            for net_name, network in networks.items())
 
     def deploy(self):
         LOG.info('Creating ssh key')
         self._set_ssh_key()
 
+        self._create_crd()
+        self._create_networks()
         LOG.info('Launch containers')
         self._create_rcs()
         self._create_services()
@@ -60,6 +71,8 @@ class KubernetesContext(Context):
         self._delete_rcs()
         self._delete_pods()
         self._delete_services()
+        self._delete_networks()
+        self._delete_crd()
 
         super(KubernetesContext, self).undeploy()
 
@@ -86,7 +99,7 @@ class KubernetesContext(Context):
             obj.delete()
 
     def _create_rcs(self):
-        for obj in self.template.k8s_objs:
+        for obj in self.template.rc_objs:
             self._create_rc(obj.get_template())
 
     def _create_rc(self, template):
@@ -104,7 +117,27 @@ class KubernetesContext(Context):
             self._delete_pod(pod)
 
     def _delete_pod(self, pod):
-        k8s_utils.delete_pod(pod)
+        k8s_utils.delete_pod(pod, skip_codes=[404])
+
+    def _create_crd(self):
+        LOG.info('Create Custom Resource Definition elements')
+        for crd in self.template.crd:
+            crd.create()
+
+    def _delete_crd(self):
+        LOG.info('Delete Custom Resource Definition elements')
+        for crd in self.template.crd:
+            crd.delete()
+
+    def _create_networks(self):  # pragma: no cover
+        LOG.info('Create Network elements')
+        for net in self.template.network_objs:
+            net.create()
+
+    def _delete_networks(self):  # pragma: no cover
+        LOG.info('Create Network elements')
+        for net in self.template.network_objs:
+            net.delete()
 
     def _get_key_path(self):
         task_id = self.name.split('-')[-1]
@@ -131,28 +164,71 @@ class KubernetesContext(Context):
         utils.remove_file(self.public_key_path)
 
     def _get_server(self, name):
-        service_name = '{}-service'.format(name)
-        service = k8s_utils.get_service_by_name(service_name).ports[0]
-
-        host = {
-            'name': service.name,
+        node_ports = self._get_service_ports(name)
+        for sn_port in (sn_port for sn_port in node_ports
+                        if sn_port['port'] == constants.SSH_PORT):
+            node_port = sn_port['node_port']
+            break
+        else:
+            raise exceptions.KubernetesSSHPortNotDefined()
+
+        return {
+            'name': name,
             'ip': self._get_node_ip(),
             'private_ip': k8s_utils.get_pod_by_name(name).status.pod_ip,
-            'ssh_port': service.node_port,
+            'ssh_port': node_port,
             'user': 'root',
             'key_filename': self.key_path,
+            'interfaces': self._get_interfaces(name),
+            'service_ports': node_ports
         }
 
-        return host
+    def _get_network(self, net_name):
+        """Retrieves the network object, searching by name
+
+        :param net_name: (str) replication controller name
+        :return: (dict) network information (name)
+        """
+        network = self._networks.get(net_name)
+        if not network:
+            return
+        return {'name': net_name}
+
+    def _get_interfaces(self, rc_name):
+        """Retrieves the network list of a replication controller
+
+        :param rc_name: (str) replication controller name
+        :return: (dict) names and information of the networks used in this
+                 replication controller; those networks must be defined in the
+                 Kubernetes cluster
+        """
+        rc = self.template.get_rc_by_name(rc_name)
+        if not rc:
+            return {}
+        return {name: {'network_name': name,
+                       'local_mac': None,
+                       'local_ip': None}
+                for name in rc.networks}
 
     def _get_node_ip(self):
         return k8s_utils.get_node_list().items[0].status.addresses[0].address
 
-    def _get_network(self, attr_name):
-        return None
-
     def _get_physical_nodes(self):
         return None
 
     def _get_physical_node_for_server(self, server_name):
         return None
+
+    def _get_service_ports(self, name):
+        service_name = '{}-service'.format(name)
+        service = k8s_utils.get_service_by_name(service_name)
+        if not service:
+            raise exceptions.KubernetesServiceObjectNotDefined()
+        ports = []
+        for port in service.ports:
+            ports.append({'name': port.name,
+                          'node_port': port.node_port,
+                          'port': port.port,
+                          'protocol': port.protocol,
+                          'target_port': port.target_port})
+        return ports
index d3af989..d233e02 100644 (file)
@@ -7,7 +7,6 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
-from __future__ import absolute_import
 import subprocess
 import os
 import collections
@@ -18,6 +17,7 @@ import six
 import pkg_resources
 
 from yardstick import ssh
+from yardstick.benchmark import contexts
 from yardstick.benchmark.contexts.base import Context
 from yardstick.common.constants import ANSIBLE_DIR, YARDSTICK_ROOT_PATH
 from yardstick.common.ansible_common import AnsibleCommon
@@ -31,7 +31,7 @@ DEFAULT_DISPATCH = 'script'
 class NodeContext(Context):
     """Class that handle nodes info"""
 
-    __context_type__ = "Node"
+    __context_type__ = contexts.CONTEXT_NODE
 
     def __init__(self):
         self.file_path = None
index e6a6f99..88ad598 100644 (file)
@@ -20,11 +20,12 @@ import re
 import time
 
 from yardstick import ssh
-from yardstick.network_services.utils import get_nsb_option
-from yardstick.benchmark.contexts.base import Context
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base
 from yardstick.benchmark.contexts.standalone import model
 from yardstick.common import exceptions
 from yardstick.network_services import utils
+from yardstick.network_services.utils import get_nsb_option
 
 
 LOG = logging.getLogger(__name__)
@@ -32,12 +33,12 @@ LOG = logging.getLogger(__name__)
 MAIN_BRIDGE = 'br0'
 
 
-class OvsDpdkContext(Context):
+class OvsDpdkContext(base.Context):
     """ This class handles OVS standalone nodes - VM running on Non-Managed NFVi
     Configuration: ovs_dpdk
     """
 
-    __context_type__ = "StandaloneOvsDpdk"
+    __context_type__ = contexts.CONTEXT_STANDALONEOVSDPDK
 
     SUPPORTED_OVS_TO_DPDK_MAP = {
         '2.6.0': '16.07.1',
index 05fac02..3da12a9 100644 (file)
@@ -18,20 +18,21 @@ import logging
 import collections
 
 from yardstick import ssh
-from yardstick.network_services.utils import get_nsb_option
-from yardstick.benchmark.contexts.base import Context
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base
 from yardstick.benchmark.contexts.standalone import model
+from yardstick.network_services.utils import get_nsb_option
 from yardstick.network_services.utils import PciAddress
 
 LOG = logging.getLogger(__name__)
 
 
-class SriovContext(Context):
+class SriovContext(base.Context):
     """ This class handles SRIOV standalone nodes - VM running on Non-Managed NFVi
     Configuration: sr-iov
     """
 
-    __context_type__ = "StandaloneSriov"
+    __context_type__ = contexts.CONTEXT_STANDALONESRIOV
 
     def __init__(self):
         self.file_path = None
index f050e8d..1dfd6c3 100644 (file)
@@ -22,7 +22,8 @@ import collections
 from six.moves import filter
 from jinja2 import Environment
 
-from yardstick.benchmark.contexts.base import Context
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base as base_context
 from yardstick.benchmark.runners import base as base_runner
 from yardstick.common.constants import CONF_FILE
 from yardstick.common.yaml_loader import yaml_load
@@ -359,7 +360,7 @@ class Task(object):     # pragma: no cover
             if is_ip_addr(target):
                 context_cfg['target'] = {"ipaddr": target}
             else:
-                context_cfg['target'] = Context.get_server(target)
+                context_cfg['target'] = base_context.Context.get_server(target)
                 if self._is_same_context(cfg["host"], target):
                     context_cfg['target']["ipaddr"] = context_cfg['target']["private_ip"]
                 else:
@@ -367,7 +368,7 @@ class Task(object):     # pragma: no cover
 
         host_name = server_name.get('host', scenario_cfg.get('host'))
         if host_name:
-            context_cfg['host'] = Context.get_server(host_name)
+            context_cfg['host'] = base_context.Context.get_server(host_name)
 
         for item in [server_name, scenario_cfg]:
             try:
@@ -384,7 +385,8 @@ class Task(object):     # pragma: no cover
                     ip_list.append(target)
                     context_cfg['target'] = {}
                 else:
-                    context_cfg['target'] = Context.get_server(target)
+                    context_cfg['target'] = (
+                        base_context.Context.get_server(target))
                     if self._is_same_context(scenario_cfg["host"],
                                              target):
                         ip_list.append(context_cfg["target"]["private_ip"])
@@ -412,7 +414,8 @@ class Task(object):     # pragma: no cover
         with attribute name mapping when using external heat templates
         """
         for context in self.contexts:
-            if context.__context_type__ not in {"Heat", "Kubernetes"}:
+            if context.__context_type__ not in {contexts.CONTEXT_HEAT,
+                                                contexts.CONTEXT_KUBERNETES}:
                 continue
 
             host = context._get_server(host_attr)
@@ -553,19 +556,19 @@ class TaskParser(object):       # pragma: no cover
         elif "contexts" in cfg:
             context_cfgs = cfg["contexts"]
         else:
-            context_cfgs = [{"type": "Dummy"}]
+            context_cfgs = [{"type": contexts.CONTEXT_DUMMY}]
 
-        contexts = []
+        _contexts = []
         for cfg_attrs in context_cfgs:
 
             cfg_attrs['task_id'] = task_id
             # default to Heat context because we are testing OpenStack
-            context_type = cfg_attrs.get("type", "Heat")
-            context = Context.get(context_type)
+            context_type = cfg_attrs.get("type", contexts.CONTEXT_HEAT)
+            context = base_context.Context.get(context_type)
             context.init(cfg_attrs)
             # Update the name in case the context has used the name_suffix
             cfg_attrs['name'] = context.name
-            contexts.append(context)
+            _contexts.append(context)
 
         run_in_parallel = cfg.get("run_in_parallel", False)
 
@@ -578,17 +581,17 @@ class TaskParser(object):       # pragma: no cover
             # relative to task path
             scenario["task_path"] = os.path.dirname(self.path)
 
-            self._change_node_names(scenario, contexts)
+            self._change_node_names(scenario, _contexts)
 
         # TODO we need something better here, a class that represent the file
         return {'scenarios': cfg['scenarios'],
                 'run_in_parallel': run_in_parallel,
                 'meet_precondition': meet_precondition,
-                'contexts': contexts,
+                'contexts': _contexts,
                 'rendered': rendered}
 
     @staticmethod
-    def _change_node_names(scenario, contexts):
+    def _change_node_names(scenario, _contexts):
         """Change the node names in a scenario, depending on the context config
 
         The nodes (VMs or physical servers) are referred in the context section
@@ -627,7 +630,7 @@ class TaskParser(object):       # pragma: no cover
           target: target-k8s
         """
         def qualified_name(name):
-            for context in contexts:
+            for context in _contexts:
                 host_name, ctx_name = context.split_host_name(name)
                 if context.assigned_name == ctx_name:
                     return '{}{}{}'.format(host_name,
@@ -718,7 +721,8 @@ def _is_background_scenario(scenario):
 def parse_nodes_with_context(scenario_cfg):
     """parse the 'nodes' fields in scenario """
     # ensure consistency in node instantiation order
-    return OrderedDict((nodename, Context.get_server(scenario_cfg["nodes"][nodename]))
+    return OrderedDict((nodename, base_context.Context.get_server(
+                        scenario_cfg["nodes"][nodename]))
                        for nodename in sorted(scenario_cfg["nodes"]))
 
 
@@ -734,7 +738,7 @@ def get_networks_from_nodes(nodes):
             network_name = interface.get('network_name')
             if not network_name:
                 continue
-            network = Context.get_network(network_name)
+            network = base_context.Context.get_network(network_name)
             if network:
                 networks[network['name']] = network
     return networks
index fbdf6c2..af25574 100755 (executable)
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+#
+# This is a modified copy of ``rally/rally/benchmark/runners/base.py``
 
-# yardstick comment: this is a modified copy of
-# rally/rally/benchmark/runners/base.py
-
-from __future__ import absolute_import
-
+import importlib
 import logging
 import multiprocessing
 import subprocess
 import time
 import traceback
-from subprocess import CalledProcessError
-
-import importlib
 
-from six.moves.queue import Empty
+from six import moves
 
-import yardstick.common.utils as utils
 from yardstick.benchmark.scenarios import base as base_scenario
+from yardstick.common import messaging
+from yardstick.common.messaging import payloads
+from yardstick.common.messaging import producer
+from yardstick.common import utils
 from yardstick.dispatcher.base import Base as DispatcherBase
 
+
 log = logging.getLogger(__name__)
 
 
@@ -41,7 +40,7 @@ def _execute_shell_command(command):
     exitcode = 0
     try:
         output = subprocess.check_output(command, shell=True)
-    except CalledProcessError:
+    except subprocess.CalledProcessError:
         exitcode = -1
         output = traceback.format_exc()
         log.error("exec command '%s' error:\n ", command)
@@ -245,7 +244,7 @@ class Runner(object):
             log.debug("output_queue size %s", self.output_queue.qsize())
             try:
                 result.update(self.output_queue.get(True, 1))
-            except Empty:
+            except moves.queue.Empty:
                 pass
         return result
 
@@ -259,7 +258,7 @@ class Runner(object):
             log.debug("result_queue size %s", self.result_queue.qsize())
             try:
                 one_record = self.result_queue.get(True, 1)
-            except Empty:
+            except moves.queue.Empty:
                 pass
             else:
                 if output_in_influxdb:
@@ -272,3 +271,22 @@ class Runner(object):
         dispatchers = DispatcherBase.get(self.config['output_config'])
         dispatcher = next((d for d in dispatchers if d.__dispatcher_type__ == 'Influxdb'))
         dispatcher.upload_one_record(record, self.case_name, '', task_id=self.task_id)
+
+
+class RunnerProducer(producer.MessagingProducer):
+    """Class implementing the message producer for runners"""
+
+    def __init__(self, _id):
+        super(RunnerProducer, self).__init__(messaging.TOPIC_RUNNER, _id=_id)
+
+    def start_iteration(self, version=1, data=None):
+        data = {} if not data else data
+        self.send_message(
+            messaging.RUNNER_METHOD_START_ITERATION,
+            payloads.RunnerPayload(version=version, data=data))
+
+    def stop_iteration(self, version=1, data=None):
+        data = {} if not data else data
+        self.send_message(
+            messaging.RUNNER_METHOD_STOP_ITERATION,
+            payloads.RunnerPayload(version=version, data=data))
diff --git a/yardstick/benchmark/runners/iteration_ipc.py b/yardstick/benchmark/runners/iteration_ipc.py
new file mode 100644 (file)
index 0000000..a0335fd
--- /dev/null
@@ -0,0 +1,205 @@
+# Copyright 2018: Intel Corporation
+# All Rights Reserved.
+#
+#    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.
+
+"""A runner that runs a configurable number of times before it returns. Each
+   iteration has a configurable timeout. The loop control depends on the
+   feedback received from the running VNFs. The context PIDs from the VNFs
+   to listen the messages from are given in the scenario "setup" method.
+"""
+
+import logging
+import multiprocessing
+import time
+import traceback
+
+import os
+
+from yardstick.benchmark.runners import base as base_runner
+from yardstick.common import exceptions
+from yardstick.common import messaging
+from yardstick.common import utils
+from yardstick.common.messaging import consumer
+from yardstick.common.messaging import payloads
+
+
+LOG = logging.getLogger(__name__)
+
+QUEUE_PUT_TIMEOUT = 10
+ITERATION_TIMEOUT = 180
+
+
+class RunnerIterationIPCEndpoint(consumer.NotificationHandler):
+    """Endpoint class for ``RunnerIterationIPCConsumer``"""
+
+    def tg_method_started(self, ctxt, **kwargs):
+        if ctxt['id'] in self._ctx_ids:
+            self._queue.put(
+                {'id': ctxt['id'],
+                 'action': messaging.TG_METHOD_STARTED,
+                 'payload': payloads.TrafficGeneratorPayload.dict_to_obj(
+                     kwargs)},
+                QUEUE_PUT_TIMEOUT)
+
+    def tg_method_finished(self, ctxt, **kwargs):
+        if ctxt['id'] in self._ctx_ids:
+            self._queue.put(
+                {'id': ctxt['id'],
+                 'action': messaging.TG_METHOD_FINISHED,
+                 'payload': payloads.TrafficGeneratorPayload.dict_to_obj(
+                     kwargs)})
+
+    def tg_method_iteration(self, ctxt, **kwargs):
+        if ctxt['id'] in self._ctx_ids:
+            self._queue.put(
+                {'id': ctxt['id'],
+                 'action': messaging.TG_METHOD_ITERATION,
+                 'payload': payloads.TrafficGeneratorPayload.dict_to_obj(
+                     kwargs)})
+
+
+class RunnerIterationIPCConsumer(consumer.MessagingConsumer):
+    """MQ consumer for "IterationIPC" runner"""
+
+    def __init__(self, _id, ctx_ids):
+        self._id = _id
+        self._queue = multiprocessing.Queue()
+        endpoints = [RunnerIterationIPCEndpoint(_id, ctx_ids, self._queue)]
+        super(RunnerIterationIPCConsumer, self).__init__(
+            messaging.TOPIC_TG, ctx_ids, endpoints)
+        self._kpi_per_id = {ctx: [] for ctx in ctx_ids}
+        self.iteration_index = None
+
+    def is_all_kpis_received_in_iteration(self):
+        """Check if all producers registered have sent the ITERATION msg
+
+        During the present iteration, all producers (traffic generators) must
+        start and finish the traffic injection, and at the end of the traffic
+        injection a TG_METHOD_ITERATION must be sent. This function will check
+        all KPIs in the present iteration are received. E.g.:
+          self.iteration_index = 2
+
+          self._kpi_per_id = {
+            'ctx1': [kpi0, kpi1, kpi2],
+            'ctx2': [kpi0, kpi1]}          --> return False
+
+          self._kpi_per_id = {
+            'ctx1': [kpi0, kpi1, kpi2],
+            'ctx2': [kpi0, kpi1, kpi2]}    --> return True
+        """
+        while not self._queue.empty():
+            msg = self._queue.get(True, 1)
+            if msg['action'] == messaging.TG_METHOD_ITERATION:
+                id_iter_list = self._kpi_per_id[msg['id']]
+                id_iter_list.append(msg['payload'].kpi)
+
+        return all(len(id_iter_list) == self.iteration_index
+                   for id_iter_list in self._kpi_per_id.values())
+
+
+def _worker_process(queue, cls, method_name, scenario_cfg,
+                    context_cfg, aborted, output_queue):  # pragma: no cover
+    runner_cfg = scenario_cfg['runner']
+
+    timeout = runner_cfg.get('timeout', ITERATION_TIMEOUT)
+    iterations = runner_cfg.get('iterations', 1)
+    run_step = runner_cfg.get('run_step', 'setup,run,teardown')
+    LOG.info('Worker START. Iterations %d times, class %s', iterations, cls)
+
+    runner_cfg['runner_id'] = os.getpid()
+
+    benchmark = cls(scenario_cfg, context_cfg)
+    method = getattr(benchmark, method_name)
+
+    if 'setup' not in run_step:
+        raise exceptions.RunnerIterationIPCSetupActionNeeded()
+    benchmark.setup()
+    producer_ctxs = benchmark.get_mq_ids()
+    if not producer_ctxs:
+        raise exceptions.RunnerIterationIPCNoCtxs()
+
+    mq_consumer = RunnerIterationIPCConsumer(os.getpid(), producer_ctxs)
+    mq_consumer.start_rpc_server()
+    mq_producer = base_runner.RunnerProducer(scenario_cfg['task_id'])
+
+    iteration_index = 1
+    while 'run' in run_step:
+        LOG.debug('runner=%(runner)s seq=%(sequence)s START',
+                  {'runner': runner_cfg['runner_id'],
+                   'sequence': iteration_index})
+        data = {}
+        result = None
+        errors = ''
+        mq_consumer.iteration_index = iteration_index
+        mq_producer.start_iteration()
+
+        try:
+            utils.wait_until_true(
+                mq_consumer.is_all_kpis_received_in_iteration,
+                timeout=timeout, sleep=2)
+            result = method(data)
+        except Exception:  # pylint: disable=broad-except
+            errors = traceback.format_exc()
+            LOG.exception(errors)
+
+        mq_producer.stop_iteration()
+
+        if result:
+            output_queue.put(result, True, QUEUE_PUT_TIMEOUT)
+        benchmark_output = {'timestamp': time.time(),
+                            'sequence': iteration_index,
+                            'data': data,
+                            'errors': errors}
+        queue.put(benchmark_output, True, QUEUE_PUT_TIMEOUT)
+
+        LOG.debug('runner=%(runner)s seq=%(sequence)s END',
+                  {'runner': runner_cfg['runner_id'],
+                   'sequence': iteration_index})
+
+        iteration_index += 1
+        if iteration_index > iterations or aborted.is_set():
+            LOG.info('"IterationIPC" worker END')
+            break
+
+    if 'teardown' in run_step:
+        try:
+            benchmark.teardown()
+        except Exception:
+            LOG.exception('Exception during teardown process')
+            mq_consumer.stop_rpc_server()
+            raise SystemExit(1)
+
+    LOG.debug('Data queue size = %s', queue.qsize())
+    LOG.debug('Output queue size = %s', output_queue.qsize())
+    mq_consumer.stop_rpc_server()
+
+
+class IterationIPCRunner(base_runner.Runner):
+    """Run a scenario for a configurable number of times.
+
+    Each iteration has a configurable timeout. The loop control depends on the
+    feedback received from the running VNFs. The context PIDs from the VNFs to
+    listen the messages from are given in the scenario "setup" method.
+    """
+    __execution_type__ = 'IterationIPC'
+
+    def _run_benchmark(self, cls, method, scenario_cfg, context_cfg):
+        name = '{}-{}-{}'.format(
+            self.__execution_type__, scenario_cfg.get('type'), os.getpid())
+        self.process = multiprocessing.Process(
+            name=name,
+            target=_worker_process,
+            args=(self.result_queue, cls, method, scenario_cfg,
+                  context_cfg, self.aborted, self.output_queue))
+        self.process.start()
index 30ac1be..90a87ac 100644 (file)
@@ -119,3 +119,7 @@ class Scenario(object):
             except TypeError:
                 dic[k] = v
         return dic
+
+    def get_mq_ids(self):  # pragma: no cover
+        """Return stored MQ producer IDs, if defined"""
+        pass
index eb62d62..7a11d3e 100644 (file)
@@ -50,7 +50,7 @@ class NetworkServiceTestCase(scenario_base.Scenario):
 
     __scenario_type__ = "NSPerf"
 
-    def __init__(self, scenario_cfg, context_cfg):  # Yardstick API
+    def __init__(self, scenario_cfg, context_cfg):  # pragma: no cover
         super(NetworkServiceTestCase, self).__init__()
         self.scenario_cfg = scenario_cfg
         self.context_cfg = context_cfg
@@ -61,6 +61,7 @@ class NetworkServiceTestCase(scenario_base.Scenario):
         self.traffic_profile = None
         self.node_netdevs = {}
         self.bin_path = get_nsb_option('bin_path', '')
+        self._mq_ids = []
 
     def _get_ip_flow_range(self, ip_start_range):
 
@@ -168,18 +169,18 @@ class NetworkServiceTestCase(scenario_base.Scenario):
         topology_yaml = vnfdgen.generate_vnfd(topology, topolgy_data)
         self.topology = topology_yaml["nsd:nsd-catalog"]["nsd"][0]
 
-    def _find_vnf_name_from_id(self, vnf_id):
+    def _find_vnf_name_from_id(self, vnf_id):  # pragma: no cover
         return next((vnfd["vnfd-id-ref"]
                      for vnfd in self.topology["constituent-vnfd"]
                      if vnf_id == vnfd["member-vnf-index"]), None)
 
-    def _find_vnfd_from_vnf_idx(self, vnf_id):
+    def _find_vnfd_from_vnf_idx(self, vnf_id):  # pragma: no cover
         return next((vnfd
                      for vnfd in self.topology["constituent-vnfd"]
                      if vnf_id == vnfd["member-vnf-index"]), None)
 
     @staticmethod
-    def find_node_if(nodes, name, if_name, vld_id):
+    def find_node_if(nodes, name, if_name, vld_id):  # pragma: no cover
         try:
             # check for xe0, xe1
             intf = nodes[name]["interfaces"][if_name]
@@ -272,14 +273,14 @@ class NetworkServiceTestCase(scenario_base.Scenario):
             node0_if["peer_intf"] = node1_copy
             node1_if["peer_intf"] = node0_copy
 
-    def _update_context_with_topology(self):
+    def _update_context_with_topology(self):  # pragma: no cover
         for vnfd in self.topology["constituent-vnfd"]:
             vnf_idx = vnfd["member-vnf-index"]
             vnf_name = self._find_vnf_name_from_id(vnf_idx)
             vnfd = self._find_vnfd_from_vnf_idx(vnf_idx)
             self.context_cfg["nodes"][vnf_name].update(vnfd)
 
-    def _generate_pod_yaml(self):
+    def _generate_pod_yaml(self):  # pragma: no cover
         context_yaml = os.path.join(LOG_DIR, "pod-{}.yaml".format(self.scenario_cfg['task_id']))
         # convert OrderedDict to a list
         # pod.yaml nodes is a list
@@ -293,7 +294,7 @@ class NetworkServiceTestCase(scenario_base.Scenario):
                            explicit_start=True)
 
     @staticmethod
-    def _serialize_node(node):
+    def _serialize_node(node):  # pragma: no cover
         new_node = copy.deepcopy(node)
         # name field is required
         # remove context suffix
@@ -315,7 +316,7 @@ class NetworkServiceTestCase(scenario_base.Scenario):
         self._update_context_with_topology()
 
     @classmethod
-    def get_vnf_impl(cls, vnf_model_id):
+    def get_vnf_impl(cls, vnf_model_id):  # pragma: no cover
         """ Find the implementing class from vnf_model["vnf"]["name"] field
 
         :param vnf_model_id: parsed vnfd model ID field
@@ -343,7 +344,7 @@ class NetworkServiceTestCase(scenario_base.Scenario):
         raise exceptions.IncorrectConfig(error_msg=message)
 
     @staticmethod
-    def create_interfaces_from_node(vnfd, node):
+    def create_interfaces_from_node(vnfd, node):  # pragma: no cover
         ext_intfs = vnfd["vdu"][0]["external-interface"] = []
         # have to sort so xe0 goes first
         for intf_name, intf in sorted(node['interfaces'].items()):
@@ -405,17 +406,14 @@ class NetworkServiceTestCase(scenario_base.Scenario):
                 pass
             self.create_interfaces_from_node(vnfd, node)
             vnf_impl = self.get_vnf_impl(vnfd['id'])
-            vnf_instance = vnf_impl(node_name, vnfd)
+            vnf_instance = vnf_impl(node_name, vnfd, scenario_cfg['task_id'])
             vnfs.append(vnf_instance)
 
         self.vnfs = vnfs
         return vnfs
 
     def setup(self):
-        """ Setup infrastructure, provission VNFs & start traffic
-
-        :return:
-        """
+        """Setup infrastructure, provission VNFs & start traffic"""
         # 1. Verify if infrastructure mapping can meet topology
         self.map_topology_to_infrastructure()
         # 1a. Load VNF models
@@ -457,6 +455,11 @@ class NetworkServiceTestCase(scenario_base.Scenario):
         for traffic_gen in traffic_runners:
             LOG.info("Starting traffic on %s", traffic_gen.name)
             traffic_gen.run_traffic(self.traffic_profile)
+            self._mq_ids.append(traffic_gen.get_mq_producer_id())
+
+    def get_mq_ids(self):  # pragma: no cover
+        """Return stored MQ producer IDs"""
+        return self._mq_ids
 
     def run(self, result):  # yardstick API
         """ Yardstick calls run() at intervals defined in the yaml and
@@ -495,10 +498,10 @@ class NetworkServiceTestCase(scenario_base.Scenario):
             LOG.exception("")
             raise RuntimeError("Error in teardown")
 
-    def pre_run_wait_time(self, time_seconds):
+    def pre_run_wait_time(self, time_seconds):  # pragma: no cover
         """Time waited before executing the run method"""
         time.sleep(time_seconds)
 
-    def post_run_wait_time(self, time_seconds):
+    def post_run_wait_time(self, time_seconds):  # pragma: no cover
         """Time waited after executing the run method"""
         pass
index 1ebd325..4ed40f8 100644 (file)
@@ -6,7 +6,6 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
-from __future__ import absolute_import
 
 import errno
 import os
@@ -14,11 +13,9 @@ from functools import reduce
 
 import pkg_resources
 
-# this module must only import other modules that do
-# not require loggers to be created, so this cannot
-# include yardstick.common.utils
 from yardstick.common.yaml_loader import yaml_load
 
+
 dirname = os.path.dirname
 abspath = os.path.abspath
 join = os.path.join
@@ -171,3 +168,10 @@ TESTSUITE_PRE = 'opnfv_'
 
 # OpenStack cloud default config parameters
 OS_CLOUD_DEFAULT_CONFIG = {'verify': False}
+
+# Kubernetes
+SCOPE_NAMESPACED = 'Namespaced'
+SCOPE_CLUSTER = 'Cluster'
+
+# VNF definition
+SSH_PORT = 22
index 935c778..cbb2949 100644 (file)
@@ -14,6 +14,8 @@
 
 from oslo_utils import excutils
 
+from yardstick.common import constants
+
 
 class ProcessExecutionError(RuntimeError):
     def __init__(self, message, returncode):
@@ -191,6 +193,15 @@ class TaskRenderError(YardstickException):
     message = 'Failed to render template:\n%(input_task)s'
 
 
+class RunnerIterationIPCSetupActionNeeded(YardstickException):
+    message = ('IterationIPC needs the "setup" action to retrieve the VNF '
+               'handling processes PIDs to receive the messages sent')
+
+
+class RunnerIterationIPCNoCtxs(YardstickException):
+    message = 'Benchmark "setup" action did not return any VNF process PID'
+
+
 class TimerTimeout(YardstickException):
     message = 'Timer timeout expired, %(timeout)s seconds'
 
@@ -199,10 +210,67 @@ class WaitTimeout(YardstickException):
     message = 'Wait timeout while waiting for condition'
 
 
+class KubernetesApiException(YardstickException):
+    message = ('Kubernetes API errors. Action: %(action)s, '
+               'resource: %(resource)s')
+
+
+class KubernetesConfigFileNotFound(YardstickException):
+    message = 'Config file (%s) not found' % constants.K8S_CONF_FILE
+
+
 class KubernetesTemplateInvalidVolumeType(YardstickException):
     message = 'No valid "volume" types present in %(volume)s'
 
 
+class KubernetesSSHPortNotDefined(YardstickException):
+    message = 'Port 22 needs to be defined'
+
+
+class KubernetesServiceObjectNotDefined(YardstickException):
+    message = 'ServiceObject is not defined'
+
+
+class KubernetesServiceObjectDefinitionError(YardstickException):
+    message = ('Kubernetes Service object definition error, missing '
+               'parameters: %(missing_parameters)s')
+
+
+class KubernetesServiceObjectNameError(YardstickException):
+    message = ('Kubernetes Service object name "%(name)s" does not comply'
+               'naming convention')
+
+
+class KubernetesCRDObjectDefinitionError(YardstickException):
+    message = ('Kubernetes Custom Resource Definition Object error, missing '
+               'parameters: %(missing_parameters)s')
+
+
+class KubernetesNetworkObjectDefinitionError(YardstickException):
+    message = ('Kubernetes Network object definition error, missing '
+               'parameters: %(missing_parameters)s')
+
+
+class KubernetesNetworkObjectKindMissing(YardstickException):
+    message = 'Kubernetes kind "Network" is not defined'
+
+
+class KubernetesWrongRestartPolicy(YardstickException):
+    message = 'Restart policy "%(rpolicy)s" is not valid'
+
+
+class KubernetesContainerPortNotDefined(YardstickException):
+    message = 'Container port not defined in "%(port)s"'
+
+
+class KubernetesContainerWrongImagePullPolicy(YardstickException):
+    message = 'Image pull policy must be "Always", "IfNotPresent" or "Never"'
+
+
+class KubernetesContainerCommandType(YardstickException):
+    message = '"args" and "command" must be string or list of strings'
+
+
 class ScenarioCreateNetworkError(YardstickException):
     message = 'Create Neutron Network Scenario failed'
 
index 54f7be6..5b78311 100644 (file)
@@ -26,10 +26,11 @@ class HttpClient(object):
         while True:
             try:
                 response = requests.post(url, data=data, headers=headers)
+                response.raise_for_status()
                 result = response.json()
                 logger.debug('The result is: %s', result)
                 return result
-            except Exception:
+            except Exception: # pylint: disable=broad-except
                 if time.time() > t_end:
                     logger.exception('')
                     raise
@@ -37,4 +38,5 @@ class HttpClient(object):
 
     def get(self, url):
         response = requests.get(url)
+        response.raise_for_status()
         return response.json()
index ee8e8ed..35e590f 100644 (file)
@@ -13,6 +13,8 @@ from kubernetes import config
 from kubernetes.client.rest import ApiException
 
 from yardstick.common import constants as consts
+from yardstick.common import exceptions
+
 
 LOG = logging.getLogger(__name__)
 LOG.setLevel(logging.DEBUG)
@@ -22,12 +24,26 @@ def get_core_api():     # pragma: no cover
     try:
         config.load_kube_config(config_file=consts.K8S_CONF_FILE)
     except IOError:
-        LOG.exception('config file not found')
-        raise
-
+        raise exceptions.KubernetesConfigFileNotFound()
     return client.CoreV1Api()
 
 
+def get_extensions_v1beta_api():
+    try:
+        config.load_kube_config(config_file=consts.K8S_CONF_FILE)
+    except IOError:
+        raise exceptions.KubernetesConfigFileNotFound()
+    return client.ApiextensionsV1beta1Api()
+
+
+def get_custom_objects_api():
+    try:
+        config.load_kube_config(config_file=consts.K8S_CONF_FILE)
+    except IOError:
+        raise exceptions.KubernetesConfigFileNotFound()
+    return client.CustomObjectsApi()
+
+
 def get_node_list(**kwargs):        # pragma: no cover
     core_v1_api = get_core_api()
     try:
@@ -120,8 +136,10 @@ def delete_replication_controller(name,
 def delete_pod(name,
                namespace='default',
                wait=False,
+               skip_codes=None,
                **kwargs):    # pragma: no cover
     # pylint: disable=unused-argument
+    skip_codes = [] if not skip_codes else skip_codes
     core_v1_api = get_core_api()
     body = kwargs.get('body', client.V1DeleteOptions())
     kwargs.pop('body', None)
@@ -130,9 +148,12 @@ def delete_pod(name,
                                           namespace,
                                           body,
                                           **kwargs)
-    except ApiException:
-        LOG.exception('Delete pod failed')
-        raise
+    except ApiException as e:
+        if e.status in skip_codes:
+            LOG.info(e.reason)
+        else:
+            raise exceptions.KubernetesApiException(
+                action='delete', resource='Pod')
 
 
 def read_pod(name,
@@ -187,6 +208,70 @@ def delete_config_map(name,
         raise
 
 
+def create_custom_resource_definition(body):
+    api = get_extensions_v1beta_api()
+    body_obj = client.V1beta1CustomResourceDefinition(
+        spec=body['spec'], metadata=body['metadata'])
+    try:
+        api.create_custom_resource_definition(body_obj)
+    except ValueError:
+        # NOTE(ralonsoh): bug in kubernetes-client/python 6.0.0
+        # https://github.com/kubernetes-client/python/issues/491
+        pass
+    except ApiException:
+        raise exceptions.KubernetesApiException(
+            action='create', resource='CustomResourceDefinition')
+
+
+def delete_custom_resource_definition(name):
+    api = get_extensions_v1beta_api()
+    body_obj = client.V1DeleteOptions()
+    try:
+        api.delete_custom_resource_definition(name, body_obj)
+    except ApiException:
+        raise exceptions.KubernetesApiException(
+            action='delete', resource='CustomResourceDefinition')
+
+
+def get_custom_resource_definition(kind):
+    api = get_extensions_v1beta_api()
+    try:
+        crd_list = api.list_custom_resource_definition()
+        for crd_obj in (crd_obj for crd_obj in crd_list.items
+                        if crd_obj.spec.names.kind == kind):
+            return crd_obj
+        return None
+    except ApiException:
+        raise exceptions.KubernetesApiException(
+            action='delete', resource='CustomResourceDefinition')
+
+
+def create_network(scope, group, version, plural, body, namespace='default'):
+    api = get_custom_objects_api()
+    try:
+        if scope == consts.SCOPE_CLUSTER:
+            api.create_cluster_custom_object(group, version, plural, body)
+        else:
+            api.create_namespaced_custom_object(
+                group, version, namespace, plural, body)
+    except ApiException:
+        raise exceptions.KubernetesApiException(
+            action='create', resource='Custom Object: Network')
+
+
+def delete_network(scope, group, version, plural, name, namespace='default'):
+    api = get_custom_objects_api()
+    try:
+        if scope == consts.SCOPE_CLUSTER:
+            api.delete_cluster_custom_object(group, version, plural, name, {})
+        else:
+            api.delete_namespaced_custom_object(
+                group, version, namespace, plural, name, {})
+    except ApiException:
+        raise exceptions.KubernetesApiException(
+            action='delete', resource='Custom Object: Network')
+
+
 def get_pod_list(namespace='default'):      # pragma: no cover
     core_v1_api = get_core_api()
     try:
index f0f012e..bd700d9 100644 (file)
@@ -1,14 +1,3 @@
-# Copyright (c) 2018 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.
 
@@ -28,9 +17,17 @@ TRANSPORT_URL = (MQ_SERVICE + '://' + MQ_USER + ':' + MQ_PASS + '@' + SERVER +
 RPC_SERVER_EXECUTOR = 'threading'
 
 # Topics.
-RUNNER = 'runner'
+TOPIC_TG = 'topic_traffic_generator'
+TOPIC_RUNNER = 'topic_runner'
 
 # Methods.
-# RUNNER methods:
-RUNNER_INFO = 'runner_info'
-RUNNER_LOOP = 'runner_loop'
+# Traffic generator consumers methods. Names must match the methods implemented
+# in the consumer endpoint class.
+TG_METHOD_STARTED = 'tg_method_started'
+TG_METHOD_FINISHED = 'tg_method_finished'
+TG_METHOD_ITERATION = 'tg_method_iteration'
+
+# Runner consumers methods. Names must match the methods implemented in the
+# consumer endpoint class.
+RUNNER_METHOD_START_ITERATION = "runner_method_start_iteration"
+RUNNER_METHOD_STOP_ITERATION = "runner_method_stop_iteration"
index 24ec6f1..7ce9bda 100644 (file)
@@ -29,9 +29,10 @@ LOG = logging.getLogger(__name__)
 class NotificationHandler(object):
     """Abstract class to define a endpoint object for a MessagingConsumer"""
 
-    def __init__(self, _id, ctx_pids, queue):
+    def __init__(self, _id, ctx_ids, queue):
+        super(NotificationHandler, self).__init__()
         self._id = _id
-        self._ctx_pids = ctx_pids
+        self._ctx_ids = ctx_ids
         self._queue = queue
 
 
@@ -43,11 +44,11 @@ class MessagingConsumer(object):
     the messages published by a `MessagingNotifier`.
     """
 
-    def __init__(self, topic, pids, endpoints, fanout=True):
+    def __init__(self, topic, ids, endpoints, fanout=True):
         """Init function.
 
         :param topic: (string) MQ exchange topic
-        :param pids: (list of int) list of PIDs of the processes implementing
+        :param ids: (list of int) list of IDs of the processes implementing
                      the MQ Notifier which will be in the message context
         :param endpoints: (list of class) list of classes implementing the
                           methods (see `MessagingNotifier.send_message) used by
@@ -58,7 +59,7 @@ class MessagingConsumer(object):
         :returns: `MessagingConsumer` class object
         """
 
-        self._pids = pids
+        self._ids = ids
         self._endpoints = endpoints
         self._transport = oslo_messaging.get_rpc_transport(
             cfg.CONF, url=messaging.TRANSPORT_URL)
index d29d798..8ede1e5 100644 (file)
@@ -51,3 +51,23 @@ class Payload(object):
     def dict_to_obj(cls, _dict):
         """Returns a Payload object built from the dictionary elements"""
         return cls(**_dict)
+
+
+class TrafficGeneratorPayload(Payload):
+    """Base traffic generator payload class"""
+    REQUIRED_FIELDS = {
+        'version',  # (str) version of the payload transmitted.
+        'iteration',  # (int) iteration index during the traffic injection,
+                      # starting from 1.
+        'kpi'  # (dict) collection of KPIs collected from the traffic
+               # injection. The content will depend on the generator and the
+               # traffic type.
+    }
+
+
+class RunnerPayload(Payload):
+    """Base runner payload class"""
+    REQUIRED_FIELDS = {
+        'version',  # (str) version of the payload transmitted.
+        'data'  # (dict) generic container of data to be used if needed.
+    }
index b6adc0c..aadab64 100644 (file)
@@ -34,18 +34,18 @@ class MessagingProducer(object):
     messages in a message queue.
     """
 
-    def __init__(self, topic, pid=os.getpid(), fanout=True):
+    def __init__(self, topic, _id=os.getpid(), fanout=True):
         """Init function.
 
         :param topic: (string) MQ exchange topic
-        :param pid: (int) PID of the process implementing this MQ Notifier
+        :param id: (int) ID of the process implementing this MQ Notifier
         :param fanout: (bool) MQ clients may request that a copy of the message
                        be delivered to all servers listening on a topic by
                        setting fanout to ``True``, rather than just one of them
         :returns: `MessagingNotifier` class object
         """
         self._topic = topic
-        self._pid = pid
+        self._id = _id
         self._fanout = fanout
         self._transport = oslo_messaging.get_rpc_transport(
             cfg.CONF, url=messaging.TRANSPORT_URL)
@@ -65,6 +65,11 @@ class MessagingProducer(object):
                        consumer endpoints
         :param payload: (subclass `Payload`) payload content
         """
-        self._notifier.cast({'pid': self._pid},
+        self._notifier.cast({'id': self._id},
                             method,
                             **payload.obj_to_dict())
+
+    @property
+    def id(self):
+        """Return MQ producer ID"""
+        return self._id
index f9fe0e3..85cecc7 100644 (file)
@@ -527,3 +527,25 @@ def wait_until_true(predicate, timeout=60, sleep=1, exception=None):
         if exception and issubclass(exception, Exception):
             raise exception  # pylint: disable=raising-bad-type
         raise exceptions.WaitTimeout
+
+
+def send_socket_command(host, port, command):
+    """Send a string command to a specific port in a host
+
+    :param host: (str) ip or hostname of the host
+    :param port: (int) port number
+    :param command: (str) command to send
+    :return: 0 if success, error number if error
+    """
+    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    ret = 0
+    try:
+        err_number = sock.connect_ex((host, int(port)))
+        if err_number != 0:
+            return err_number
+        sock.sendall(six.b(command))
+    except Exception:  # pylint: disable=broad-except
+        ret = 1
+    finally:
+        sock.close()
+    return ret
index 937c266..0c6d977 100644 (file)
@@ -11,7 +11,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.
-"""This module implements stub for publishing results in yardstick format."""
+
 import logging
 
 from yardstick.network_services.nfvi.resource import ResourceProfile
@@ -31,12 +31,13 @@ class Collector(object):
         self.bin_path = get_nsb_option('bin_path', '')
         self.resource_profiles = {}
 
-        for ctx_name, nodes in contexts_nodes.items():
-            for node in (node for node in nodes if node.get('collectd')):
+        for ctx_name, nodes in ((ctx_name, nodes) for (ctx_name, nodes)
+                                in contexts_nodes.items() if nodes):
+            for node in (node for node in nodes
+                         if node and node.get('collectd')):
                 name = ".".join([node['name'], ctx_name])
                 self.resource_profiles.update(
-                    {name: ResourceProfile.make_from_node(node, timeout)}
-                    )
+                    {name: ResourceProfile.make_from_node(node, timeout)})
 
     def start(self):
         for resource in self.resource_profiles.values():
index 393f60f..74deeec 100644 (file)
@@ -166,9 +166,10 @@ class IxNextgen(object):  # pragma: no cover
         :return: list of paired frame sizes and weights
         """
         weighted_range_pairs = []
-        for size, weight in framesize.items():
-            weighted_range_pairs.append(int(size.upper().replace('B', '')))
-            weighted_range_pairs.append(int(weight))
+        for size, weight in ((s, w) for (s, w) in framesize.items()
+                             if int(w) != 0):
+            size = int(size.upper().replace('B', ''))
+            weighted_range_pairs.append([size, size, int(weight)])
         return weighted_range_pairs
 
     def iter_over_get_lists(self, x1, x2, y2, offset=0):
@@ -339,7 +340,7 @@ class IxNextgen(object):  # pragma: no cover
                         "percentLineRate" no used)
         - Frame size: custom IMIX [1] definition; a list of packet size in
                       bytes and the weight. E.g.:
-                      [64, 10, 128, 15, 512, 5]
+                      [[64, 64, 10], [128, 128, 15], [512, 512, 5]]
 
         [1] https://en.wikipedia.org/wiki/Internet_Mix
 
index 1357f6b..8e9bc87 100644 (file)
@@ -246,8 +246,9 @@ class AclApproxVnf(SampleVNF):
         'packets_dropped': 2,
     }
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if setup_env_helper_type is None:
             setup_env_helper_type = AclApproxSetupEnvSetupEnvHelper
-
-        super(AclApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type)
+        super(AclApproxVnf, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
index 9ceac31..0fb3100 100644 (file)
 # 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.
-""" Base class implementation for generic vnf implementation """
 
 import abc
 
 import logging
 import six
 
+from yardstick.common import messaging
+from yardstick.common.messaging import consumer
+from yardstick.common.messaging import payloads
+from yardstick.common.messaging import producer
 from yardstick.network_services.helpers.samplevnf_helper import PortPairs
 
 
@@ -138,6 +141,70 @@ class VnfdHelper(dict):
             yield port_name, port_num
 
 
+class TrafficGeneratorProducer(producer.MessagingProducer):
+    """Class implementing the message producer for traffic generators
+
+    This message producer must be instantiated in the process created
+    "run_traffic" process.
+    """
+    def __init__(self, _id):
+        super(TrafficGeneratorProducer, self).__init__(messaging.TOPIC_TG,
+                                                       _id=_id)
+
+    def tg_method_started(self, version=1):
+        """Send a message to inform the traffic generation has started"""
+        self.send_message(
+            messaging.TG_METHOD_STARTED,
+            payloads.TrafficGeneratorPayload(version=version, iteration=0,
+                                             kpi={}))
+
+    def tg_method_finished(self, version=1):
+        """Send a message to inform the traffic generation has finished"""
+        self.send_message(
+            messaging.TG_METHOD_FINISHED,
+            payloads.TrafficGeneratorPayload(version=version, iteration=0,
+                                             kpi={}))
+
+    def tg_method_iteration(self, iteration, version=1, kpi=None):
+        """Send a message, with KPI, once an iteration has finished"""
+        kpi = {} if kpi is None else kpi
+        self.send_message(
+            messaging.TG_METHOD_ITERATION,
+            payloads.TrafficGeneratorPayload(version=version,
+                                             iteration=iteration, kpi=kpi))
+
+
+@six.add_metaclass(abc.ABCMeta)
+class GenericVNFEndpoint(consumer.NotificationHandler):
+    """Endpoint class for ``GenericVNFConsumer``"""
+
+    @abc.abstractmethod
+    def runner_method_start_iteration(self, ctxt, **kwargs):
+        """Endpoint when RUNNER_METHOD_START_ITERATION is received
+
+        :param ctxt: (dict) {'id': <Producer ID>}
+        :param kwargs: (dict) ``payloads.RunnerPayload`` context
+        """
+
+    @abc.abstractmethod
+    def runner_method_stop_iteration(self, ctxt, **kwargs):
+        """Endpoint when RUNNER_METHOD_STOP_ITERATION is received
+
+        :param ctxt: (dict) {'id': <Producer ID>}
+        :param kwargs: (dict) ``payloads.RunnerPayload`` context
+        """
+
+
+class GenericVNFConsumer(consumer.MessagingConsumer):
+    """MQ consumer for ``GenericVNF`` derived classes"""
+
+    def __init__(self, ctx_ids, endpoints):
+        if not isinstance(endpoints, list):
+            endpoints = [endpoints]
+        super(GenericVNFConsumer, self).__init__(messaging.TOPIC_RUNNER,
+                                                 ctx_ids, endpoints)
+
+
 @six.add_metaclass(abc.ABCMeta)
 class GenericVNF(object):
     """Class providing file-like API for generic VNF implementation
@@ -150,8 +217,9 @@ class GenericVNF(object):
     UPLINK = PortPairs.UPLINK
     DOWNLINK = PortPairs.DOWNLINK
 
-    def __init__(self, name, vnfd):
+    def __init__(self, name, vnfd, task_id):
         self.name = name
+        self._task_id = task_id
         self.vnfd_helper = VnfdHelper(vnfd)
         # List of statistics we can obtain from this VNF
         # - ETSI MANO 6.3.1.1 monitoring_parameter
@@ -210,12 +278,13 @@ class GenericVNF(object):
 
 @six.add_metaclass(abc.ABCMeta)
 class GenericTrafficGen(GenericVNF):
-    """ Class providing file-like API for generic traffic generator """
+    """Class providing file-like API for generic traffic generator"""
 
-    def __init__(self, name, vnfd):
-        super(GenericTrafficGen, self).__init__(name, vnfd)
+    def __init__(self, name, vnfd, task_id):
+        super(GenericTrafficGen, self).__init__(name, vnfd, task_id)
         self.runs_traffic = True
         self.traffic_finished = False
+        self._mq_producer = None
 
     @abc.abstractmethod
     def run_traffic(self, traffic_profile):
@@ -286,3 +355,16 @@ class GenericTrafficGen(GenericVNF):
         :return: True/False
         """
         pass
+
+    @staticmethod
+    def _setup_mq_producer(id):
+        """Setup the TG MQ producer to send messages between processes
+
+        :return: (derived class from ``MessagingProducer``) MQ producer object
+        """
+        return TrafficGeneratorProducer(id)
+
+    def get_mq_producer_id(self):
+        """Return the MQ producer ID if initialized"""
+        if self._mq_producer:
+            return self._mq_producer.id
index bfe628f..14f1e2e 100644 (file)
@@ -85,12 +85,12 @@ class CgnaptApproxVnf(SampleVNF):
         "packets_dropped": 4,
     }
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if setup_env_helper_type is None:
             setup_env_helper_type = CgnaptApproxSetupEnvHelper
-
-        super(CgnaptApproxVnf, self).__init__(name, vnfd, setup_env_helper_type,
-                                              resource_helper_type)
+        super(CgnaptApproxVnf, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
 
     def _vnf_up_post(self):
         super(CgnaptApproxVnf, self)._vnf_up_post()
index 6d28f47..3241719 100644 (file)
@@ -969,7 +969,7 @@ class ProxResourceHelper(ClientResourceHelper):
             self._test_type = self.setup_helper.find_in_section('global', 'name', None)
         return self._test_type
 
-    def run_traffic(self, traffic_profile):
+    def run_traffic(self, traffic_profile, *args):
         self._queue.cancel_join_thread()
         self.lower = 0.0
         self.upper = 100.0
index bc810ec..839f309 100644 (file)
@@ -34,7 +34,8 @@ class ProxApproxVnf(SampleVNF):
     VNF_PROMPT = "PROX started"
     LUA_PARAMETER_NAME = "sut"
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if setup_env_helper_type is None:
             setup_env_helper_type = ProxDpdkVnfSetupEnvHelper
 
@@ -45,8 +46,8 @@ class ProxApproxVnf(SampleVNF):
         self.prev_packets_sent = 0
         self.prev_tsc = 0
         self.tsc_hz = 0
-        super(ProxApproxVnf, self).__init__(name, vnfd, setup_env_helper_type,
-                                            resource_helper_type)
+        super(ProxApproxVnf, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
 
     def _vnf_up_post(self):
         self.resource_helper.up_post()
index 90b7b21..e99de9c 100644 (file)
@@ -34,7 +34,8 @@ class RouterVNF(SampleVNF):
 
     WAIT_TIME = 1
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if setup_env_helper_type is None:
             setup_env_helper_type = DpdkVnfSetupEnvHelper
 
@@ -42,7 +43,8 @@ class RouterVNF(SampleVNF):
         vnfd['mgmt-interface'].pop("pkey", "")
         vnfd['mgmt-interface']['password'] = 'password'
 
-        super(RouterVNF, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type)
+        super(RouterVNF, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
 
     def instantiate(self, scenario_cfg, context_cfg):
         self.scenario_helper.scenario_cfg = scenario_cfg
index 1ee71aa..3ef7c33 100644 (file)
 
 import logging
 from multiprocessing import Queue, Value, Process
-
 import os
 import posixpath
 import re
-import six
+import uuid
 import subprocess
 import time
 
+import six
+
 from trex_stl_lib.trex_stl_client import LoggerApi
 from trex_stl_lib.trex_stl_client import STLClient
 from trex_stl_lib.trex_stl_exceptions import STLError
@@ -408,12 +409,13 @@ class ClientResourceHelper(ResourceHelper):
         time.sleep(self.QUEUE_WAIT_TIME)
         self._queue.put(samples)
 
-    def run_traffic(self, traffic_profile):
+    def run_traffic(self, traffic_profile, mq_producer):
         # if we don't do this we can hang waiting for the queue to drain
         # have to do this in the subprocess
         self._queue.cancel_join_thread()
         # fixme: fix passing correct trex config file,
         # instead of searching the default path
+        mq_producer.tg_method_started()
         try:
             self._build_ports()
             self.client = self._connect()
@@ -421,8 +423,11 @@ class ClientResourceHelper(ResourceHelper):
             self.client.remove_all_streams(self.all_ports)  # remove all streams
             traffic_profile.register_generator(self)
 
+            iteration_index = 0
             while self._terminated.value == 0:
+                iteration_index += 1
                 self._run_traffic_once(traffic_profile)
+                mq_producer.tg_method_iteration(iteration_index)
 
             self.client.stop(self.all_ports)
             self.client.disconnect()
@@ -433,6 +438,8 @@ class ClientResourceHelper(ResourceHelper):
                 return  # return if trex/tg server is stopped.
             raise
 
+        mq_producer.tg_method_finished()
+
     def terminate(self):
         self._terminated.value = 1  # stop client
 
@@ -612,6 +619,7 @@ class ScenarioHelper(object):
         test_timeout = self.options.get('timeout', constants.DEFAULT_VNF_TIMEOUT)
         return test_duration if test_duration > test_timeout else test_timeout
 
+
 class SampleVNF(GenericVNF):
     """ Class providing file-like API for generic VNF implementation """
 
@@ -621,8 +629,9 @@ class SampleVNF(GenericVNF):
     APP_NAME = "SampleVNF"
     # we run the VNF interactively, so the ssh command will timeout after this long
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
-        super(SampleVNF, self).__init__(name, vnfd)
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
+        super(SampleVNF, self).__init__(name, vnfd, task_id)
         self.bin_path = get_nsb_option('bin_path', '')
 
         self.scenario_helper = ScenarioHelper(self.name)
@@ -853,8 +862,9 @@ class SampleVNFTrafficGen(GenericTrafficGen):
     APP_NAME = 'Sample'
     RUN_WAIT = 1
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
-        super(SampleVNFTrafficGen, self).__init__(name, vnfd)
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
+        super(SampleVNFTrafficGen, self).__init__(name, vnfd, task_id)
         self.bin_path = get_nsb_option('bin_path', '')
 
         self.scenario_helper = ScenarioHelper(self.name)
@@ -911,12 +921,13 @@ class SampleVNFTrafficGen(GenericTrafficGen):
                 LOG.info("%s TG Server is up and running.", self.APP_NAME)
                 return self._tg_process.exitcode
 
-    def _traffic_runner(self, traffic_profile):
+    def _traffic_runner(self, traffic_profile, mq_id):
         # always drop connections first thing in new processes
         # so we don't get paramiko errors
         self.ssh_helper.drop_connection()
         LOG.info("Starting %s client...", self.APP_NAME)
-        self.resource_helper.run_traffic(traffic_profile)
+        self._mq_producer = self._setup_mq_producer(mq_id)
+        self.resource_helper.run_traffic(traffic_profile, self._mq_producer)
 
     def run_traffic(self, traffic_profile):
         """ Generate traffic on the wire according to the given params.
@@ -926,10 +937,12 @@ class SampleVNFTrafficGen(GenericTrafficGen):
         :param traffic_profile:
         :return: True/False
         """
-        name = "{}-{}-{}-{}".format(self.name, self.APP_NAME, traffic_profile.__class__.__name__,
+        name = '{}-{}-{}-{}'.format(self.name, self.APP_NAME,
+                                    traffic_profile.__class__.__name__,
                                     os.getpid())
-        self._traffic_process = Process(name=name, target=self._traffic_runner,
-                                        args=(traffic_profile,))
+        self._traffic_process = Process(
+            name=name, target=self._traffic_runner,
+            args=(traffic_profile, uuid.uuid1().int))
         self._traffic_process.start()
         # Wait for traffic process to start
         while self.resource_helper.client_started.value == 0:
@@ -938,8 +951,6 @@ class SampleVNFTrafficGen(GenericTrafficGen):
             if not self._traffic_process.is_alive():
                 break
 
-        return self._traffic_process.is_alive()
-
     def collect_kpi(self):
         # check if the tg processes have exited
         physical_node = Context.get_physical_node_from_server(
index 102c66f..e0fc47d 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from __future__ import absolute_import
+import collections
 import csv
 import glob
 import logging
 import os
 import shutil
-
-from collections import OrderedDict
 import subprocess
 
 from yardstick.common import utils
@@ -65,7 +63,7 @@ class IxLoadResourceHelper(ClientResourceHelper):
 
     RESULTS_MOUNT = "/mnt/Results"
 
-    KPI_LIST = OrderedDict((
+    KPI_LIST = collections.OrderedDict((
         ('http_throughput', 'HTTP Total Throughput (Kbps)'),
         ('simulated_users', 'HTTP Simulated Users'),
         ('concurrent_connections', 'HTTP Concurrent Connections'),
@@ -75,7 +73,8 @@ class IxLoadResourceHelper(ClientResourceHelper):
 
     def __init__(self, setup_helper):
         super(IxLoadResourceHelper, self).__init__(setup_helper)
-        self.result = OrderedDict((key, ResourceDataHelper()) for key in self.KPI_LIST)
+        self.result = collections.OrderedDict((key, ResourceDataHelper())
+                                              for key in self.KPI_LIST)
         self.resource_file_name = ''
         self.data = None
 
@@ -124,12 +123,13 @@ class IxLoadResourceHelper(ClientResourceHelper):
 
 class IxLoadTrafficGen(SampleVNFTrafficGen):
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if resource_helper_type is None:
             resource_helper_type = IxLoadResourceHelper
 
-        super(IxLoadTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
-                                               resource_helper_type)
+        super(IxLoadTrafficGen, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
         self._result = {}
 
     def run_traffic(self, traffic_profile):
index a989543..a3b5afa 100644 (file)
@@ -71,7 +71,7 @@ class PingResourceHelper(ClientResourceHelper):
         self._queue = Queue()
         self._parser = PingParser(self._queue)
 
-    def run_traffic(self, traffic_profile):
+    def run_traffic(self, traffic_profile, *args):
         # drop the connection in order to force a new one
         self.ssh_helper.drop_connection()
 
@@ -103,14 +103,14 @@ class PingTrafficGen(SampleVNFTrafficGen):
     APP_NAME = 'Ping'
     RUN_WAIT = 4
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if setup_env_helper_type is None:
             setup_env_helper_type = PingSetupEnvHelper
         if resource_helper_type is None:
             resource_helper_type = PingResourceHelper
-
-        super(PingTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
-                                             resource_helper_type)
+        super(PingTrafficGen, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
         self._result = {}
 
     def _check_status(self):
index 282dd92..854319a 100644 (file)
@@ -30,9 +30,11 @@ class ProxTrafficGen(SampleVNFTrafficGen):
     LUA_PARAMETER_NAME = "gen"
     WAIT_TIME = 1
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         # don't call superclass, use custom wrapper of ProxApproxVnf
-        self._vnf_wrapper = ProxApproxVnf(name, vnfd, setup_env_helper_type, resource_helper_type)
+        self._vnf_wrapper = ProxApproxVnf(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
         self.bin_path = get_nsb_option('bin_path', '')
         self.name = self._vnf_wrapper.name
         self.ssh_helper = self._vnf_wrapper.ssh_helper
index a1f9fbe..4d3bc2c 100644 (file)
@@ -102,7 +102,7 @@ class IxiaResourceHelper(ClientResourceHelper):
         self.client.assign_ports()
         self.client.create_traffic_model()
 
-    def run_traffic(self, traffic_profile):
+    def run_traffic(self, traffic_profile, *args):
         if self._terminated.value:
             return
 
@@ -157,12 +157,12 @@ class IxiaTrafficGen(SampleVNFTrafficGen):
 
     APP_NAME = 'Ixia'
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if resource_helper_type is None:
             resource_helper_type = IxiaResourceHelper
-
-        super(IxiaTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
-                                             resource_helper_type)
+        super(IxiaTrafficGen, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
         self._ixia_traffic_gen = None
         self.ixia_file_name = ''
         self.vnf_port_pairs = []
index 07cec67..cdbb414 100644 (file)
@@ -64,9 +64,9 @@ class TrexTrafficGenRFC(tg_trex.TrexTrafficGen):
     traffic for rfc2544 testcase.
     """
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if resource_helper_type is None:
             resource_helper_type = TrexRfcResourceHelper
-
-        super(TrexTrafficGenRFC, self).__init__(name, vnfd, setup_env_helper_type,
-                                                resource_helper_type)
+        super(TrexTrafficGenRFC, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
index 80b42e2..58b7348 100644 (file)
@@ -198,15 +198,14 @@ class TrexTrafficGen(SampleVNFTrafficGen):
 
     APP_NAME = 'TRex'
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if resource_helper_type is None:
             resource_helper_type = TrexResourceHelper
-
         if setup_env_helper_type is None:
             setup_env_helper_type = TrexDpdkVnfSetupEnvHelper
-
-        super(TrexTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
-                                             resource_helper_type)
+        super(TrexTrafficGen, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
 
     def _check_status(self):
         return self.resource_helper.check_status()
index fa92744..e3fde1a 100644 (file)
@@ -60,15 +60,14 @@ class UdpReplayApproxVnf(SampleVNF):
 
     PIPELINE_COMMAND = REPLAY_PIPELINE_COMMAND
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if resource_helper_type is None:
             resource_helper_type = UdpReplayResourceHelper
-
         if setup_env_helper_type is None:
             setup_env_helper_type = UdpReplaySetupEnvHelper
-
-        super(UdpReplayApproxVnf, self).__init__(name, vnfd, setup_env_helper_type,
-                                                 resource_helper_type)
+        super(UdpReplayApproxVnf, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
 
     def _build_pipeline_kwargs(self):
         ports = self.vnfd_helper.port_pairs.all_ports
index 432f30a..a1523de 100644 (file)
@@ -52,8 +52,9 @@ class FWApproxVnf(SampleVNF):
         'packets_dropped': 3,
     }
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if setup_env_helper_type is None:
             setup_env_helper_type = FWApproxSetupEnvHelper
-
-        super(FWApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type)
+        super(FWApproxVnf, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
index 57ea2ee..b7cf8b3 100644 (file)
@@ -239,7 +239,7 @@ class ConfigCreate(object):
 
 class VpeApproxSetupEnvHelper(DpdkVnfSetupEnvHelper):
 
-    APP_NAME = 'vPE'
+    APP_NAME = 'vPE_vnf'
     CFG_CONFIG = "/tmp/vpe_config"
     CFG_SCRIPT = "/tmp/vpe_script"
     TM_CONFIG = "/tmp/full_tm_profile_10G.cfg"
@@ -286,16 +286,17 @@ class VpeApproxSetupEnvHelper(DpdkVnfSetupEnvHelper):
 class VpeApproxVnf(SampleVNF):
     """ This class handles vPE VNF model-driver definitions """
 
-    APP_NAME = 'vPE'
+    APP_NAME = 'vPE_vnf'
     APP_WORD = 'vpe'
     COLLECT_KPI = VPE_COLLECT_KPI
     WAIT_TIME = 20
 
-    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
+                 resource_helper_type=None):
         if setup_env_helper_type is None:
             setup_env_helper_type = VpeApproxSetupEnvHelper
-
-        super(VpeApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type)
+        super(VpeApproxVnf, self).__init__(
+            name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
 
     def get_stats(self, *args, **kwargs):
         raise NotImplementedError
index 8ccb988..8d9fc41 100644 (file)
@@ -8,25 +8,49 @@
 ##############################################################################
 
 import copy
+import re
 
+from oslo_serialization import jsonutils
+import six
+
+from yardstick.common import constants
 from yardstick.common import exceptions
-from yardstick.common import utils
 from yardstick.common import kubernetes_utils as k8s_utils
+from yardstick.common import utils
 
 
 class ContainerObject(object):
 
     SSH_MOUNT_PATH = '/tmp/.ssh/'
     IMAGE_DEFAULT = 'openretriever/yardstick'
-    COMMAND_DEFAULT = '/bin/bash'
+    COMMAND_DEFAULT = ['/bin/bash', '-c']
+    RESOURCES = ('requests', 'limits')
+    PORT_OPTIONS = ('containerPort', 'hostIP', 'hostPort', 'name', 'protocol')
+    IMAGE_PULL_POLICY = ('Always', 'IfNotPresent', 'Never')
 
     def __init__(self, name, ssh_key, **kwargs):
         self._name = name
         self._ssh_key = ssh_key
         self._image = kwargs.get('image', self.IMAGE_DEFAULT)
-        self._command = [kwargs.get('command', self.COMMAND_DEFAULT)]
-        self._args = kwargs.get('args', [])
+        self._command = self._parse_commands(
+            kwargs.get('command', self.COMMAND_DEFAULT))
+        self._args = self._parse_commands(kwargs.get('args', []))
         self._volume_mounts = kwargs.get('volumeMounts', [])
+        self._security_context = kwargs.get('securityContext')
+        self._env = kwargs.get('env', [])
+        self._resources = kwargs.get('resources', {})
+        self._ports = kwargs.get('ports', [])
+        self._image_pull_policy = kwargs.get('imagePullPolicy')
+        self._tty = kwargs.get('tty')
+        self._stdin = kwargs.get('stdin')
+
+    @staticmethod
+    def _parse_commands(command):
+        if isinstance(command, six.string_types):
+            return [command]
+        elif isinstance(command, list):
+            return command
+        raise exceptions.KubernetesContainerCommandType()
 
     def _create_volume_mounts(self):
         """Return all "volumeMounts" items per container"""
@@ -47,24 +71,63 @@ class ContainerObject(object):
     def get_container_item(self):
         """Create a "container" item"""
         container_name = '{}-container'.format(self._name)
-        return {'args': self._args,
-                'command': self._command,
-                'image': self._image,
-                'name': container_name,
-                'volumeMounts': self._create_volume_mounts()}
-
-
-class KubernetesObject(object):
+        container = {'args': self._args,
+                     'command': self._command,
+                     'image': self._image,
+                     'name': container_name,
+                     'volumeMounts': self._create_volume_mounts()}
+        if self._security_context:
+            container['securityContext'] = self._security_context
+        if self._env:
+            container['env'] = []
+            for env in self._env:
+                container['env'].append({'name': env['name'],
+                                         'value': env['value']})
+        if self._ports:
+            container['ports'] = []
+            for port in self._ports:
+                if 'containerPort' not in port.keys():
+                    raise exceptions.KubernetesContainerPortNotDefined(
+                        port=port)
+                _port = {port_option: value for port_option, value
+                         in port.items() if port_option in self.PORT_OPTIONS}
+                container['ports'].append(_port)
+        if self._resources:
+            container['resources'] = {}
+            for res in (res for res in self._resources if
+                        res in self.RESOURCES):
+                container['resources'][res] = self._resources[res]
+        if self._image_pull_policy:
+            if self._image_pull_policy not in self.IMAGE_PULL_POLICY:
+                raise exceptions.KubernetesContainerWrongImagePullPolicy()
+            container['imagePullPolicy'] = self._image_pull_policy
+        if self._stdin is not None:
+            container['stdin'] = self._stdin
+        if self._tty is not None:
+            container['tty'] = self._tty
+        return container
+
+
+class ReplicationControllerObject(object):
 
     SSHKEY_DEFAULT = 'yardstick_key'
+    RESTART_POLICY = ('Always', 'OnFailure', 'Never')
+    TOLERATIONS_KEYS = ('key', 'value', 'effect', 'operator')
 
     def __init__(self, name, **kwargs):
-        super(KubernetesObject, self).__init__()
+        super(ReplicationControllerObject, self).__init__()
         parameters = copy.deepcopy(kwargs)
         self.name = name
         self.node_selector = parameters.pop('nodeSelector', {})
         self.ssh_key = parameters.pop('ssh_key', self.SSHKEY_DEFAULT)
         self._volumes = parameters.pop('volumes', [])
+        self._security_context = parameters.pop('securityContext', None)
+        self._networks = parameters.pop('networks', [])
+        self._tolerations = parameters.pop('tolerations', [])
+        self._restart_policy = parameters.pop('restartPolicy', 'Always')
+        if self._restart_policy not in self.RESTART_POLICY:
+            raise exceptions.KubernetesWrongRestartPolicy(
+                rpolicy=self._restart_policy)
 
         containers = parameters.pop('containers', None)
         if containers:
@@ -85,14 +148,14 @@ class KubernetesObject(object):
                 "replicas": 1,
                 "template": {
                     "metadata": {
-                        "labels": {
-                            "app": name
-                        }
+                        "labels": {"app": name}
                     },
                     "spec": {
                         "containers": [],
                         "volumes": [],
-                        "nodeSelector": {}
+                        "nodeSelector": {},
+                        "restartPolicy": self._restart_policy,
+                        "tolerations": []
                     }
                 }
             }
@@ -102,6 +165,13 @@ class KubernetesObject(object):
         self._add_containers()
         self._add_node_selector()
         self._add_volumes()
+        self._add_security_context()
+        self._add_networks()
+        self._add_tolerations()
+
+    @property
+    def networks(self):
+        return self._networks
 
     def get_template(self):
         return self.template
@@ -153,34 +223,225 @@ class KubernetesObject(object):
         return {'name': name,
                 type_name: type_data}
 
+    def _add_security_context(self):
+        if self._security_context:
+            utils.set_dict_value(self.template,
+                                 'spec.template.spec.securityContext',
+                                 self._security_context)
+
+    def _add_networks(self):
+        networks = []
+        for net in self._networks:
+            networks.append({'name': net})
+
+        if not networks:
+            return
+
+        annotations = {'networks': jsonutils.dumps(networks)}
+        utils.set_dict_value(self.template,
+                             'spec.template.metadata.annotations',
+                             annotations)
+
+    def _add_tolerations(self):
+        tolerations = []
+        for tol in self._tolerations:
+            tolerations.append({k: tol[k] for k in tol
+                                if k in self.TOLERATIONS_KEYS})
+
+        tolerations = ([{'operator': 'Exists'}] if not tolerations
+                       else tolerations)
+        utils.set_dict_value(self.template,
+                             'spec.template.spec.tolerations',
+                             tolerations)
 
-class ServiceObject(object):
 
-    def __init__(self, name):
-        self.name = '{}-service'.format(name)
+class ServiceNodePortObject(object):
+
+    MANDATORY_PARAMETERS = {'port', 'name'}
+    NAME_REGEX = re.compile(r'^[a-z0-9]([-a-z0-9]*[a-z0-9])?$')
+
+    def __init__(self, name, **kwargs):
+        """Service kind "NodePort" object
+
+        :param name: (string) name of the Service
+        :param kwargs: (dict) node_ports -> (list) port, name, targetPort,
+                                                   nodePort
+        """
+        self._name = '{}-service'.format(name)
         self.template = {
-            'metadata': {
-                'name': '{}-service'.format(name)
-            },
+            'metadata': {'name': '{}-service'.format(name)},
             'spec': {
                 'type': 'NodePort',
-                'ports': [
-                    {
-                        'port': 22,
-                        'protocol': 'TCP'
-                    }
-                ],
-                'selector': {
-                    'app': name
-                }
+                'ports': [],
+                'selector': {'app': name}
             }
         }
 
+        self._add_port(22, 'ssh', protocol='TCP')
+        node_ports = copy.deepcopy(kwargs.get('node_ports', []))
+        for port in node_ports:
+            if not self.MANDATORY_PARAMETERS.issubset(port.keys()):
+                missing_parameters = ', '.join(
+                    str(param) for param in
+                    (self.MANDATORY_PARAMETERS - set(port.keys())))
+                raise exceptions.KubernetesServiceObjectDefinitionError(
+                    missing_parameters=missing_parameters)
+            port_number = port.pop('port')
+            name = port.pop('name')
+            if not self.NAME_REGEX.match(name):
+                raise exceptions.KubernetesServiceObjectNameError(name=name)
+            self._add_port(port_number, name, **port)
+
+    def _add_port(self, port, name, protocol=None, targetPort=None,
+                  nodePort=None):
+        _port = {'port': port,
+                 'name': name}
+        if protocol:
+            _port['protocol'] = protocol
+        if targetPort:
+            _port['targetPort'] = targetPort
+        if nodePort:
+            _port['nodePort'] = nodePort
+        self.template['spec']['ports'].append(_port)
+
     def create(self):
         k8s_utils.create_service(self.template)
 
     def delete(self):
-        k8s_utils.delete_service(self.name)
+        k8s_utils.delete_service(self._name)
+
+
+class CustomResourceDefinitionObject(object):
+
+    MANDATORY_PARAMETERS = {'name'}
+
+    def __init__(self, ctx_name, **kwargs):
+        if not self.MANDATORY_PARAMETERS.issubset(kwargs):
+            missing_parameters = ', '.join(
+                str(param) for param in
+                (self.MANDATORY_PARAMETERS - set(kwargs)))
+            raise exceptions.KubernetesCRDObjectDefinitionError(
+                missing_parameters=missing_parameters)
+
+        singular = kwargs['name']
+        plural = singular + 's'
+        kind = singular.title()
+        version = kwargs.get('version', 'v1')
+        scope = kwargs.get('scope', constants.SCOPE_NAMESPACED)
+        group = ctx_name + '.com'
+        self._name = metadata_name = plural + '.' + group
+
+        self._template = {
+            'metadata': {
+                'name': metadata_name
+            },
+            'spec': {
+                'group': group,
+                'version': version,
+                'scope': scope,
+                'names': {'plural': plural,
+                          'singular': singular,
+                          'kind': kind}
+            }
+        }
+
+    def create(self):
+        k8s_utils.create_custom_resource_definition(self._template)
+
+    def delete(self):
+        k8s_utils.delete_custom_resource_definition(self._name)
+
+
+class NetworkObject(object):
+
+    MANDATORY_PARAMETERS = {'plugin', 'args'}
+    KIND = 'Network'
+
+    def __init__(self, name, **kwargs):
+        if not self.MANDATORY_PARAMETERS.issubset(kwargs):
+            missing_parameters = ', '.join(
+                str(param) for param in
+                (self.MANDATORY_PARAMETERS - set(kwargs)))
+            raise exceptions.KubernetesNetworkObjectDefinitionError(
+                missing_parameters=missing_parameters)
+
+        self._name = name
+        self._plugin = kwargs['plugin']
+        self._args = kwargs['args']
+        self._crd = None
+        self._template = None
+        self._group = None
+        self._version = None
+        self._plural = None
+        self._scope = None
+
+    @property
+    def crd(self):
+        if self._crd:
+            return self._crd
+        crd = k8s_utils.get_custom_resource_definition(self.KIND)
+        if not crd:
+            raise exceptions.KubernetesNetworkObjectKindMissing()
+        self._crd = crd
+        return self._crd
+
+    @property
+    def group(self):
+        if self._group:
+            return self._group
+        self._group = self.crd.spec.group
+        return self._group
+
+    @property
+    def version(self):
+        if self._version:
+            return self._version
+        self._version = self.crd.spec.version
+        return self._version
+
+    @property
+    def plural(self):
+        if self._plural:
+            return self._plural
+        self._plural = self.crd.spec.names.plural
+        return self._plural
+
+    @property
+    def scope(self):
+        if self._scope:
+            return self._scope
+        self._scope = self.crd.spec.scope
+        return self._scope
+
+    @property
+    def template(self):
+        """"Network" object template
+
+        This template can be rendered only once the CRD "Network" is created in
+        Kubernetes. This function call must be delayed until the creation of
+        the CRD "Network".
+        """
+        if self._template:
+            return self._template
+
+        self._template = {
+            'apiVersion': '{}/{}'.format(self.group, self.version),
+            'kind': self.KIND,
+            'metadata': {
+                'name': self._name
+            },
+            'plugin': self._plugin,
+            'args': self._args
+        }
+        return self._template
+
+    def create(self):
+        k8s_utils.create_network(self.scope, self.group, self.version,
+                                 self.plural, self.template)
+
+    def delete(self):
+        k8s_utils.delete_network(self.scope, self.group, self.version,
+                                 self.plural, self._name)
 
 
 class KubernetesTemplate(object):
@@ -193,16 +454,21 @@ class KubernetesTemplate(object):
         """
         context_cfg = copy.deepcopy(context_cfg)
         servers_cfg = context_cfg.pop('servers', {})
+        crd_cfg = context_cfg.pop('custom_resources', [])
+        networks_cfg = context_cfg.pop('networks', {})
         self.name = name
         self.ssh_key = '{}-key'.format(name)
 
-        self.rcs = [self._get_rc_name(rc) for rc in servers_cfg]
-        self.k8s_objs = [KubernetesObject(self._get_rc_name(rc),
-                                          ssh_key=self.ssh_key,
-                                          **cfg)
-                         for rc, cfg in servers_cfg.items()]
-        self.service_objs = [ServiceObject(s) for s in self.rcs]
-
+        self.rcs = {self._get_rc_name(rc): cfg
+                    for rc, cfg in servers_cfg.items()}
+        self.rc_objs = [ReplicationControllerObject(
+            rc, ssh_key=self.ssh_key, **cfg) for rc, cfg in self.rcs.items()]
+        self.service_objs = [ServiceNodePortObject(rc, **cfg)
+                             for rc, cfg in self.rcs.items()]
+        self.crd = [CustomResourceDefinitionObject(self.name, **crd)
+                    for crd in crd_cfg]
+        self.network_objs = [NetworkObject(net_name, **net_data)
+                             for net_name, net_data in networks_cfg.items()]
         self.pods = []
 
     def _get_rc_name(self, rc_name):
@@ -214,3 +480,8 @@ class KubernetesTemplate(object):
                      if p.metadata.name.startswith(s)]
 
         return self.pods
+
+    def get_rc_by_name(self, rc_name):
+        """Returns a ``ReplicationControllerObject``, searching by name"""
+        for rc in (rc for rc in self.rc_objs if rc.name == rc_name):
+            return rc
index 9987434..f3e31e7 100644 (file)
@@ -32,25 +32,25 @@ class DummyPayload(payloads.Payload):
 class DummyEndpoint(consumer.NotificationHandler):
 
     def info(self, ctxt, **kwargs):
-        if ctxt['pid'] in self._ctx_pids:
-            self._queue.put('ID {}, data: {}, pid: {}'.format(
-                self._id, kwargs['data'], ctxt['pid']))
+        if ctxt['id'] in self._ctx_ids:
+            self._queue.put('Nr {}, data: {}, id: {}'.format(
+                self._id, kwargs['data'], ctxt['id']))
 
 
 class DummyConsumer(consumer.MessagingConsumer):
 
-    def __init__(self, _id, ctx_pids, queue):
+    def __init__(self, _id, ctx_ids, queue):
         self._id = _id
-        endpoints = [DummyEndpoint(_id, ctx_pids, queue)]
-        super(DummyConsumer, self).__init__(TOPIC, ctx_pids, endpoints)
+        endpoints = [DummyEndpoint(_id, ctx_ids, queue)]
+        super(DummyConsumer, self).__init__(TOPIC, ctx_ids, endpoints)
 
 
 class DummyProducer(producer.MessagingProducer):
     pass
 
 
-def _run_consumer(_id, ctx_pids, queue):
-    _consumer = DummyConsumer(_id, ctx_pids, queue)
+def _run_consumer(_id, ctx_ids, queue):
+    _consumer = DummyConsumer(_id, ctx_ids, queue)
     _consumer.start_rpc_server()
     _consumer.wait()
 
@@ -67,8 +67,8 @@ class MessagingTestCase(base.BaseFunctionalTestCase):
         num_consumers = 10
         ctx_1 = 100001
         ctx_2 = 100002
-        producers = [DummyProducer(TOPIC, pid=ctx_1),
-                     DummyProducer(TOPIC, pid=ctx_2)]
+        producers = [DummyProducer(TOPIC, _id=ctx_1),
+                     DummyProducer(TOPIC, _id=ctx_2)]
 
         processes = []
         for i in range(num_consumers):
@@ -91,7 +91,7 @@ class MessagingTestCase(base.BaseFunctionalTestCase):
             output.append(output_queue.get(True, 1))
 
         self.assertEqual(num_consumers * 4, len(output))
-        msg_template = 'ID {}, data: {}, pid: {}'
+        msg_template = 'Nr {}, data: {}, id: {}'
         for i in range(num_consumers):
             for ctx in [ctx_1, ctx_2]:
                 for message in ['message 0', 'message 1']:
index b5333bb..b9f1f77 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import multiprocessing
 import unittest
+import socket
 import sys
+import time
 
 from yardstick.common import utils
 
@@ -32,3 +35,38 @@ class ImportModulesFromPackageTestCase(unittest.TestCase):
         library_obj = getattr(module_obj, library_name)
         class_obj = getattr(library_obj, class_name)
         self.assertEqual(class_name, class_obj().__class__.__name__)
+
+
+class SendSocketCommandTestCase(unittest.TestCase):
+
+    @staticmethod
+    def _run_socket_server(port):
+        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        sock.bind(('localhost', port))
+        sock.listen(1)
+        conn = None
+        while not conn:
+            conn, _ = sock.accept()
+        sock.close()
+
+    @staticmethod
+    def _terminate_server(socket_server):
+        # Wait until the socket server closes the open port.
+        time.sleep(1)
+        if socket_server and socket_server.is_alive():
+            socket_server.terminate()
+
+    def test_send_command(self):
+        port = 47001
+
+        socket_server = multiprocessing.Process(
+            name='run_socket_server',
+            target=SendSocketCommandTestCase._run_socket_server,
+            args=(port, )).start()
+
+        self.addCleanup(self._terminate_server, socket_server)
+
+        # Wait until the socket is open.
+        time.sleep(0.5)
+        self.assertEqual(
+            0, utils.send_socket_command('localhost', port, 'test_command'))
diff --git a/yardstick/tests/functional/network_services/__init__.py b/yardstick/tests/functional/network_services/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/yardstick/tests/functional/network_services/vnf_generic/__init__.py b/yardstick/tests/functional/network_services/vnf_generic/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/yardstick/tests/functional/network_services/vnf_generic/vnf/__init__.py b/yardstick/tests/functional/network_services/vnf_generic/vnf/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/yardstick/tests/functional/network_services/vnf_generic/vnf/test_base.py b/yardstick/tests/functional/network_services/vnf_generic/vnf/test_base.py
new file mode 100644 (file)
index 0000000..e57f8f5
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (c) 2018 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.
+
+import multiprocessing
+import time
+import uuid
+
+import mock
+
+from yardstick.common import messaging
+from yardstick.common.messaging import payloads
+from yardstick.common.messaging import producer
+from yardstick.network_services.vnf_generic.vnf import base as vnf_base
+from yardstick.tests.functional import base as ft_base
+
+
+class _TrafficGenMQConsumer(vnf_base.GenericTrafficGen,
+                            vnf_base.GenericVNFEndpoint):
+
+    def __init__(self, name, vnfd, task_id):
+        vnf_base.GenericTrafficGen.__init__(self, name, vnfd, task_id)
+        self.queue = multiprocessing.Queue()
+        self._id = uuid.uuid1().int
+        vnf_base.GenericVNFEndpoint.__init__(self, self._id, [task_id],
+                                             self.queue)
+        self._consumer = vnf_base.GenericVNFConsumer([task_id], self)
+        self._consumer.start_rpc_server()
+
+    def run_traffic(self, *args):
+        pass
+
+    def terminate(self):
+        pass
+
+    def collect_kpi(self):
+        pass
+
+    def instantiate(self, *args):
+        pass
+
+    def scale(self, flavor=''):
+        pass
+
+    def runner_method_start_iteration(self, ctxt, **kwargs):
+        if ctxt['id'] in self._ctx_ids:
+            self._queue.put(
+                {'action': messaging.RUNNER_METHOD_START_ITERATION,
+                 'payload': payloads.RunnerPayload.dict_to_obj(kwargs)})
+
+    def runner_method_stop_iteration(self, ctxt, **kwargs):
+        if ctxt['id'] in self._ctx_ids:
+            self._queue.put(
+                {'action': messaging.RUNNER_METHOD_STOP_ITERATION,
+                 'payload': payloads.RunnerPayload.dict_to_obj(kwargs)})
+
+
+class _DummyProducer(producer.MessagingProducer):
+    pass
+
+
+class GenericVNFMQConsumerTestCase(ft_base.BaseFunctionalTestCase):
+
+    def test_fistro(self):
+        vnfd = {'benchmark': {'kpi': mock.ANY},
+                'vdu': [{'external-interface': 'ext_int'}]
+                }
+        task_id = uuid.uuid1().int
+        tg_obj = _TrafficGenMQConsumer('name_tg', vnfd, task_id)
+        producer = _DummyProducer(messaging.TOPIC_RUNNER, task_id)
+
+        num_messages = 10
+        for i in range(num_messages):
+            pload = payloads.RunnerPayload(version=10, data=i)
+            for method in (messaging.RUNNER_METHOD_START_ITERATION,
+                           messaging.RUNNER_METHOD_STOP_ITERATION):
+                producer.send_message(method, pload)
+
+        time.sleep(0.5)  # Let consumers attend the calls
+        output = []
+        while not tg_obj.queue.empty():
+            data = tg_obj.queue.get(True, 1)
+            data_dict = {'action': data['action'],
+                         'payload': data['payload'].obj_to_dict()}
+            output.append(data_dict)
+
+        self.assertEqual(num_messages * 2, len(output))
+        for i in range(num_messages):
+            pload = payloads.RunnerPayload(version=10, data=i).obj_to_dict()
+            for method in (messaging.RUNNER_METHOD_START_ITERATION,
+                           messaging.RUNNER_METHOD_STOP_ITERATION):
+                reg = {'action': method, 'payload': pload}
+                self.assertIn(reg, output)
index a4a8359..69779d3 100644 (file)
@@ -19,6 +19,7 @@ import mock
 import six
 import unittest
 
+from yardstick.benchmark import contexts
 from yardstick.benchmark.contexts import base
 from yardstick.benchmark.contexts.standalone import model
 from yardstick.benchmark.contexts.standalone import ovs_dpdk
@@ -82,7 +83,7 @@ class OvsDpdkContextTestCase(unittest.TestCase):
 
     def test_init(self):
         ATTRS = {
-            'name': 'StandaloneOvsDpdk',
+            'name': contexts.CONTEXT_STANDALONEOVSDPDK,
             'task_id': '1234567890',
             'file': 'pod',
             'flavor': {},
index 1690846..74c3156 100644 (file)
@@ -18,6 +18,7 @@ import mock
 import unittest
 
 from yardstick import ssh
+from yardstick.benchmark import contexts
 from yardstick.benchmark.contexts import base
 from yardstick.benchmark.contexts.standalone import model
 from yardstick.benchmark.contexts.standalone import sriov
@@ -30,7 +31,7 @@ class SriovContextTestCase(unittest.TestCase):
     NODES_DUPLICATE_SAMPLE = "nodes_duplicate_sample.yaml"
 
     ATTRS = {
-        'name': 'StandaloneSriov',
+        'name': contexts.CONTEXT_STANDALONESRIOV,
         'task_id': '1234567890',
         'file': 'pod',
         'flavor': {},
index 821b84a..b526e7c 100644 (file)
@@ -7,16 +7,23 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
+import collections
+import time
+
 import mock
 import unittest
 
+from yardstick.benchmark import contexts
 from yardstick.benchmark.contexts import base
 from yardstick.benchmark.contexts import kubernetes
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.common import kubernetes_utils as k8s_utils
 from yardstick.orchestrator import kubernetes as orchestrator_kubernetes
 
 
 CONTEXT_CFG = {
-    'type': 'Kubernetes',
+    'type': contexts.CONTEXT_KUBERNETES,
     'name': 'k8s',
     'task_id': '1234567890',
     'servers': {
@@ -32,10 +39,42 @@ CONTEXT_CFG = {
             'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; '
                      'service ssh restart;while true ; do sleep 10000; done']
         }
+    },
+    'networks': {
+        'flannel': {
+            'args': 'flannel_args',
+            'plugin': 'flannel'
+        },
+        'sriov01': {
+            'args': 'sriov_args',
+            'plugin': 'sriov'
+        },
     }
 }
 
-prefix = 'yardstick.benchmark.contexts.kubernetes'
+
+class NodePort(object):
+    def __init__(self):
+        self.node_port = 30000
+        self.port = constants.SSH_PORT
+        self.name = 'port_name'
+        self.protocol = 'TCP'
+        self.target_port = constants.SSH_PORT
+
+
+class Service(object):
+    def __init__(self):
+        self.ports = [NodePort()]
+
+
+class Status(object):
+    def __init__(self):
+        self.pod_ip = '172.16.10.131'
+
+
+class Pod(object):
+    def __init__(self):
+        self.status = Status()
 
 
 class KubernetesTestCase(unittest.TestCase):
@@ -55,17 +94,19 @@ class KubernetesTestCase(unittest.TestCase):
     @mock.patch.object(kubernetes.KubernetesContext, '_delete_ssh_key')
     @mock.patch.object(kubernetes.KubernetesContext, '_delete_rcs')
     @mock.patch.object(kubernetes.KubernetesContext, '_delete_pods')
-    def test_undeploy(self,
-                      mock_delete_pods,
-                      mock_delete_rcs,
-                      mock_delete_ssh,
-                      mock_delete_services):
+    @mock.patch.object(kubernetes.KubernetesContext, '_delete_networks')
+    @mock.patch.object(kubernetes.KubernetesContext, '_delete_crd')
+    def test_undeploy(self, mock_delete_pods, mock_delete_rcs,
+                      mock_delete_ssh, mock_delete_services,
+                      mock_delete_networks, mock_delete_crd):
 
         self.k8s_context.undeploy()
         mock_delete_ssh.assert_called_once()
         mock_delete_rcs.assert_called_once()
         mock_delete_pods.assert_called_once()
         mock_delete_services.assert_called_once()
+        mock_delete_networks.assert_called_once()
+        mock_delete_crd.assert_called_once()
 
     @mock.patch.object(kubernetes.KubernetesContext, '_create_services')
     @mock.patch.object(kubernetes.KubernetesContext, '_wait_until_running')
@@ -73,27 +114,28 @@ class KubernetesTestCase(unittest.TestCase):
                        'get_rc_pods')
     @mock.patch.object(kubernetes.KubernetesContext, '_create_rcs')
     @mock.patch.object(kubernetes.KubernetesContext, '_set_ssh_key')
-    def test_deploy(self,
-                    mock_set_ssh_key,
-                    mock_create_rcs,
-                    mock_get_rc_pods,
-                    mock_wait_until_running,
-                    mock_create_services):
-
-        with mock.patch("yardstick.benchmark.contexts.kubernetes.time"):
+    @mock.patch.object(kubernetes.KubernetesContext, '_create_networks')
+    @mock.patch.object(kubernetes.KubernetesContext, '_create_crd')
+    def test_deploy(self, mock_set_ssh_key, mock_create_rcs, mock_get_rc_pods,
+                    mock_wait_until_running, mock_create_services,
+                    mock_create_networks, mock_create_crd):
+
+        with mock.patch.object(time, 'sleep'):
             self.k8s_context.deploy()
         mock_set_ssh_key.assert_called_once()
         mock_create_rcs.assert_called_once()
         mock_create_services.assert_called_once()
         mock_get_rc_pods.assert_called_once()
         mock_wait_until_running.assert_called_once()
+        mock_create_networks.assert_called_once()
+        mock_create_crd.assert_called_once()
 
     @mock.patch.object(kubernetes, 'paramiko', **{"resource_filename.return_value": ""})
     @mock.patch.object(kubernetes, 'pkg_resources', **{"resource_filename.return_value": ""})
     @mock.patch.object(kubernetes, 'utils')
     @mock.patch.object(kubernetes, 'open', create=True)
-    @mock.patch.object(kubernetes.k8s_utils, 'delete_config_map')
-    @mock.patch.object(kubernetes.k8s_utils, 'create_config_map')
+    @mock.patch.object(k8s_utils, 'delete_config_map')
+    @mock.patch.object(k8s_utils, 'create_config_map')
     def test_ssh_key(self, mock_create, mock_delete, *args):
         self.k8s_context._set_ssh_key()
         self.k8s_context._delete_ssh_key()
@@ -101,49 +143,32 @@ class KubernetesTestCase(unittest.TestCase):
         mock_create.assert_called_once()
         mock_delete.assert_called_once()
 
-    @mock.patch.object(kubernetes.k8s_utils, 'read_pod_status')
+    @mock.patch.object(k8s_utils, 'read_pod_status')
     def test_wait_until_running(self, mock_read_pod_status):
 
         self.k8s_context.template.pods = ['server']
         mock_read_pod_status.return_value = 'Running'
         self.k8s_context._wait_until_running()
 
-    @mock.patch.object(kubernetes.k8s_utils, 'get_pod_by_name')
+    @mock.patch.object(k8s_utils, 'get_pod_by_name')
     @mock.patch.object(kubernetes.KubernetesContext, '_get_node_ip')
-    @mock.patch.object(kubernetes.k8s_utils, 'get_service_by_name')
-    def test_get_server(self,
-                        mock_get_service_by_name,
-                        mock_get_node_ip,
-                        mock_get_pod_by_name):
-        class Service(object):
-            def __init__(self):
-                self.name = 'yardstick'
-                self.node_port = 30000
-
-        class Services(object):
-            def __init__(self):
-                self.ports = [Service()]
-
-        class Status(object):
-            def __init__(self):
-                self.pod_ip = '172.16.10.131'
-
-        class Pod(object):
-            def __init__(self):
-                self.status = Status()
-
-        mock_get_service_by_name.return_value = Services()
+    def test_get_server(self, mock_get_node_ip, mock_get_pod_by_name):
         mock_get_pod_by_name.return_value = Pod()
         mock_get_node_ip.return_value = '172.16.10.131'
-
-        self.assertIsNotNone(self.k8s_context._get_server('server'))
+        with mock.patch.object(self.k8s_context, '_get_service_ports') as \
+                mock_get_sports:
+            mock_get_sports.return_value = [
+                {'port': constants.SSH_PORT, 'node_port': 30000}]
+            server = self.k8s_context._get_server('server_name')
+        self.assertEqual('server_name', server['name'])
+        self.assertEqual(30000, server['ssh_port'])
 
     @mock.patch.object(kubernetes.KubernetesContext, '_create_rc')
     def test_create_rcs(self, mock_create_rc):
         self.k8s_context._create_rcs()
         mock_create_rc.assert_called()
 
-    @mock.patch.object(kubernetes.k8s_utils, 'create_replication_controller')
+    @mock.patch.object(k8s_utils, 'create_replication_controller')
     def test_create_rc(self, mock_create_replication_controller):
         self.k8s_context._create_rc({})
         mock_create_replication_controller.assert_called_once()
@@ -153,22 +178,22 @@ class KubernetesTestCase(unittest.TestCase):
         self.k8s_context._delete_rcs()
         mock_delete_rc.assert_called()
 
-    @mock.patch.object(kubernetes.k8s_utils, 'delete_replication_controller')
+    @mock.patch.object(k8s_utils, 'delete_replication_controller')
     def test_delete_rc(self, mock_delete_replication_controller):
         self.k8s_context._delete_rc({})
         mock_delete_replication_controller.assert_called_once()
 
-    @mock.patch.object(kubernetes.k8s_utils, 'get_node_list')
+    @mock.patch.object(k8s_utils, 'get_node_list')
     def test_get_node_ip(self, mock_get_node_list):
         self.k8s_context._get_node_ip()
         mock_get_node_list.assert_called_once()
 
-    @mock.patch('yardstick.orchestrator.kubernetes.ServiceObject.create')
+    @mock.patch.object(orchestrator_kubernetes.ServiceNodePortObject, 'create')
     def test_create_services(self, mock_create):
         self.k8s_context._create_services()
         mock_create.assert_called()
 
-    @mock.patch('yardstick.orchestrator.kubernetes.ServiceObject.delete')
+    @mock.patch.object(orchestrator_kubernetes.ServiceNodePortObject, 'delete')
     def test_delete_services(self, mock_delete):
         self.k8s_context._delete_services()
         mock_delete.assert_called()
@@ -182,6 +207,9 @@ class KubernetesTestCase(unittest.TestCase):
         mock_k8stemplate.assert_called_once_with(self.k8s_context.name,
                                                  CONTEXT_CFG)
         self.assertEqual('fake_template', self.k8s_context.template)
+        self.assertEqual(2, len(self.k8s_context._networks))
+        self.assertIn('flannel', self.k8s_context._networks.keys())
+        self.assertIn('sriov01', self.k8s_context._networks.keys())
 
     def test__get_physical_nodes(self):
         result = self.k8s_context._get_physical_nodes()
@@ -190,3 +218,56 @@ class KubernetesTestCase(unittest.TestCase):
     def test__get_physical_node_for_server(self):
         result = self.k8s_context._get_physical_node_for_server("fake")
         self.assertIsNone(result)
+
+    def test__get_network(self):
+        networks = collections.OrderedDict([('n1', 'data1'), ('n2', 'data2')])
+        self.k8s_context._networks = networks
+        self.assertEqual({'name': 'n1'}, self.k8s_context._get_network('n1'))
+        self.assertEqual({'name': 'n2'}, self.k8s_context._get_network('n2'))
+        self.assertIsNone(self.k8s_context._get_network('n3'))
+
+    @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate,
+                       'get_rc_by_name')
+    def test__get_interfaces(self, mock_get_rc):
+        rc = orchestrator_kubernetes.ReplicationControllerObject('rc_name')
+        rc._networks = ['net1', 'net2']
+        mock_get_rc.return_value = rc
+        expected = {'net1': {'network_name': 'net1',
+                             'local_mac': None,
+                             'local_ip': None},
+                    'net2': {'network_name': 'net2',
+                             'local_mac': None,
+                             'local_ip': None}}
+        self.assertEqual(expected, self.k8s_context._get_interfaces('rc_name'))
+
+    @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate,
+                       'get_rc_by_name')
+    def test__get_interfaces_no_networks(self, mock_get_rc):
+        rc = orchestrator_kubernetes.ReplicationControllerObject('rc_name')
+        mock_get_rc.return_value = rc
+        self.assertEqual({}, self.k8s_context._get_interfaces('rc_name'))
+
+    @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate,
+                       'get_rc_by_name', return_value=None)
+    def test__get_interfaces_no_rc(self, *args):
+        self.assertEqual({}, self.k8s_context._get_interfaces('rc_name'))
+
+    @mock.patch.object(k8s_utils, 'get_service_by_name',
+                       return_value=Service())
+    def test__get_service_ports(self, mock_get_service_by_name):
+        name = 'rc_name'
+        service_ports = self.k8s_context._get_service_ports(name)
+        mock_get_service_by_name.assert_called_once_with(name + '-service')
+        expected = {'node_port': 30000,
+                    'port': constants.SSH_PORT,
+                    'name': 'port_name',
+                    'protocol': 'TCP',
+                    'target_port': constants.SSH_PORT}
+        self.assertEqual(expected, service_ports[0])
+
+    @mock.patch.object(k8s_utils, 'get_service_by_name',
+                       return_value=None)
+    def test__get_service_ports_exception(self, *args):
+        name = 'rc_name'
+        with self.assertRaises(exceptions.KubernetesServiceObjectNotDefined):
+            self.k8s_context._get_service_ports(name)
index 0424c77..3523663 100644 (file)
@@ -28,7 +28,7 @@ from yardstick.common import utils
 
 class TaskTestCase(unittest.TestCase):
 
-    @mock.patch.object(task, 'Context')
+    @mock.patch.object(base, 'Context')
     def test_parse_nodes_with_context_same_context(self, mock_context):
         scenario_cfg = {
             "nodes": {
@@ -69,7 +69,7 @@ class TaskTestCase(unittest.TestCase):
                                                            dispatcher2])
         self.assertIsNone(t._do_output(output_config, {}))
 
-    @mock.patch.object(task, 'Context')
+    @mock.patch.object(base, 'Context')
     def test_parse_networks_from_nodes(self, mock_context):
         nodes = {
             'node1': {
@@ -133,7 +133,7 @@ class TaskTestCase(unittest.TestCase):
         self.assertEqual(mock_context.get_network.call_count, expected_get_network_calls)
         self.assertDictEqual(networks, expected)
 
-    @mock.patch.object(task, 'Context')
+    @mock.patch.object(base, 'Context')
     @mock.patch.object(task, 'base_runner')
     def test_run(self, mock_base_runner, *args):
         scenario = {
@@ -156,7 +156,7 @@ class TaskTestCase(unittest.TestCase):
         t._run([scenario], False, "yardstick.out")
         runner.run.assert_called_once()
 
-    @mock.patch.object(task, 'Context')
+    @mock.patch.object(base, 'Context')
     @mock.patch.object(task, 'base_runner')
     def test_run_ProxDuration(self, mock_base_runner, *args):
         scenario = {
index 559c991..49ba1ef 100644 (file)
@@ -8,12 +8,17 @@
 ##############################################################################
 
 import time
+import uuid
 
 import mock
+from oslo_config import cfg
+import oslo_messaging
 import subprocess
 
 from yardstick.benchmark.runners import base as runner_base
 from yardstick.benchmark.runners import iteration
+from yardstick.common import messaging
+from yardstick.common.messaging import payloads
 from yardstick.tests.unit import base as ut_base
 
 
@@ -94,3 +99,54 @@ class RunnerTestCase(ut_base.BaseUnitTestCase):
 
         with self.assertRaises(NotImplementedError):
             runner._run_benchmark(mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock())
+
+
+class RunnerProducerTestCase(ut_base.BaseUnitTestCase):
+
+    @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+    @mock.patch.object(oslo_messaging, 'RPCClient')
+    @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+                       return_value='rpc_transport')
+    @mock.patch.object(cfg, 'CONF')
+    def test__init(self, mock_config, mock_transport, mock_rpcclient,
+                   mock_target):
+        _id = uuid.uuid1().int
+        runner_producer = runner_base.RunnerProducer(_id)
+        mock_transport.assert_called_once_with(
+            mock_config, url='rabbit://yardstick:yardstick@localhost:5672/')
+        mock_target.assert_called_once_with(topic=messaging.TOPIC_RUNNER,
+                                            fanout=True,
+                                            server=messaging.SERVER)
+        mock_rpcclient.assert_called_once_with('rpc_transport', 'rpc_target')
+        self.assertEqual(_id, runner_producer._id)
+        self.assertEqual(messaging.TOPIC_RUNNER, runner_producer._topic)
+
+    @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+    @mock.patch.object(oslo_messaging, 'RPCClient')
+    @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+                       return_value='rpc_transport')
+    @mock.patch.object(payloads, 'RunnerPayload', return_value='runner_pload')
+    def test_start_iteration(self, mock_runner_payload, *args):
+        runner_producer = runner_base.RunnerProducer(uuid.uuid1().int)
+        with mock.patch.object(runner_producer,
+                               'send_message') as mock_message:
+            runner_producer.start_iteration(version=10)
+
+        mock_message.assert_called_once_with(
+            messaging.RUNNER_METHOD_START_ITERATION, 'runner_pload')
+        mock_runner_payload.assert_called_once_with(version=10, data={})
+
+    @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+    @mock.patch.object(oslo_messaging, 'RPCClient')
+    @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+                       return_value='rpc_transport')
+    @mock.patch.object(payloads, 'RunnerPayload', return_value='runner_pload')
+    def test_stop_iteration(self, mock_runner_payload, *args):
+        runner_producer = runner_base.RunnerProducer(uuid.uuid1().int)
+        with mock.patch.object(runner_producer,
+                               'send_message') as mock_message:
+            runner_producer.stop_iteration(version=15)
+
+        mock_message.assert_called_once_with(
+            messaging.RUNNER_METHOD_STOP_ITERATION, 'runner_pload')
+        mock_runner_payload.assert_called_once_with(version=15, data={})
diff --git a/yardstick/tests/unit/benchmark/runner/test_iteration_ipc.py b/yardstick/tests/unit/benchmark/runner/test_iteration_ipc.py
new file mode 100644 (file)
index 0000000..10d14a8
--- /dev/null
@@ -0,0 +1,136 @@
+# Copyright (c) 2018 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.
+
+import multiprocessing
+import time
+import os
+import uuid
+
+import mock
+
+from yardstick.benchmark.runners import iteration_ipc
+from yardstick.common import messaging
+from yardstick.common.messaging import payloads
+from yardstick.tests.unit import base as ut_base
+
+
+class RunnerIterationIPCEndpointTestCase(ut_base.BaseUnitTestCase):
+
+    def setUp(self):
+        self._id = uuid.uuid1().int
+        self._ctx_ids = [uuid.uuid1().int, uuid.uuid1().int]
+        self._queue = multiprocessing.Queue()
+        self.runner = iteration_ipc.RunnerIterationIPCEndpoint(
+            self._id, self._ctx_ids, self._queue)
+        self._kwargs = {'version': 1, 'iteration': 10, 'kpi': {}}
+        self._pload_dict = payloads.TrafficGeneratorPayload.dict_to_obj(
+            self._kwargs).obj_to_dict()
+
+    def test_tg_method_started(self):
+        self._queue.empty()
+        ctxt = {'id': self._ctx_ids[0]}
+        self.runner.tg_method_started(ctxt, **self._kwargs)
+        time.sleep(0.2)
+
+        output = []
+        while not self._queue.empty():
+            output.append(self._queue.get(True, 1))
+
+        self.assertEqual(1, len(output))
+        self.assertEqual(self._ctx_ids[0], output[0]['id'])
+        self.assertEqual(messaging.TG_METHOD_STARTED, output[0]['action'])
+        self.assertEqual(self._pload_dict, output[0]['payload'].obj_to_dict())
+
+    def test_tg_method_finished(self):
+        self._queue.empty()
+        ctxt = {'id': self._ctx_ids[0]}
+        self.runner.tg_method_finished(ctxt, **self._kwargs)
+        time.sleep(0.2)
+
+        output = []
+        while not self._queue.empty():
+            output.append(self._queue.get(True, 1))
+
+        self.assertEqual(1, len(output))
+        self.assertEqual(self._ctx_ids[0], output[0]['id'])
+        self.assertEqual(messaging.TG_METHOD_FINISHED, output[0]['action'])
+        self.assertEqual(self._pload_dict, output[0]['payload'].obj_to_dict())
+
+    def test_tg_method_iteration(self):
+        self._queue.empty()
+        ctxt = {'id': self._ctx_ids[0]}
+        self.runner.tg_method_iteration(ctxt, **self._kwargs)
+        time.sleep(0.2)
+
+        output = []
+        while not self._queue.empty():
+            output.append(self._queue.get(True, 1))
+
+        self.assertEqual(1, len(output))
+        self.assertEqual(self._ctx_ids[0], output[0]['id'])
+        self.assertEqual(messaging.TG_METHOD_ITERATION, output[0]['action'])
+        self.assertEqual(self._pload_dict, output[0]['payload'].obj_to_dict())
+
+
+class RunnerIterationIPCConsumerTestCase(ut_base.BaseUnitTestCase):
+
+    def setUp(self):
+        self._id = uuid.uuid1().int
+        self._ctx_ids = [uuid.uuid1().int, uuid.uuid1().int]
+        self.consumer = iteration_ipc.RunnerIterationIPCConsumer(
+            self._id, self._ctx_ids)
+        self.consumer._queue = mock.Mock()
+
+    def test__init(self):
+        self.assertEqual({self._ctx_ids[0]: [], self._ctx_ids[1]: []},
+                         self.consumer._kpi_per_id)
+
+    def test_is_all_kpis_received_in_iteration(self):
+        payload = payloads.TrafficGeneratorPayload(
+            version=1, iteration=1, kpi={})
+        msg1 = {'action': messaging.TG_METHOD_ITERATION,
+                'id': self._ctx_ids[0], 'payload': payload}
+        msg2 = {'action': messaging.TG_METHOD_ITERATION,
+                'id': self._ctx_ids[1], 'payload': payload}
+        self.consumer.iteration_index = 1
+
+        self.consumer._queue.empty.side_effect = [False, True]
+        self.consumer._queue.get.return_value = msg1
+        self.assertFalse(self.consumer.is_all_kpis_received_in_iteration())
+
+        self.consumer._queue.empty.side_effect = [False, True]
+        self.consumer._queue.get.return_value = msg2
+        self.assertTrue(self.consumer.is_all_kpis_received_in_iteration())
+
+
+class IterationIPCRunnerTestCase(ut_base.BaseUnitTestCase):
+
+    @mock.patch.object(iteration_ipc, '_worker_process')
+    @mock.patch.object(os, 'getpid', return_value=12345678)
+    @mock.patch.object(multiprocessing, 'Process', return_value=mock.Mock())
+    def test__run_benchmark(self, mock_process, mock_getpid, mock_worker):
+        method = 'method'
+        scenario_cfg = {'type': 'scenario_type'}
+        context_cfg = 'context_cfg'
+        name = '%s-%s-%s' % ('IterationIPC', 'scenario_type', 12345678)
+        runner = iteration_ipc.IterationIPCRunner(mock.ANY)
+        mock_getpid.reset_mock()
+
+        runner._run_benchmark('class', method, scenario_cfg, context_cfg)
+        mock_process.assert_called_once_with(
+            name=name,
+            target=mock_worker,
+            args=(runner.result_queue, 'class', method, scenario_cfg,
+                  context_cfg, runner.aborted, runner.output_queue))
+        mock_getpid.assert_called_once()
index bb1a7aa..cdb91f6 100644 (file)
@@ -436,6 +436,7 @@ class TestNetworkServiceTestCase(unittest.TestCase):
             self._get_file_abspath("tg_trex_tpl.yaml")
         self.context_cfg["nodes"]['vnf__1']['VNF model'] = \
             self._get_file_abspath("tg_trex_tpl.yaml")
+        self.context_cfg['task_id'] = 'fake_task_id'
 
         vnf = mock.Mock(autospec=GenericVNF)
         self.s.get_vnf_impl = mock.Mock(return_value=vnf)
@@ -553,6 +554,7 @@ class TestNetworkServiceTestCase(unittest.TestCase):
             tgen.verify_traffic = lambda x: verified_dict
             tgen.terminate = mock.Mock(return_value=True)
             tgen.name = "tgen__1"
+            tgen.run_traffic.return_value = 'tg_id'
             vnf = mock.Mock(autospec=GenericVNF)
             vnf.runs_traffic = False
             vnf.terminate = mock.Mock(return_value=True)
@@ -565,7 +567,6 @@ class TestNetworkServiceTestCase(unittest.TestCase):
             self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
             self.s._fill_traffic_profile = \
                 mock.Mock(return_value=TRAFFIC_PROFILE)
-            self.assertIsNone(self.s.setup())
 
     def test_setup_exception(self):
         with mock.patch("yardstick.ssh.SSH") as ssh:
@@ -656,6 +657,9 @@ class TestNetworkServiceTestCase(unittest.TestCase):
         )
         self.assertEqual(self.s.topology, 'fake_nsd')
 
+    def test_get_mq_ids(self):
+        self.assertEqual(self.s._mq_ids, self.s.get_mq_ids())
+
     def test_teardown(self):
         vnf = mock.Mock(autospec=GenericVNF)
         vnf.terminate = mock.Mock(return_value=True)
index 00ec220..37b1f19 100644 (file)
@@ -44,3 +44,39 @@ class PayloadTestCase(ut_base.BaseUnitTestCase):
         _dict = {'version': 2, 'key1': 'value100', 'key2': 'value200'}
         payload = _DummyPayload.dict_to_obj(_dict)
         self.assertEqual(set(_dict.keys()), payload._fields)
+
+
+class TrafficGeneratorPayloadTestCase(ut_base.BaseUnitTestCase):
+
+    def test_init(self):
+        tg_payload = payloads.TrafficGeneratorPayload(
+            version=1, iteration=10, kpi={'key1': 'value1'})
+        self.assertEqual(1, tg_payload.version)
+        self.assertEqual(10, tg_payload.iteration)
+        self.assertEqual({'key1': 'value1'}, tg_payload.kpi)
+        self.assertEqual(3, len(tg_payload._fields))
+
+    def test__init_missing_required_fields(self):
+        with self.assertRaises(exceptions.PayloadMissingAttributes):
+            payloads.TrafficGeneratorPayload(version=1, iteration=10)
+        with self.assertRaises(exceptions.PayloadMissingAttributes):
+            payloads.TrafficGeneratorPayload(iteration=10, kpi={})
+        with self.assertRaises(exceptions.PayloadMissingAttributes):
+            payloads.TrafficGeneratorPayload(iteration=10)
+
+
+class RunnerPayloadTestCase(ut_base.BaseUnitTestCase):
+
+    def test_init(self):
+        runner_payload = payloads.RunnerPayload(version=5,
+                                                data={'key1': 'value1'})
+        self.assertEqual(5, runner_payload.version)
+        self.assertEqual({'key1': 'value1'}, runner_payload.data)
+
+    def test__init_missing_required_fields(self):
+        with self.assertRaises(exceptions.PayloadMissingAttributes):
+            payloads.RunnerPayload(version=1)
+        with self.assertRaises(exceptions.PayloadMissingAttributes):
+            payloads.RunnerPayload(data=None)
+        with self.assertRaises(exceptions.PayloadMissingAttributes):
+            payloads.RunnerPayload()
index 0289689..22286e5 100644 (file)
@@ -44,3 +44,10 @@ class MessagingProducerTestCase(ut_base.BaseUnitTestCase):
                 topic='test_topic', fanout=True, server=messaging.SERVER)
             mock_RPCClient.assert_called_once_with('test_rpc_transport',
                                                    'test_Target')
+
+    def test_id(self):
+        with mock.patch.object(oslo_messaging, 'RPCClient'), \
+                mock.patch.object(oslo_messaging, 'get_rpc_transport'), \
+                mock.patch.object(oslo_messaging, 'Target'):
+            msg_producer = _MessagingProducer('topic', 'id_to_check')
+        self.assertEqual('id_to_check', msg_producer.id)
diff --git a/yardstick/tests/unit/common/test_kubernetes_utils.py b/yardstick/tests/unit/common/test_kubernetes_utils.py
new file mode 100644 (file)
index 0000000..bdc2c12
--- /dev/null
@@ -0,0 +1,252 @@
+# Copyright (c) 2018 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.
+
+import mock
+from kubernetes import client
+from kubernetes.client import rest
+from kubernetes import config
+
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.common import kubernetes_utils
+from yardstick.tests.unit import base
+
+
+class GetExtensionsV1betaApiTestCase(base.BaseUnitTestCase):
+
+    @mock.patch.object(client, 'ApiextensionsV1beta1Api', return_value='api')
+    @mock.patch.object(config, 'load_kube_config')
+    def test_execute_correct(self, mock_load_kube_config, mock_api):
+        self.assertEqual('api', kubernetes_utils.get_extensions_v1beta_api())
+        mock_load_kube_config.assert_called_once_with(
+            config_file=constants.K8S_CONF_FILE)
+        mock_api.assert_called_once()
+
+    @mock.patch.object(config, 'load_kube_config')
+    def test_execute_exception(self, mock_load_kube_config):
+        mock_load_kube_config.side_effect = IOError
+        with self.assertRaises(exceptions.KubernetesConfigFileNotFound):
+            kubernetes_utils.get_extensions_v1beta_api()
+
+
+class GetCustomObjectsApiTestCase(base.BaseUnitTestCase):
+
+    @mock.patch.object(client, 'CustomObjectsApi', return_value='api')
+    @mock.patch.object(config, 'load_kube_config')
+    def test_execute_correct(self, mock_load_kube_config, mock_api):
+        self.assertEqual('api', kubernetes_utils.get_custom_objects_api())
+        mock_load_kube_config.assert_called_once_with(
+            config_file=constants.K8S_CONF_FILE)
+        mock_api.assert_called_once()
+
+    @mock.patch.object(config, 'load_kube_config')
+    def test_execute_exception(self, mock_load_kube_config):
+        mock_load_kube_config.side_effect = IOError
+        with self.assertRaises(exceptions.KubernetesConfigFileNotFound):
+            kubernetes_utils.get_custom_objects_api()
+
+
+class CreateCustomResourceDefinitionTestCase(base.BaseUnitTestCase):
+
+    @mock.patch.object(client, 'V1beta1CustomResourceDefinition',
+                       return_value='crd_obj')
+    @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api')
+    def test_execute_correct(self, mock_get_api, mock_crd):
+        mock_create_crd = mock.Mock()
+        mock_get_api.return_value = mock_create_crd
+        body = {'spec': 'fake_spec', 'metadata': 'fake_metadata'}
+
+        kubernetes_utils.create_custom_resource_definition(body)
+        mock_get_api.assert_called_once()
+        mock_crd.assert_called_once_with(spec='fake_spec',
+                                         metadata='fake_metadata')
+        mock_create_crd.create_custom_resource_definition.\
+            assert_called_once_with('crd_obj')
+
+    @mock.patch.object(client, 'V1beta1CustomResourceDefinition',
+                       return_value='crd_obj')
+    @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api')
+    def test_execute_exception(self, mock_get_api, mock_crd):
+        mock_create_crd = mock.Mock()
+        mock_create_crd.create_custom_resource_definition.\
+            side_effect = rest.ApiException
+        mock_get_api.return_value = mock_create_crd
+        body = {'spec': 'fake_spec', 'metadata': 'fake_metadata'}
+
+        with self.assertRaises(exceptions.KubernetesApiException):
+            kubernetes_utils.create_custom_resource_definition(body)
+        mock_get_api.assert_called_once()
+        mock_crd.assert_called_once_with(spec='fake_spec',
+                                         metadata='fake_metadata')
+        mock_create_crd.create_custom_resource_definition.\
+            assert_called_once_with('crd_obj')
+
+
+class DeleteCustomResourceDefinitionTestCase(base.BaseUnitTestCase):
+
+    @mock.patch.object(client, 'V1DeleteOptions', return_value='del_obj')
+    @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api')
+    def test_execute_correct(self, mock_get_api, mock_delobj):
+        mock_delete_crd = mock.Mock()
+        mock_get_api.return_value = mock_delete_crd
+
+        kubernetes_utils.delete_custom_resource_definition('name')
+        mock_get_api.assert_called_once()
+        mock_delobj.assert_called_once()
+        mock_delete_crd.delete_custom_resource_definition.\
+            assert_called_once_with('name', 'del_obj')
+
+    @mock.patch.object(client, 'V1DeleteOptions', return_value='del_obj')
+    @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api')
+    def test_execute_exception(self, mock_get_api, mock_delobj):
+        mock_delete_crd = mock.Mock()
+        mock_delete_crd.delete_custom_resource_definition.\
+            side_effect = rest.ApiException
+        mock_get_api.return_value = mock_delete_crd
+
+        with self.assertRaises(exceptions.KubernetesApiException):
+            kubernetes_utils.delete_custom_resource_definition('name')
+        mock_delobj.assert_called_once()
+        mock_delete_crd.delete_custom_resource_definition.\
+            assert_called_once_with('name', 'del_obj')
+
+
+class GetCustomResourceDefinitionTestCase(base.BaseUnitTestCase):
+
+    @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api')
+    def test_execute_value(self, mock_get_api):
+        crd_obj = mock.Mock()
+        crd_obj.spec.names.kind = 'some_kind'
+        crd_list = mock.Mock()
+        crd_list.items = [crd_obj]
+        mock_api = mock.Mock()
+        mock_api.list_custom_resource_definition.return_value = crd_list
+        mock_get_api.return_value = mock_api
+        self.assertEqual(
+            crd_obj,
+            kubernetes_utils.get_custom_resource_definition('some_kind'))
+
+    @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api')
+    def test_execute_none(self, mock_get_api):
+        crd_obj = mock.Mock()
+        crd_obj.spec.names.kind = 'some_kind'
+        crd_list = mock.Mock()
+        crd_list.items = [crd_obj]
+        mock_api = mock.Mock()
+        mock_api.list_custom_resource_definition.return_value = crd_list
+        mock_get_api.return_value = mock_api
+        self.assertIsNone(
+            kubernetes_utils.get_custom_resource_definition('other_kind'))
+
+    @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api')
+    def test_execute_exception(self, mock_get_api):
+        mock_api = mock.Mock()
+        mock_api.list_custom_resource_definition.\
+            side_effect = rest.ApiException
+        mock_get_api.return_value = mock_api
+        with self.assertRaises(exceptions.KubernetesApiException):
+            kubernetes_utils.get_custom_resource_definition('kind')
+
+
+class CreateNetworkTestCase(base.BaseUnitTestCase):
+    @mock.patch.object(kubernetes_utils, 'get_custom_objects_api')
+    def test_execute_correct(self, mock_get_api):
+        mock_api = mock.Mock()
+        mock_get_api.return_value = mock_api
+        group = 'group.com'
+        version = mock.Mock()
+        plural = 'networks'
+        body = mock.Mock()
+
+        kubernetes_utils.create_network(
+            constants.SCOPE_CLUSTER, group, version, plural, body)
+        mock_api.create_cluster_custom_object.assert_called_once_with(
+            group, version, plural, body)
+
+        mock_api.reset_mock()
+        kubernetes_utils.create_network(
+            constants.SCOPE_NAMESPACED, group, version, plural, body)
+        mock_api.create_namespaced_custom_object.assert_called_once_with(
+            group, version, 'default', plural, body)
+
+
+    @mock.patch.object(kubernetes_utils, 'get_custom_objects_api')
+    def test_execute_exception(self, mock_get_api):
+        mock_api = mock.Mock()
+        mock_api.create_cluster_custom_object.side_effect = rest.ApiException
+        mock_get_api.return_value = mock_api
+        with self.assertRaises(exceptions.KubernetesApiException):
+            kubernetes_utils.create_network(
+                constants.SCOPE_CLUSTER, mock.ANY, mock.ANY, mock.ANY,
+                mock.ANY)
+
+
+class DeleteNetworkTestCase(base.BaseUnitTestCase):
+    @mock.patch.object(kubernetes_utils, 'get_custom_objects_api')
+    def test_execute_correct(self, mock_get_api):
+        mock_api = mock.Mock()
+        mock_get_api.return_value = mock_api
+        group = 'group.com'
+        version = mock.Mock()
+        plural = 'networks'
+        name = 'network'
+
+        kubernetes_utils.delete_network(
+            constants.SCOPE_CLUSTER, group, version, plural, name)
+        mock_api.delete_cluster_custom_object.assert_called_once_with(
+            group, version, plural, name, {})
+
+        mock_api.reset_mock()
+        kubernetes_utils.delete_network(
+            constants.SCOPE_NAMESPACED, group, version, plural, name)
+        mock_api.delete_namespaced_custom_object.assert_called_once_with(
+            group, version, 'default', plural, name, {})
+
+    @mock.patch.object(kubernetes_utils, 'get_custom_objects_api')
+    def test_execute_exception(self, mock_get_api):
+        mock_api = mock.Mock()
+        mock_api.delete_cluster_custom_object.side_effect = rest.ApiException
+        mock_get_api.return_value = mock_api
+        with self.assertRaises(exceptions.KubernetesApiException):
+            kubernetes_utils.delete_network(
+                constants.SCOPE_CLUSTER, mock.ANY, mock.ANY, mock.ANY,
+                mock.ANY)
+
+
+class DeletePodTestCase(base.BaseUnitTestCase):
+    @mock.patch.object(kubernetes_utils, 'get_core_api')
+    def test_execute_correct(self, mock_get_api):
+        mock_api = mock.Mock()
+        mock_get_api.return_value = mock_api
+
+        kubernetes_utils.delete_pod("name", body=None)
+        mock_api.delete_namespaced_pod.assert_called_once_with(
+            "name", 'default', None)
+
+    @mock.patch.object(kubernetes_utils, 'get_core_api')
+    def test_execute_exception(self, mock_get_api):
+        mock_api = mock.Mock()
+        mock_api.delete_namespaced_pod.side_effect = rest.ApiException(status=200)
+
+        mock_get_api.return_value = mock_api
+        with self.assertRaises(exceptions.KubernetesApiException):
+            kubernetes_utils.delete_pod(mock.ANY, skip_codes=[404])
+
+    @mock.patch.object(kubernetes_utils, 'get_core_api')
+    def test_execute_skip_exception(self, mock_get_api):
+        mock_api = mock.Mock()
+        mock_api.delete_namespaced_pod.side_effect = rest.ApiException(status=404)
+
+        mock_get_api.return_value = mock_api
+        kubernetes_utils.delete_pod(mock.ANY, skip_codes=[404])
index 6247afd..446afdd 100644 (file)
@@ -16,6 +16,7 @@ import mock
 import os
 import six
 from six.moves import configparser
+import socket
 import time
 import unittest
 
@@ -1282,3 +1283,29 @@ class WaitUntilTrueTestCase(ut_base.BaseUnitTestCase):
             self.assertIsNone(
                 utils.wait_until_true(lambda: False, timeout=1, sleep=1,
                                       exception=MyTimeoutException))
+
+
+class SendSocketCommandTestCase(unittest.TestCase):
+
+    @mock.patch.object(socket, 'socket')
+    def test_execute_correct(self, mock_socket):
+        mock_socket_obj = mock.Mock()
+        mock_socket_obj.connect_ex.return_value = 0
+        mock_socket.return_value = mock_socket_obj
+        self.assertEqual(0, utils.send_socket_command('host', 22, 'command'))
+        mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
+        mock_socket_obj.connect_ex.assert_called_once_with(('host', 22))
+        mock_socket_obj.sendall.assert_called_once_with(six.b('command'))
+        mock_socket_obj.close.assert_called_once()
+
+    @mock.patch.object(socket, 'socket')
+    def test_execute_exception(self, mock_socket):
+        mock_socket_obj = mock.Mock()
+        mock_socket_obj.connect_ex.return_value = 0
+        mock_socket.return_value = mock_socket_obj
+        mock_socket_obj.sendall.side_effect = socket.error
+        self.assertEqual(1, utils.send_socket_command('host', 22, 'command'))
+        mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM)
+        mock_socket_obj.connect_ex.assert_called_once_with(('host', 22))
+        mock_socket_obj.sendall.assert_called_once_with(six.b('command'))
+        mock_socket_obj.close.assert_called_once()
index 4271f85..cffa4d4 100644 (file)
 # 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.
-#
 
-import unittest
+import copy
 import mock
+import unittest
 
 from yardstick.network_services.collector import subscriber
 from yardstick import ssh
@@ -38,14 +38,15 @@ class MockVnfAprrox(object):
 
 class CollectorTestCase(unittest.TestCase):
 
-    NODES = {'context1': [{'name': 'node1',
-                           'ip': '1.2.3.4',
-                           'collectd': {
-                               'plugins': {'abc': 12, 'def': 34},
-                               'interval': 987
-                           },
-                           }]
-             }
+    NODES = {
+        'context1': [{'name': 'node1',
+                      'ip': '1.2.3.4',
+                      'collectd': {
+                          'plugins': {'abc': 12, 'def': 34},
+                          'interval': 987}
+                      }
+        ]
+    }
 
     def setUp(self):
         vnf = MockVnfAprrox()
@@ -61,13 +62,29 @@ class CollectorTestCase(unittest.TestCase):
     def tearDown(self):
         self.ssh_patch.stop()
 
-    def test___init__(self, *_):
+    def test___init__(self, *args):
         vnf = MockVnfAprrox()
         collector = subscriber.Collector([vnf], self.NODES)
         self.assertEqual(len(collector.vnfs), 1)
         self.assertEqual(len(collector.nodes), 1)
 
-    def test_start(self, *_):
+    def test___init__no_node_information(self, *args):
+        vnf = MockVnfAprrox()
+        nodes = copy.deepcopy(self.NODES)
+        nodes['context1'].append(None)
+        collector = subscriber.Collector([vnf], nodes)
+        self.assertEqual(len(collector.vnfs), 1)
+        self.assertEqual(len(collector.nodes), 1)
+
+    def test___init__no_node_information_in_context(self, *args):
+        vnf = MockVnfAprrox()
+        nodes = copy.deepcopy(self.NODES)
+        nodes['context1'] = None
+        collector = subscriber.Collector([vnf], nodes)
+        self.assertEqual(len(collector.vnfs), 1)
+        self.assertEqual(len(collector.nodes), 1)
+
+    def test_start(self, *args):
         resource_profile = mock.MagicMock()
         self.collector.resource_profiles = {'key': resource_profile}
         self.collector.bin_path = 'path'
@@ -92,7 +109,7 @@ class CollectorTestCase(unittest.TestCase):
         for resource in self.collector.resource_profiles.values():
             resource.stop.assert_called_once()
 
-    def test_get_kpi(self, *_):
+    def test_get_kpi(self, *args):
         result = self.collector.get_kpi()
 
         self.assertEqual(2, len(result))
index 34afa3d..541855a 100644 (file)
@@ -203,13 +203,9 @@ class TestIxNextgen(unittest.TestCase):
         ixnet_gen._ixnet = self.ixnet
         framesize = {'64B': '75', '512b': '25'}
         output = ixnet_gen._parse_framesize(framesize)
-        for idx in range(len(framesize)):
-            if output[idx * 2] == 64:
-                self.assertEqual(75, output[idx * 2 + 1])
-            elif output[idx * 2] == 512:
-                self.assertEqual(25, output[idx * 2 + 1])
-            else:
-                raise self.failureException('Framesize (64, 512) not present')
+        self.assertEqual(2, len(output))
+        self.assertIn([64, 64, 75], output)
+        self.assertIn([512, 512, 25], output)
 
     @mock.patch.object(IxNetwork, 'IxNet')
     def test_connect(self, mock_ixnet):
index f04d2c6..01fc19a 100644 (file)
@@ -11,7 +11,6 @@
 # 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.
-#
 
 import unittest
 import mock
@@ -19,22 +18,14 @@ import os
 import re
 import copy
 
-from yardstick.tests import STL_MOCKS
-from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
 from yardstick.common import utils
 from yardstick.common import exceptions
 from yardstick.benchmark.contexts import base as ctx_base
-
-
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
-
-if stl_patch:
-    from yardstick.network_services.vnf_generic.vnf import acl_vnf
-    from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
-    from yardstick.network_services.nfvi.resource import ResourceProfile
-    from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper
+from yardstick.network_services.vnf_generic.vnf import acl_vnf
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.nfvi.resource import ResourceProfile
+from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
 
 
 TEST_FILE_YAML = 'nsb_test_case.yaml'
@@ -246,7 +237,7 @@ class TestAclApproxVnf(unittest.TestCase):
 
     def test___init__(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
+        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
         self.assertIsNone(acl_approx_vnf._vnf_process)
 
     @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
@@ -256,7 +247,7 @@ class TestAclApproxVnf(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
+        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
         acl_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {acl_approx_vnf.name: "mock"}
         }
@@ -279,7 +270,7 @@ class TestAclApproxVnf(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
+        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
         acl_approx_vnf.q_in = mock.MagicMock()
         acl_approx_vnf.q_out = mock.MagicMock()
         acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
@@ -291,7 +282,7 @@ class TestAclApproxVnf(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
+        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
         acl_approx_vnf.q_in = mock.MagicMock()
         acl_approx_vnf.q_out = mock.MagicMock()
         acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
@@ -312,7 +303,7 @@ class TestAclApproxVnf(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
+        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
         acl_approx_vnf._build_config = mock.MagicMock()
         acl_approx_vnf.queue_wrapper = mock.MagicMock()
         acl_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
@@ -332,7 +323,7 @@ class TestAclApproxVnf(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
+        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
         acl_approx_vnf.deploy_helper = mock.MagicMock()
         acl_approx_vnf.resource_helper = mock.MagicMock()
         acl_approx_vnf._build_config = mock.MagicMock()
@@ -350,7 +341,7 @@ class TestAclApproxVnf(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
+        acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
         acl_approx_vnf._vnf_process = mock.MagicMock()
         acl_approx_vnf._vnf_process.terminate = mock.Mock()
         acl_approx_vnf.used_drivers = {"01:01.0": "i40e",
index ebedcb4..2ea13a5 100644 (file)
 # 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.
-#
 
 import multiprocessing
 import os
+import uuid
 
 import mock
+from oslo_config import cfg
+import oslo_messaging
 import unittest
 
+from yardstick.common import messaging
+from yardstick.common.messaging import payloads
 from yardstick.network_services.vnf_generic.vnf import base
 from yardstick.ssh import SSH
+from yardstick.tests.unit import base as ut_base
 
 
 IP_PIPELINE_CFG_FILE_TPL = ("arp_route_tbl = ({port0_local_ip_hex},"
@@ -140,6 +145,24 @@ VNFD = {
 }
 
 
+class _DummyGenericTrafficGen(base.GenericTrafficGen):  # pragma: no cover
+
+    def run_traffic(self, *args):
+        pass
+
+    def terminate(self):
+        pass
+
+    def collect_kpi(self):
+        pass
+
+    def instantiate(self, *args):
+        pass
+
+    def scale(self, flavor=''):
+        pass
+
+
 class FileAbsPath(object):
     def __init__(self, module_file):
         super(FileAbsPath, self).__init__()
@@ -206,22 +229,23 @@ class TestQueueFileWrapper(unittest.TestCase):
         self.assertIsNotNone(queue_file_wrapper.q_out.empty())
 
 
-class TestGenericVNF(unittest.TestCase):
+class TestGenericVNF(ut_base.BaseUnitTestCase):
 
     def test_definition(self):
         """Make sure that the abstract class cannot be instantiated"""
         with self.assertRaises(TypeError) as exc:
             # pylint: disable=abstract-class-instantiated
-            base.GenericVNF('vnf1', VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+            base.GenericVNF('vnf1', VNFD['vnfd:vnfd-catalog']['vnfd'][0],
+                            'task_id')
 
-        msg = ("Can't instantiate abstract class GenericVNF with abstract methods "
-               "collect_kpi, instantiate, scale, start_collect, "
+        msg = ("Can't instantiate abstract class GenericVNF with abstract "
+               "methods collect_kpi, instantiate, scale, start_collect, "
                "stop_collect, terminate, wait_for_instantiate")
 
         self.assertEqual(msg, str(exc.exception))
 
 
-class TestGenericTrafficGen(unittest.TestCase):
+class GenericTrafficGenTestCase(ut_base.BaseUnitTestCase):
 
     def test_definition(self):
         """Make sure that the abstract class cannot be instantiated"""
@@ -229,8 +253,96 @@ class TestGenericTrafficGen(unittest.TestCase):
         name = 'vnf1'
         with self.assertRaises(TypeError) as exc:
             # pylint: disable=abstract-class-instantiated
-            base.GenericTrafficGen(name, vnfd)
+            base.GenericTrafficGen(name, vnfd, 'task_id')
         msg = ("Can't instantiate abstract class GenericTrafficGen with "
                "abstract methods collect_kpi, instantiate, run_traffic, "
                "scale, terminate")
         self.assertEqual(msg, str(exc.exception))
+
+    def test_get_mq_producer_id(self):
+        vnfd = {'benchmark': {'kpi': mock.ANY},
+                'vdu': [{'external-interface': 'ext_int'}]
+                }
+        tg = _DummyGenericTrafficGen('name', vnfd, 'task_id')
+        tg._mq_producer = mock.Mock()
+        tg._mq_producer.id = 'fake_id'
+        self.assertEqual('fake_id', tg.get_mq_producer_id())
+
+
+class TrafficGeneratorProducerTestCase(ut_base.BaseUnitTestCase):
+
+    @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+    @mock.patch.object(oslo_messaging, 'RPCClient')
+    @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+                       return_value='rpc_transport')
+    @mock.patch.object(cfg, 'CONF')
+    def test__init(self, mock_config, mock_transport, mock_rpcclient,
+                   mock_target):
+        _id = uuid.uuid1().int
+        tg_producer = base.TrafficGeneratorProducer(_id)
+        mock_transport.assert_called_once_with(
+            mock_config, url='rabbit://yardstick:yardstick@localhost:5672/')
+        mock_target.assert_called_once_with(topic=messaging.TOPIC_TG,
+                                            fanout=True,
+                                            server=messaging.SERVER)
+        mock_rpcclient.assert_called_once_with('rpc_transport', 'rpc_target')
+        self.assertEqual(_id, tg_producer._id)
+        self.assertEqual(messaging.TOPIC_TG, tg_producer._topic)
+
+    @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+    @mock.patch.object(oslo_messaging, 'RPCClient')
+    @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+                       return_value='rpc_transport')
+    @mock.patch.object(payloads, 'TrafficGeneratorPayload',
+                       return_value='tg_pload')
+    def test_tg_method_started(self, mock_tg_payload, *args):
+        tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int)
+        with mock.patch.object(tg_producer, 'send_message') as mock_message:
+            tg_producer.tg_method_started(version=10)
+
+        mock_message.assert_called_once_with(messaging.TG_METHOD_STARTED,
+                                             'tg_pload')
+        mock_tg_payload.assert_called_once_with(version=10, iteration=0,
+                                                kpi={})
+
+    @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+    @mock.patch.object(oslo_messaging, 'RPCClient')
+    @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+                       return_value='rpc_transport')
+    @mock.patch.object(payloads, 'TrafficGeneratorPayload',
+                       return_value='tg_pload')
+    def test_tg_method_finished(self, mock_tg_payload, *args):
+        tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int)
+        with mock.patch.object(tg_producer, 'send_message') as mock_message:
+            tg_producer.tg_method_finished(version=20)
+
+        mock_message.assert_called_once_with(messaging.TG_METHOD_FINISHED,
+                                             'tg_pload')
+        mock_tg_payload.assert_called_once_with(version=20, iteration=0,
+                                                kpi={})
+
+    @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+    @mock.patch.object(oslo_messaging, 'RPCClient')
+    @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+                       return_value='rpc_transport')
+    @mock.patch.object(payloads, 'TrafficGeneratorPayload',
+                       return_value='tg_pload')
+    def test_tg_method_iteration(self, mock_tg_payload, *args):
+        tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int)
+        with mock.patch.object(tg_producer, 'send_message') as mock_message:
+            tg_producer.tg_method_iteration(100, version=30, kpi={'k': 'v'})
+
+        mock_message.assert_called_once_with(messaging.TG_METHOD_ITERATION,
+                                             'tg_pload')
+        mock_tg_payload.assert_called_once_with(version=30, iteration=100,
+                                                kpi={'k': 'v'})
+
+
+class GenericVNFConsumerTestCase(ut_base.BaseUnitTestCase):
+
+    def test__init(self):
+        endpoints = 'endpoint_1'
+        _ids = [uuid.uuid1().int]
+        gvnf_consumer = base.GenericVNFConsumer(_ids, endpoints)
+        self.assertEqual(_ids, gvnf_consumer._ids)
+        self.assertEqual([endpoints], gvnf_consumer._endpoints)
index 635ca41..32f5b75 100644 (file)
@@ -318,14 +318,14 @@ class TestCgnaptApproxVnf(unittest.TestCase):
 
     def test___init__(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
         self.assertIsNone(cgnapt_approx_vnf._vnf_process)
 
     @mock.patch.object(process, 'check_if_process_failed')
     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
     def test_collect_kpi(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
         cgnapt_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {cgnapt_approx_vnf.name: "mock"}
         }
@@ -349,7 +349,7 @@ class TestCgnaptApproxVnf(unittest.TestCase):
     @mock.patch.object(time, 'sleep')
     def test_vnf_execute_command(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
         cgnapt_approx_vnf.q_in = mock.Mock()
         cgnapt_approx_vnf.q_out = mock.Mock()
         cgnapt_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
@@ -357,7 +357,7 @@ class TestCgnaptApproxVnf(unittest.TestCase):
 
     def test_get_stats(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
         with mock.patch.object(cgnapt_approx_vnf, 'vnf_execute') as mock_exec:
             mock_exec.return_value = 'output'
             self.assertEqual('output', cgnapt_approx_vnf.get_stats())
@@ -366,7 +366,7 @@ class TestCgnaptApproxVnf(unittest.TestCase):
 
     def test_run_vcgnapt(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
         cgnapt_approx_vnf.ssh_helper = mock.Mock()
         cgnapt_approx_vnf.setup_helper = mock.Mock()
         with mock.patch.object(cgnapt_approx_vnf, '_build_config'), \
@@ -379,7 +379,7 @@ class TestCgnaptApproxVnf(unittest.TestCase):
     @mock.patch.object(ctx_base.Context, 'get_context_from_server')
     def test_instantiate(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
         cgnapt_approx_vnf.deploy_helper = mock.MagicMock()
         cgnapt_approx_vnf.resource_helper = mock.MagicMock()
         cgnapt_approx_vnf._build_config = mock.MagicMock()
@@ -396,7 +396,7 @@ class TestCgnaptApproxVnf(unittest.TestCase):
     def test__vnf_up_post(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
         self.scenario_cfg['options'][name]['napt'] = 'static'
-        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
         cgnapt_approx_vnf.vnf_execute = mock.Mock()
         cgnapt_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
         with mock.patch.object(cgnapt_approx_vnf, 'setup_helper') as \
@@ -407,6 +407,6 @@ class TestCgnaptApproxVnf(unittest.TestCase):
 
     def test__vnf_up_post_short(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+        cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
         cgnapt_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
         cgnapt_approx_vnf._vnf_up_post()
index 678e580..f144e8c 100644 (file)
@@ -317,7 +317,7 @@ class TestProxApproxVnf(unittest.TestCase):
     @mock.patch(SSH_HELPER)
     def test___init__(self, ssh, *args):
         mock_ssh(ssh)
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         self.assertIsNone(prox_approx_vnf._vnf_process)
 
     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
@@ -325,7 +325,7 @@ class TestProxApproxVnf(unittest.TestCase):
     def test_collect_kpi_no_client(self, ssh, *args):
         mock_ssh(ssh)
 
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         prox_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {prox_approx_vnf.name: "mock"}
         }
@@ -350,7 +350,7 @@ class TestProxApproxVnf(unittest.TestCase):
                                                 [2, 1, 2, 3, 4, 5], [3, 1, 2, 3, 4, 5]]
         resource_helper.collect_collectd_kpi.return_value = {'core': {'result': 234}}
 
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         prox_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {prox_approx_vnf.name: "mock"}
         }
@@ -376,7 +376,8 @@ class TestProxApproxVnf(unittest.TestCase):
         mock_ssh(ssh)
 
         resource_helper = mock.MagicMock()
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, deepcopy(self.VNFD0))
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, deepcopy(self.VNFD0),
+                                                 'task_id')
         prox_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {prox_approx_vnf.name: "mock"}
         }
@@ -399,7 +400,7 @@ class TestProxApproxVnf(unittest.TestCase):
     def test_run_prox(self, ssh, *_):
         mock_ssh(ssh)
 
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         prox_approx_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG
         prox_approx_vnf.ssh_helper.join_bin_path.return_value = '/tool_path12/tool_file34'
         prox_approx_vnf.setup_helper.remote_path = 'configs/file56.cfg'
@@ -413,7 +414,7 @@ class TestProxApproxVnf(unittest.TestCase):
 
     @mock.patch(SSH_HELPER)
     def bad_test_instantiate(self, *args):
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         prox_approx_vnf.scenario_helper = mock.MagicMock()
         prox_approx_vnf.setup_helper = mock.MagicMock()
         # we can't mock super
@@ -423,7 +424,7 @@ class TestProxApproxVnf(unittest.TestCase):
     @mock.patch(SSH_HELPER)
     def test_wait_for_instantiate_panic(self, ssh, *args):
         mock_ssh(ssh, exec_result=(1, "", ""))
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         prox_approx_vnf._vnf_process = mock.MagicMock(**{"is_alive.return_value": True})
         prox_approx_vnf._run_prox = mock.Mock(return_value=0)
         prox_approx_vnf.WAIT_TIME = 0
@@ -435,7 +436,7 @@ class TestProxApproxVnf(unittest.TestCase):
     @mock.patch(SSH_HELPER)
     def test_terminate(self, ssh, *args):
         mock_ssh(ssh)
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         prox_approx_vnf._vnf_process = mock.MagicMock()
         prox_approx_vnf._vnf_process.terminate = mock.Mock()
         prox_approx_vnf.ssh_helper = mock.MagicMock()
@@ -447,7 +448,7 @@ class TestProxApproxVnf(unittest.TestCase):
     @mock.patch(SSH_HELPER)
     def test__vnf_up_post(self, ssh, *args):
         mock_ssh(ssh)
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         prox_approx_vnf.resource_helper = resource_helper = mock.Mock()
 
         prox_approx_vnf._vnf_up_post()
@@ -456,7 +457,7 @@ class TestProxApproxVnf(unittest.TestCase):
     @mock.patch(SSH_HELPER)
     def test_vnf_execute_oserror(self, ssh, *args):
         mock_ssh(ssh)
-        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0)
+        prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
         prox_approx_vnf.resource_helper = resource_helper = mock.Mock()
 
         resource_helper.execute.side_effect = OSError(errno.EPIPE, "")
index edd0ff7..ad74145 100644 (file)
 # 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.
-#
 
 import unittest
 import mock
 
-from yardstick.tests import STL_MOCKS
 from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
 from yardstick.benchmark.contexts import base as ctx_base
-
-
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
-
-if stl_patch:
-    from yardstick.network_services.vnf_generic.vnf.router_vnf import RouterVNF
+from yardstick.network_services.vnf_generic.vnf.router_vnf import RouterVNF
 
 
 TEST_FILE_YAML = 'nsb_test_case.yaml'
@@ -208,7 +199,7 @@ class TestRouterVNF(unittest.TestCase):
 
     def test___init__(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        router_vnf = RouterVNF(name, vnfd)
+        router_vnf = RouterVNF(name, vnfd, 'task_id')
         self.assertIsNone(router_vnf._vnf_process)
 
     def test_get_stats(self):
@@ -222,7 +213,7 @@ class TestRouterVNF(unittest.TestCase):
         m = mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        router_vnf = RouterVNF(name, vnfd)
+        router_vnf = RouterVNF(name, vnfd, 'task_id')
         router_vnf.scenario_helper.scenario_cfg = {
             'nodes': {router_vnf.name: "mock"}
         }
@@ -241,7 +232,7 @@ class TestRouterVNF(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        router_vnf = RouterVNF(name, vnfd)
+        router_vnf = RouterVNF(name, vnfd, 'task_id')
         router_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
         router_vnf._run()
         router_vnf.ssh_helper.drop_connection.assert_called_once()
@@ -252,7 +243,7 @@ class TestRouterVNF(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        router_vnf = RouterVNF(name, vnfd)
+        router_vnf = RouterVNF(name, vnfd, 'task_id')
         router_vnf.WAIT_TIME = 0
         router_vnf.INTERFACE_WAIT = 0
         self.scenario_cfg.update({"nodes": {"vnf__1": ""}})
@@ -265,7 +256,7 @@ class TestRouterVNF(unittest.TestCase):
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        router_vnf = RouterVNF(name, vnfd)
+        router_vnf = RouterVNF(name, vnfd, 'task_id')
         router_vnf._vnf_process = mock.MagicMock()
         router_vnf._vnf_process.terminate = mock.Mock()
         self.assertIsNone(router_vnf.terminate())
index 331e80d..c35d2db 100644 (file)
@@ -1090,6 +1090,57 @@ class TestClientResourceHelper(unittest.TestCase):
 
         self.assertIs(client_resource_helper._connect(client), client)
 
+    @mock.patch.object(ClientResourceHelper, '_build_ports')
+    @mock.patch.object(ClientResourceHelper, '_run_traffic_once')
+    def test_run_traffic(self, mock_run_traffic_once, mock_build_ports):
+        client_resource_helper = ClientResourceHelper(mock.Mock())
+        client = mock.Mock()
+        traffic_profile = mock.Mock()
+        mq_producer = mock.Mock()
+        with mock.patch.object(client_resource_helper, '_connect') \
+                as mock_connect, \
+                mock.patch.object(client_resource_helper, '_terminated') \
+                as mock_terminated:
+            mock_connect.return_value = client
+            type(mock_terminated).value = mock.PropertyMock(
+                side_effect=[0, 1, lambda x: x])
+            client_resource_helper.run_traffic(traffic_profile, mq_producer)
+
+        mock_build_ports.assert_called_once()
+        traffic_profile.register_generator.assert_called_once()
+        mq_producer.tg_method_started.assert_called_once()
+        mq_producer.tg_method_finished.assert_called_once()
+        mq_producer.tg_method_iteration.assert_called_once_with(1)
+        mock_run_traffic_once.assert_called_once_with(traffic_profile)
+
+    @mock.patch.object(ClientResourceHelper, '_build_ports')
+    @mock.patch.object(ClientResourceHelper, '_run_traffic_once',
+                       side_effect=Exception)
+    def test_run_traffic_exception(self, mock_run_traffic_once,
+                                   mock_build_ports):
+        client_resource_helper = ClientResourceHelper(mock.Mock())
+        client = mock.Mock()
+        traffic_profile = mock.Mock()
+        mq_producer = mock.Mock()
+        with mock.patch.object(client_resource_helper, '_connect') \
+                as mock_connect, \
+                mock.patch.object(client_resource_helper, '_terminated') \
+                as mock_terminated:
+            mock_connect.return_value = client
+            type(mock_terminated).value = mock.PropertyMock(return_value=0)
+            mq_producer.reset_mock()
+            # NOTE(ralonsoh): "trex_stl_exceptions.STLError" is mocked
+            with self.assertRaises(Exception):
+                client_resource_helper.run_traffic(traffic_profile,
+                                                   mq_producer)
+
+        mock_build_ports.assert_called_once()
+        traffic_profile.register_generator.assert_called_once()
+        mock_run_traffic_once.assert_called_once_with(traffic_profile)
+        mq_producer.tg_method_started.assert_called_once()
+        mq_producer.tg_method_finished.assert_not_called()
+        mq_producer.tg_method_iteration.assert_not_called()
+
 
 class TestRfc2544ResourceHelper(unittest.TestCase):
 
@@ -1492,7 +1543,7 @@ class TestSampleVnf(unittest.TestCase):
     }
 
     def test___init__(self):
-        sample_vnf = SampleVNF('vnf1', self.VNFD_0)
+        sample_vnf = SampleVNF('vnf1', self.VNFD_0, 'task_id')
 
         self.assertEqual(sample_vnf.name, 'vnf1')
         self.assertDictEqual(sample_vnf.vnfd_helper, self.VNFD_0)
@@ -1510,7 +1561,8 @@ class TestSampleVnf(unittest.TestCase):
         class MyResourceHelper(ResourceHelper):
             pass
 
-        sample_vnf = SampleVNF('vnf1', self.VNFD_0, MySetupEnvHelper, MyResourceHelper)
+        sample_vnf = SampleVNF('vnf1', self.VNFD_0, 'task_id',
+                               MySetupEnvHelper, MyResourceHelper)
 
         self.assertEqual(sample_vnf.name, 'vnf1')
         self.assertDictEqual(sample_vnf.vnfd_helper, self.VNFD_0)
@@ -1524,7 +1576,7 @@ class TestSampleVnf(unittest.TestCase):
     @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.Process')
     def test__start_vnf(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf._run = mock.Mock()
 
         self.assertIsNone(sample_vnf.queue_wrapper)
@@ -1543,7 +1595,7 @@ class TestSampleVnf(unittest.TestCase):
         }
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf.scenario_helper.scenario_cfg = {
             'nodes': {sample_vnf.name: 'mock'}
         }
@@ -1587,7 +1639,7 @@ class TestSampleVnf(unittest.TestCase):
                          'plugin1': {'param': 1}}}
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf__0', vnfd)
+        sample_vnf = SampleVNF('vnf__0', vnfd, 'task_id')
         sample_vnf._update_collectd_options(scenario_cfg, context_cfg)
         self.assertEqual(sample_vnf.setup_helper.collectd_options, expected)
 
@@ -1614,7 +1666,7 @@ class TestSampleVnf(unittest.TestCase):
                          'plugin1': {'param': 1}}}
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf._update_options(options2, options1)
         self.assertEqual(options2, expected)
 
@@ -1636,7 +1688,7 @@ class TestSampleVnf(unittest.TestCase):
         ]
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf.APP_NAME = 'sample1'
         sample_vnf.WAIT_TIME_FOR_SCRIPT = 0
         sample_vnf._start_server = mock.Mock(return_value=0)
@@ -1667,7 +1719,7 @@ class TestSampleVnf(unittest.TestCase):
         ]
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf.APP_NAME = 'sample1'
         sample_vnf.q_out = mock.Mock()
         sample_vnf.q_out.qsize.side_effect = iter(queue_size_list)
@@ -1677,7 +1729,7 @@ class TestSampleVnf(unittest.TestCase):
 
     def test_terminate_without_vnf_process(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf.APP_NAME = 'sample1'
         sample_vnf.vnf_execute = mock.Mock()
         sample_vnf.ssh_helper = mock.Mock()
@@ -1688,7 +1740,7 @@ class TestSampleVnf(unittest.TestCase):
 
     def test_get_stats(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf.APP_NAME = 'sample1'
         sample_vnf.APP_WORD = 'sample1'
         sample_vnf.vnf_execute = mock.Mock(return_value='the stats')
@@ -1698,7 +1750,7 @@ class TestSampleVnf(unittest.TestCase):
     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
     def test_collect_kpi(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf.scenario_helper.scenario_cfg = {
             'nodes': {sample_vnf.name: "mock"}
         }
@@ -1726,7 +1778,7 @@ class TestSampleVnf(unittest.TestCase):
     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
     def test_collect_kpi_default(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf.scenario_helper.scenario_cfg = {
             'nodes': {sample_vnf.name: "mock"}
         }
@@ -1745,7 +1797,7 @@ class TestSampleVnf(unittest.TestCase):
 
     def test_scale(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         self.assertRaises(y_exceptions.FunctionNotImplemented,
                           sample_vnf.scale)
 
@@ -1753,7 +1805,7 @@ class TestSampleVnf(unittest.TestCase):
         test_cmd = 'test cmd'
         run_kwargs = {'arg1': 'val1', 'arg2': 'val2'}
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sample_vnf = SampleVNF('vnf1', vnfd)
+        sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
         sample_vnf.ssh_helper = mock.Mock()
         sample_vnf.setup_helper = mock.Mock()
         with mock.patch.object(sample_vnf, '_build_config',
@@ -1889,30 +1941,30 @@ class TestSampleVNFTrafficGen(unittest.TestCase):
     }
 
     def test__check_status(self):
-        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
 
         with self.assertRaises(NotImplementedError):
             sample_vnf_tg._check_status()
 
     def test_listen_traffic(self):
-        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
 
         sample_vnf_tg.listen_traffic(mock.Mock())
 
     def test_verify_traffic(self):
-        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
 
         sample_vnf_tg.verify_traffic(mock.Mock())
 
     def test_terminate(self):
-        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
         sample_vnf_tg._traffic_process = mock.Mock()
         sample_vnf_tg._tg_process = mock.Mock()
 
         sample_vnf_tg.terminate()
 
     def test__wait_for_process(self):
-        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
         with mock.patch.object(sample_vnf_tg, '_check_status',
                                return_value=0) as mock_status, \
                 mock.patch.object(sample_vnf_tg, '_tg_process') as mock_proc:
@@ -1923,14 +1975,14 @@ class TestSampleVNFTrafficGen(unittest.TestCase):
             mock_status.assert_called_once()
 
     def test__wait_for_process_not_alive(self):
-        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
         with mock.patch.object(sample_vnf_tg, '_tg_process') as mock_proc:
             mock_proc.is_alive.return_value = False
             self.assertRaises(RuntimeError, sample_vnf_tg._wait_for_process)
             mock_proc.is_alive.assert_called_once()
 
     def test__wait_for_process_delayed(self):
-        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
         with mock.patch.object(sample_vnf_tg, '_check_status',
                                side_effect=[1, 0]) as mock_status, \
                 mock.patch.object(sample_vnf_tg,
@@ -1942,6 +1994,6 @@ class TestSampleVNFTrafficGen(unittest.TestCase):
             mock_status.assert_has_calls([mock.call(), mock.call()])
 
     def test_scale(self):
-        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+        sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
         self.assertRaises(y_exceptions.FunctionNotImplemented,
                           sample_vnf_tg.scale)
index 66f9e93..53474b9 100644 (file)
@@ -16,19 +16,19 @@ import subprocess
 
 import mock
 import six
-import unittest
 
 from yardstick import ssh
 from yardstick.benchmark.contexts import base as ctx_base
 from yardstick.common import utils
 from yardstick.network_services.vnf_generic.vnf import tg_ixload
-from yardstick.network_services.traffic_profile.base import TrafficProfile
+from yardstick.network_services.traffic_profile import base as tp_base
+from yardstick.tests.unit import base as ut_base
 
 
 NAME = "tg__1"
 
 
-class TestIxLoadTrafficGen(unittest.TestCase):
+class TestIxLoadTrafficGen(ut_base.BaseUnitTestCase):
     VNFD = {'vnfd:vnfd-catalog':
             {'vnfd':
              [{'short-name': 'VpeVnf',
@@ -107,28 +107,33 @@ class TestIxLoadTrafficGen(unittest.TestCase):
             "frame_size": 64}}
 
     def setUp(self):
-        self._mock_call = mock.patch.object(subprocess, "call")
+        self._mock_call = mock.patch.object(subprocess, 'call')
         self.mock_call = self._mock_call.start()
         self._mock_open = mock.patch.object(tg_ixload, 'open')
         self.mock_open = self._mock_open.start()
+        self._mock_ssh = mock.patch.object(ssh, 'SSH')
+        self.mock_ssh = self._mock_ssh.start()
+        ssh_obj_mock = mock.Mock(autospec=ssh.SSH)
+        ssh_obj_mock.execute = mock.Mock(return_value=(0, '', ''))
+        ssh_obj_mock.run = mock.Mock(return_value=(0, '', ''))
+        self.mock_ssh.from_node.return_value = ssh_obj_mock
         self.addCleanup(self._stop_mock)
 
     def _stop_mock(self):
         self._mock_call.stop()
         self._mock_open.stop()
+        self._mock_ssh.stop()
 
-    @mock.patch.object(ssh, 'SSH')
-    def test___init__(self, *args):
+    def test___init__(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         self.assertIsNone(ixload_traffic_gen.resource_helper.data)
 
     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
                        return_value='mock_node')
-    @mock.patch.object(ssh, 'SSH')
     def test_collect_kpi(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         ixload_traffic_gen.scenario_helper.scenario_cfg = {
             'nodes': {ixload_traffic_gen.name: "mock"}
         }
@@ -140,97 +145,88 @@ class TestIxLoadTrafficGen(unittest.TestCase):
             'collect_stats': {}}
         self.assertEqual(expected, result)
 
-    @mock.patch.object(ssh, 'SSH')
-    def test_listen_traffic(self, *args):
+    def test_listen_traffic(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         self.assertIsNone(ixload_traffic_gen.listen_traffic({}))
 
     @mock.patch.object(utils, 'find_relative_file')
     @mock.patch.object(utils, 'makedirs')
     @mock.patch.object(ctx_base.Context, 'get_context_from_server')
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
-    @mock.patch.object(ssh, 'SSH')
+    @mock.patch.object(tg_ixload, 'shutil')
     def test_instantiate(self, mock_shutil, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         scenario_cfg = {'tc': "nsb_test_case",
                         'ixia_profile': "ixload.cfg",
                         'task_path': "/path/to/task"}
         ixload_traffic_gen.RESULTS_MOUNT = "/tmp/result"
         mock_shutil.copy = mock.Mock()
-        scenario_cfg.update({'options': {'packetsize': 64, 'traffic_type': 4,
-                                         'rfc2544': {'allowed_drop_rate': '0.8 - 1'},
-                                         'vnf__1': {'rules': 'acl_1rule.yaml',
-                                                    'vnf_config': {'lb_config': 'SW',
-                                                                   'lb_count': 1,
-                                                                   'worker_config':
-                                                                   '1C/1T',
-                                                                   'worker_threads': 1}}
-                                         }})
-        scenario_cfg.update({
-            'nodes': {ixload_traffic_gen.name: "mock"}
-        })
+        scenario_cfg.update(
+            {'options':
+                 {'packetsize': 64, 'traffic_type': 4,
+                  'rfc2544': {'allowed_drop_rate': '0.8 - 1'},
+                  'vnf__1': {'rules': 'acl_1rule.yaml',
+                             'vnf_config': {'lb_config': 'SW',
+                                            'lb_count': 1,
+                                            'worker_config':
+                                                '1C/1T',
+                                            'worker_threads': 1}}
+                  }
+             }
+        )
+        scenario_cfg.update({'nodes': {ixload_traffic_gen.name: "mock"}})
         with mock.patch.object(six.moves.builtins, 'open',
                                create=True) as mock_open:
             mock_open.return_value = mock.MagicMock()
             ixload_traffic_gen.instantiate(scenario_cfg, {})
 
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open")
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min")
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max")
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len")
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
-    @mock.patch.object(ssh, 'SSH')
+    @mock.patch.object(tg_ixload, 'open')
+    @mock.patch.object(tg_ixload, 'min')
+    @mock.patch.object(tg_ixload, 'max')
+    @mock.patch.object(tg_ixload, 'len')
+    @mock.patch.object(tg_ixload, 'shutil')
     def test_run_traffic(self, *args):
-        mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
-        mock_traffic_profile.get_traffic_definition.return_value = "64"
+        mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+        mock_traffic_profile.get_traffic_definition.return_value = '64'
         mock_traffic_profile.params = self.TRAFFIC_PROFILE
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        vnfd["mgmt-interface"].update({"tg-config": {}})
-        vnfd["mgmt-interface"]["tg-config"].update({"ixchassis":
-                                                    "1.1.1.1"})
-        vnfd["mgmt-interface"]["tg-config"].update({"py_bin_path":
-                                                    "/root"})
-        sut = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        vnfd['mgmt-interface'].update({'tg-config': {}})
+        vnfd['mgmt-interface']['tg-config'].update({'ixchassis': '1.1.1.1'})
+        vnfd['mgmt-interface']['tg-config'].update({'py_bin_path': '/root'})
+        sut = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         sut.connection = mock.Mock()
-        sut.connection.run = mock.Mock()
         sut._traffic_runner = mock.Mock(return_value=0)
         result = sut.run_traffic(mock_traffic_profile)
         self.assertIsNone(result)
 
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open")
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min")
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max")
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len")
-    @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
-    @mock.patch.object(ssh, 'SSH')
+    @mock.patch.object(tg_ixload, 'open')
+    @mock.patch.object(tg_ixload, 'min')
+    @mock.patch.object(tg_ixload, 'max')
+    @mock.patch.object(tg_ixload, 'len')
+    @mock.patch.object(tg_ixload, 'shutil')
     def test_run_traffic_csv(self, *args):
-        mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
-        mock_traffic_profile.get_traffic_definition.return_value = "64"
+        mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+        mock_traffic_profile.get_traffic_definition.return_value = '64'
         mock_traffic_profile.params = self.TRAFFIC_PROFILE
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        vnfd["mgmt-interface"].update({"tg-config": {}})
-        vnfd["mgmt-interface"]["tg-config"].update({"ixchassis":
-                                                    "1.1.1.1"})
-        vnfd["mgmt-interface"]["tg-config"].update({"py_bin_path":
-                                                    "/root"})
-        sut = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        vnfd['mgmt-interface'].update({'tg-config': {}})
+        vnfd['mgmt-interface']['tg-config'].update({'ixchassis': '1.1.1.1'})
+        vnfd['mgmt-interface']['tg-config'].update({'py_bin_path': '/root'})
+        sut = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         sut.connection = mock.Mock()
-        sut.connection.run = mock.Mock()
         sut._traffic_runner = mock.Mock(return_value=0)
-        sut.rel_bin_path = mock.Mock(return_value="/tmp/*.csv")
+        subprocess.call(['touch', '/tmp/1.csv'])
+        sut.rel_bin_path = mock.Mock(return_value='/tmp/*.csv')
         result = sut.run_traffic(mock_traffic_profile)
         self.assertIsNone(result)
 
-    @mock.patch.object(ssh, 'SSH')
-    def test_terminate(self, *args):
+    def test_terminate(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         self.assertIsNone(ixload_traffic_gen.terminate())
 
-    @mock.patch.object(ssh, 'SSH')
-    def test_parse_csv_read(self, mock_ssh):
+    def test_parse_csv_read(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
         kpi_data = {
             'HTTP Total Throughput (Kbps)': 1,
@@ -240,21 +236,13 @@ class TestIxLoadTrafficGen(unittest.TestCase):
             'HTTP Transaction Rate': True,
         }
         http_reader = [kpi_data]
-
-        mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
-        mock_ssh_type.execute.return_value = 0, "", ""
-        mock_ssh.from_node.return_value = mock_ssh_type
-
-        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         result = ixload_traffic_gen.resource_helper.result
-
         ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
-        for key_left, key_right in (
-                tg_ixload.IxLoadResourceHelper.KPI_LIST.items()):
-            self.assertEqual(result[key_left][-1], int(kpi_data[key_right]))
+        for k_left, k_right in tg_ixload.IxLoadResourceHelper.KPI_LIST.items():
+            self.assertEqual(result[k_left][-1], int(kpi_data[k_right]))
 
-    @mock.patch.object(ssh, 'SSH')
-    def test_parse_csv_read_value_error(self, mock_ssh, *args):
+    def test_parse_csv_read_value_error(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
         http_reader = [{
             'HTTP Total Throughput (Kbps)': 1,
@@ -263,19 +251,13 @@ class TestIxLoadTrafficGen(unittest.TestCase):
             'HTTP Connection Rate': 4,
             'HTTP Transaction Rate': 5,
         }]
-
-        mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
-        mock_ssh_type.execute.return_value = 0, "", ""
-        mock_ssh.from_node.return_value = mock_ssh_type
-
-        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
         init_value = ixload_traffic_gen.resource_helper.result
-
         ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
-        self.assertDictEqual(ixload_traffic_gen.resource_helper.result, init_value)
+        self.assertDictEqual(ixload_traffic_gen.resource_helper.result,
+                             init_value)
 
-    @mock.patch.object(ssh, 'SSH')
-    def test_parse_csv_read_error(self, mock_ssh, *args):
+    def test_parse_csv_read_error(self,):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
         http_reader = [{
             'HTTP Total Throughput (Kbps)': 1,
@@ -283,12 +265,7 @@ class TestIxLoadTrafficGen(unittest.TestCase):
             'HTTP Concurrent Connections': 3,
             'HTTP Transaction Rate': 5,
         }]
-
-        mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
-        mock_ssh_type.execute.return_value = 0, "", ""
-        mock_ssh.from_node.return_value = mock_ssh_type
-
-        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd)
+        ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
 
         with self.assertRaises(KeyError):
             ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
index d774bb9..434a7b7 100644 (file)
@@ -20,21 +20,15 @@ import mock
 import unittest
 
 from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
-from yardstick.tests import STL_MOCKS
 from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.tg_ping import PingParser
+from yardstick.network_services.vnf_generic.vnf.tg_ping import PingTrafficGen
+from yardstick.network_services.vnf_generic.vnf.tg_ping import PingResourceHelper
+from yardstick.network_services.vnf_generic.vnf.tg_ping import PingSetupEnvHelper
+from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper
 
-SSH_HELPER = "yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper"
-
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
 
-if stl_patch:
-    from yardstick.network_services.vnf_generic.vnf.tg_ping import PingParser
-    from yardstick.network_services.vnf_generic.vnf.tg_ping import PingTrafficGen
-    from yardstick.network_services.vnf_generic.vnf.tg_ping import PingResourceHelper
-    from yardstick.network_services.vnf_generic.vnf.tg_ping import PingSetupEnvHelper
-    from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper
+SSH_HELPER = "yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper"
 
 
 class TestPingResourceHelper(unittest.TestCase):
@@ -232,7 +226,7 @@ class TestPingTrafficGen(unittest.TestCase):
     @mock.patch("yardstick.ssh.SSH")
     def test___init__(self, ssh):
         ssh.from_node.return_value.execute.return_value = 0, "success", ""
-        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0)
+        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
 
         self.assertIsInstance(ping_traffic_gen.setup_helper, PingSetupEnvHelper)
         self.assertIsInstance(ping_traffic_gen.resource_helper, PingResourceHelper)
@@ -249,7 +243,7 @@ class TestPingTrafficGen(unittest.TestCase):
             (0, 'if_name_2', ''),
         ]
         ssh.from_node.return_value.execute.side_effect = iter(execute_result_data)
-        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0)
+        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
         ext_ifs = ping_traffic_gen.vnfd_helper.interfaces
         self.assertNotEqual(ext_ifs[0]['virtual-interface']['local_iface_name'], 'if_name_1')
         self.assertNotEqual(ext_ifs[1]['virtual-interface']['local_iface_name'], 'if_name_2')
@@ -259,7 +253,7 @@ class TestPingTrafficGen(unittest.TestCase):
     def test_collect_kpi(self, ssh, *args):
         mock_ssh(ssh, exec_result=(0, "success", ""))
 
-        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0)
+        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
         ping_traffic_gen.scenario_helper.scenario_cfg = {
             'nodes': {ping_traffic_gen.name: "mock"}
         }
@@ -277,7 +271,7 @@ class TestPingTrafficGen(unittest.TestCase):
     @mock.patch(SSH_HELPER)
     def test_instantiate(self, ssh):
         mock_ssh(ssh, spec=VnfSshHelper, exec_result=(0, "success", ""))
-        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0)
+        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
         ping_traffic_gen.setup_helper.ssh_helper = mock.MagicMock(
             **{"execute.return_value": (0, "xe0_fake", "")})
         self.assertIsInstance(ping_traffic_gen.ssh_helper, mock.Mock)
@@ -292,7 +286,7 @@ class TestPingTrafficGen(unittest.TestCase):
         self.assertIsNotNone(ping_traffic_gen._result)
 
     def test_listen_traffic(self):
-        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0)
+        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
         self.assertIsNone(ping_traffic_gen.listen_traffic({}))
 
     @mock.patch("yardstick.ssh.SSH")
@@ -300,5 +294,5 @@ class TestPingTrafficGen(unittest.TestCase):
         ssh.from_node.return_value.execute.return_value = 0, "success", ""
         ssh.from_node.return_value.run.return_value = 0, "success", ""
 
-        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0)
+        ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
         self.assertIsNone(ping_traffic_gen.terminate())
index 050aa4a..5ad182f 100644 (file)
@@ -17,21 +17,14 @@ import unittest
 import mock
 
 from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
-from yardstick.tests import STL_MOCKS
 from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.tg_prox import ProxTrafficGen
+from yardstick.network_services.traffic_profile.base import TrafficProfile
 
 
 SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
 NAME = 'vnf__1'
 
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
-
-if stl_patch:
-    from yardstick.network_services.vnf_generic.vnf.tg_prox import ProxTrafficGen
-    from yardstick.network_services.traffic_profile.base import TrafficProfile
-
 
 @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
 class TestProxTrafficGen(unittest.TestCase):
@@ -321,7 +314,7 @@ class TestProxTrafficGen(unittest.TestCase):
     @mock.patch(SSH_HELPER)
     def test___init__(self, ssh, *args):
         mock_ssh(ssh)
-        prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0)
+        prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0, 'task_id')
         self.assertIsNone(prox_traffic_gen._tg_process)
         self.assertIsNone(prox_traffic_gen._traffic_process)
 
@@ -329,7 +322,7 @@ class TestProxTrafficGen(unittest.TestCase):
     @mock.patch(SSH_HELPER)
     def test_collect_kpi(self, ssh, *args):
         mock_ssh(ssh)
-        prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0)
+        prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0, 'task_id')
         prox_traffic_gen.scenario_helper.scenario_cfg = {
             'nodes': {prox_traffic_gen.name: "mock"}
         }
@@ -357,7 +350,7 @@ class TestProxTrafficGen(unittest.TestCase):
         mock_traffic_profile.params = self.TRAFFIC_PROFILE
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        prox_traffic_gen = ProxTrafficGen(NAME, vnfd)
+        prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id')
         ssh_helper = mock.MagicMock(
             **{"execute.return_value": (0, "", ""), "bin_path": ""})
         prox_traffic_gen.ssh_helper = ssh_helper
@@ -399,21 +392,22 @@ class TestProxTrafficGen(unittest.TestCase):
         mock_traffic_profile.params = self.TRAFFIC_PROFILE
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sut = ProxTrafficGen(NAME, vnfd)
+        sut = ProxTrafficGen(NAME, vnfd, 'task_id')
         sut._get_socket = mock.MagicMock()
         sut.ssh_helper = mock.Mock()
         sut.ssh_helper.run = mock.Mock()
         sut.setup_helper.prox_config_dict = {}
-        sut._connect_client = mock.Mock(autospec=STLClient)
+        sut._connect_client = mock.Mock(autospec=mock.Mock())
         sut._connect_client.get_stats = mock.Mock(return_value="0")
-        sut._traffic_runner(mock_traffic_profile)
+        sut._setup_mq_producer = mock.Mock(return_value='mq_producer')
+        sut._traffic_runner(mock_traffic_profile, mock.ANY)
 
     @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket')
     @mock.patch(SSH_HELPER)
     def test_listen_traffic(self, ssh, *args):
         mock_ssh(ssh)
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        prox_traffic_gen = ProxTrafficGen(NAME, vnfd)
+        prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id')
         self.assertIsNone(prox_traffic_gen.listen_traffic(mock.Mock()))
 
     @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket')
@@ -421,7 +415,7 @@ class TestProxTrafficGen(unittest.TestCase):
     def test_terminate(self, ssh, *args):
         mock_ssh(ssh)
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        prox_traffic_gen = ProxTrafficGen(NAME, vnfd)
+        prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id')
         prox_traffic_gen._terminated = mock.MagicMock()
         prox_traffic_gen._traffic_process = mock.MagicMock()
         prox_traffic_gen._traffic_process.terminate = mock.Mock()
index 42ac40b..ddb6324 100644 (file)
@@ -18,10 +18,11 @@ import mock
 import six
 import unittest
 
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base as ctx_base
 from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api
 from yardstick.network_services.traffic_profile import base as tp_base
 from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_ixia
-from yardstick.benchmark.contexts import base as ctx_base
 
 
 TEST_FILE_YAML = 'nsb_test_case.yaml'
@@ -162,7 +163,8 @@ class TestIXIATrafficGen(unittest.TestCase):
                               'nodes': {'tg__1': 'trafficgen_1.yardstick',
                                         'vnf__1': 'vnf.yardstick'},
                               'topology': 'vpe_vnf_topology.yaml'}],
-               'context': {'nfvi_type': 'baremetal', 'type': 'Node',
+               'context': {'nfvi_type': 'baremetal',
+                           'type': contexts.CONTEXT_NODE,
                            'name': 'yardstick',
                            'file': '/etc/yardstick/nodes/pod.yaml'},
                'schema': 'yardstick:task:0.1'}
@@ -175,7 +177,7 @@ class TestIXIATrafficGen(unittest.TestCase):
             ssh.from_node.return_value = ssh_mock
             vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
             # NOTE(ralonsoh): check the object returned.
-            tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd)
+            tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd, 'task_id')
 
     def test_listen_traffic(self, *args):
         with mock.patch("yardstick.ssh.SSH") as ssh:
@@ -184,7 +186,8 @@ class TestIXIATrafficGen(unittest.TestCase):
                 mock.Mock(return_value=(0, "", ""))
             ssh.from_node.return_value = ssh_mock
             vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd)
+            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
+                                                               'task_id')
             self.assertIsNone(ixnet_traffic_gen.listen_traffic({}))
 
     @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
@@ -197,7 +200,8 @@ class TestIXIATrafficGen(unittest.TestCase):
                 mock.Mock(return_value=(0, "", ""))
             ssh.from_node.return_value = ssh_mock
             vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd)
+            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
+                                                               'task_id')
             scenario_cfg = {'tc': "nsb_test_case", "topology": "",
                             'ixia_profile': "ixload.cfg"}
             scenario_cfg.update(
@@ -234,7 +238,8 @@ class TestIXIATrafficGen(unittest.TestCase):
             ssh.from_node.return_value = ssh_mock
 
             vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd)
+            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
+                                                               'task_id')
             ixnet_traffic_gen.scenario_helper.scenario_cfg = {
                 'nodes': {ixnet_traffic_gen.name: "mock"}
             }
@@ -253,7 +258,8 @@ class TestIXIATrafficGen(unittest.TestCase):
             ssh_mock.execute = \
                 mock.Mock(return_value=(0, "", ""))
             ssh.from_node.return_value = ssh_mock
-            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd)
+            ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
+                                                               'task_id')
             ixnet_traffic_gen._terminated = mock.MagicMock()
             ixnet_traffic_gen._terminated.value = 0
             ixnet_traffic_gen._ixia_traffic_gen = mock.MagicMock()
@@ -269,7 +275,7 @@ class TestIXIATrafficGen(unittest.TestCase):
 
     def test__check_status(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        sut = tg_rfc2544_ixia.IxiaTrafficGen('vnf1', vnfd)
+        sut = tg_rfc2544_ixia.IxiaTrafficGen('vnf1', vnfd, 'task_id')
         sut._check_status()
 
     @mock.patch("yardstick.ssh.SSH")
@@ -335,7 +341,7 @@ class TestIXIATrafficGen(unittest.TestCase):
         mock_traffic_profile.get_drop_percentage.return_value = [
             'Completed', samples]
 
-        sut = tg_rfc2544_ixia.IxiaTrafficGen(name, vnfd)
+        sut = tg_rfc2544_ixia.IxiaTrafficGen(name, vnfd, 'task_id')
         sut.vnf_port_pairs = [[[0], [1]]]
         sut.tc_file_name = self._get_file_abspath(TEST_FILE_YAML)
         sut.topology = ""
@@ -379,7 +385,8 @@ class TestIXIATrafficGen(unittest.TestCase):
                     mock.mock_open(), create=True)
         @mock.patch('yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.LOG.exception')
         def _traffic_runner(*args):
-            result = sut._traffic_runner(mock_traffic_profile)
+            sut._setup_mq_producer = mock.Mock(return_value='mq_producer')
+            result = sut._traffic_runner(mock_traffic_profile, mock.ANY)
             self.assertIsNone(result)
 
         _traffic_runner()
index 4d3e4ff..6aba410 100644 (file)
 import mock
 import unittest
 
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base as ctx_base
 from yardstick.network_services.traffic_profile import base as tp_base
 from yardstick.network_services.vnf_generic.vnf import sample_vnf
 from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_trex
-from yardstick.benchmark.contexts import base as ctx_base
 
 
 class TestTrexRfcResouceHelper(unittest.TestCase):
@@ -206,7 +207,7 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
         ],
         'context': {
             'nfvi_type': 'baremetal',
-            'type': 'Node',
+            'type': contexts.CONTEXT_NODE,
             'name': 'yardstick',
             'file': '/etc/yardstick/nodes/pod.yaml',
         },
@@ -222,12 +223,14 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
         self._mock_ssh_helper.stop()
 
     def test___init__(self):
-        trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_0)
+        trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC(
+            'vnf1', self.VNFD_0, 'task_id')
         self.assertIsNotNone(trex_traffic_gen.resource_helper._terminated.value)
 
     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
     def test_collect_kpi(self, *args):
-        trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_0)
+        trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC(
+            'vnf1', self.VNFD_0, 'task_id')
         trex_traffic_gen.scenario_helper.scenario_cfg = {
             'nodes': {trex_traffic_gen.name: "mock"}
         }
@@ -243,7 +246,8 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
         mock_traffic_profile.get_traffic_definition.return_value = "64"
         mock_traffic_profile.params = self.TRAFFIC_PROFILE
 
-        trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_0)
+        trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC(
+            'vnf1', self.VNFD_0, 'task_id')
         trex_traffic_gen._start_server = mock.Mock(return_value=0)
         trex_traffic_gen.resource_helper = mock.MagicMock()
         trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
@@ -278,7 +282,8 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
         mock_traffic_profile.get_traffic_definition.return_value = "64"
         mock_traffic_profile.params = self.TRAFFIC_PROFILE
 
-        trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_0)
+        trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC(
+            'vnf1', self.VNFD_0, 'task_id')
         trex_traffic_gen.resource_helper = mock.MagicMock()
         trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
         scenario_cfg = {
index 350ba84..9ed2abb 100644 (file)
@@ -300,14 +300,14 @@ class TestTrexTrafficGen(unittest.TestCase):
 
     def test___init__(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         self.assertIsInstance(trex_traffic_gen.resource_helper,
                               tg_trex.TrexResourceHelper)
 
     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
     def test_collect_kpi(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         trex_traffic_gen.scenario_helper.scenario_cfg = {
             'nodes': {trex_traffic_gen.name: "mock"}
         }
@@ -321,13 +321,13 @@ class TestTrexTrafficGen(unittest.TestCase):
 
     def test_listen_traffic(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         self.assertIsNone(trex_traffic_gen.listen_traffic({}))
 
     @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
     def test_instantiate(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         trex_traffic_gen._start_server = mock.Mock(return_value=0)
         trex_traffic_gen._tg_process = mock.MagicMock()
         trex_traffic_gen._tg_process.start = mock.Mock()
@@ -342,7 +342,7 @@ class TestTrexTrafficGen(unittest.TestCase):
     @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
     def test_instantiate_error(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         trex_traffic_gen._start_server = mock.Mock(return_value=0)
         trex_traffic_gen._tg_process = mock.MagicMock()
         trex_traffic_gen._tg_process.start = mock.Mock()
@@ -355,7 +355,7 @@ class TestTrexTrafficGen(unittest.TestCase):
 
     def test__start_server(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         trex_traffic_gen.ssh_helper = mock.MagicMock()
         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
         trex_traffic_gen.scenario_helper.scenario_cfg = {}
@@ -363,7 +363,7 @@ class TestTrexTrafficGen(unittest.TestCase):
 
     def test__start_server_multiple_queues(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         trex_traffic_gen.ssh_helper = mock.MagicMock()
         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
         trex_traffic_gen.scenario_helper.scenario_cfg = {
@@ -377,7 +377,7 @@ class TestTrexTrafficGen(unittest.TestCase):
         mock_traffic_profile.params = self.TRAFFIC_PROFILE
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        self.sut = tg_trex.TrexTrafficGen(NAME, vnfd)
+        self.sut = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         self.sut.ssh_helper = mock.Mock()
         self.sut.ssh_helper.run = mock.Mock()
         self.sut._connect_client = mock.Mock()
@@ -387,12 +387,13 @@ class TestTrexTrafficGen(unittest.TestCase):
         # must generate cfg before we can run traffic so Trex port mapping is
         # created
         self.sut.resource_helper.generate_cfg()
+        self.sut._setup_mq_producer = mock.Mock()
         with mock.patch.object(self.sut.resource_helper, 'run_traffic'):
-            self.sut._traffic_runner(mock_traffic_profile)
+            self.sut._traffic_runner(mock_traffic_profile, mock.ANY)
 
     def test__generate_trex_cfg(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
         self.assertIsNone(trex_traffic_gen.resource_helper.generate_cfg())
 
@@ -431,7 +432,7 @@ class TestTrexTrafficGen(unittest.TestCase):
               'local_mac': '00:00:00:00:00:01'},
              'vnfd-connection-point-ref': 'xe1',
              'name': 'xe1'}]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
         trex_traffic_gen.resource_helper.generate_cfg()
         trex_traffic_gen.resource_helper._build_ports()
@@ -448,25 +449,24 @@ class TestTrexTrafficGen(unittest.TestCase):
         mock_traffic_profile.params = self.TRAFFIC_PROFILE
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        self.sut = tg_trex.TrexTrafficGen(NAME, vnfd)
+        self.sut = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         self.sut.ssh_helper = mock.Mock()
         self.sut.ssh_helper.run = mock.Mock()
         self.sut._traffic_runner = mock.Mock(return_value=0)
         self.sut.resource_helper.client_started.value = 1
-        result = self.sut.run_traffic(mock_traffic_profile)
+        self.sut.run_traffic(mock_traffic_profile)
         self.sut._traffic_process.terminate()
-        self.assertIsNotNone(result)
 
     def test_terminate(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         trex_traffic_gen.ssh_helper = mock.MagicMock()
         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
         self.assertIsNone(trex_traffic_gen.terminate())
 
     def test__connect_client(self):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+        trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
         client = mock.Mock()
         client.connect = mock.Mock(return_value=0)
         self.assertIsNotNone(trex_traffic_gen.resource_helper._connect(client))
index 1c4ced3..56c971d 100644 (file)
 # 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.
-#
 
 import unittest
 import mock
 import os
 
-from yardstick.tests import STL_MOCKS
 from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
 from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.udp_replay import UdpReplayApproxVnf
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper
 
 
 SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
 
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
-
-if stl_patch:
-    from yardstick.network_services.vnf_generic.vnf.udp_replay import UdpReplayApproxVnf
-    from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper
-
-
 TEST_FILE_YAML = 'nsb_test_case.yaml'
 
-
 NAME = "vnf__1"
 
 
@@ -327,7 +317,8 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
     }
 
     def test___init__(self, *args):
-        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+                                                   'task_id')
         self.assertIsNone(udp_replay_approx_vnf._vnf_process)
 
     @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
@@ -342,7 +333,7 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
             "Port\t\tRx Packet\t\tTx Packet\t\tRx Pkt Drop\t\tTx Pkt Drop \r\n"\
             "0\t\t7374156\t\t7374136\t\t\t0\t\t\t0\r\n" \
             "1\t\t7374316\t\t7374315\t\t\t0\t\t\t0\r\n\r\nReplay>\r\r\nReplay>"
-        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, vnfd)
+        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, vnfd, 'task_id')
         udp_replay_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {udp_replay_approx_vnf.name: "mock"}
         }
@@ -364,7 +355,8 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
     def test_get_stats(self, ssh, *args):
         mock_ssh(ssh)
 
-        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+                                                   'task_id')
         udp_replay_approx_vnf.q_in = mock.MagicMock()
         udp_replay_approx_vnf.q_out = mock.MagicMock()
         udp_replay_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
@@ -390,7 +382,8 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
         nfvi_context.attrs = {'nfvi_type': 'baremetal'}
         mock_get_ctx.return_value = nfvi_context
 
-        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+                                                   'task_id')
         udp_replay_approx_vnf.queue_wrapper = mock.MagicMock()
         udp_replay_approx_vnf.nfvi_context = mock_get_ctx
         udp_replay_approx_vnf.nfvi_context.attrs = {'nfvi_type': 'baremetal'}
@@ -415,7 +408,8 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
         nfvi_context.attrs = {'nfvi_type': "baremetal"}
         mock_get_ctx.return_value = nfvi_context
 
-        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+                                                   'task_id')
         udp_replay_approx_vnf.setup_helper.bound_pci = ['0000:00:0.1', '0000:00:0.3']
         udp_replay_approx_vnf.all_ports = ["xe0", "xe1"]
         udp_replay_approx_vnf.ssh_helper.provision_tool = mock.MagicMock(return_value="tool_path")
@@ -437,7 +431,8 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
     def test_run_udp_replay(self, ssh, *args):
         mock_ssh(ssh)
 
-        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+                                                   'task_id')
         udp_replay_approx_vnf._build_config = mock.MagicMock()
         udp_replay_approx_vnf.queue_wrapper = mock.MagicMock()
         udp_replay_approx_vnf.scenario_helper = mock.MagicMock()
@@ -451,7 +446,8 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
     def test_instantiate(self, ssh, *args):
         mock_ssh(ssh)
 
-        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+                                                   'task_id')
         udp_replay_approx_vnf.q_out.put("Replay>")
         udp_replay_approx_vnf.WAIT_TIME = 0
         udp_replay_approx_vnf.setup_helper.setup_vnf_environment = mock.Mock()
@@ -469,7 +465,8 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
     @mock.patch('yardstick.ssh.SSH')
     @mock.patch(SSH_HELPER)
     def test_instantiate_panic(self, *args):
-        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+        udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+                                                   'task_id')
         udp_replay_approx_vnf.WAIT_TIME = 0
         udp_replay_approx_vnf.q_out.put("some text PANIC some text")
         udp_replay_approx_vnf.setup_helper.setup_vnf_environment = mock.Mock()
index b67a3cd..efbb7a8 100644 (file)
 # 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.
-#
 
 import unittest
 import mock
 import os
 
-from yardstick.tests import STL_MOCKS
-from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
-
 from yardstick.common import utils
 from yardstick.benchmark.contexts import base as ctx_base
-
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
-
-if stl_patch:
-    from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxVnf
-    from yardstick.network_services.nfvi.resource import ResourceProfile
-    from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxSetupEnvHelper
+from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxVnf
+from yardstick.network_services.nfvi.resource import ResourceProfile
+from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxSetupEnvHelper
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
 
 
 TEST_FILE_YAML = 'nsb_test_case.yaml'
@@ -241,7 +232,7 @@ class TestFWApproxVnf(unittest.TestCase):
 
     def test___init__(self, *args):
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        vfw_approx_vnf = FWApproxVnf(name, vnfd)
+        vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
         self.assertIsNone(vfw_approx_vnf._vnf_process)
 
     STATS = """\
@@ -264,7 +255,7 @@ pipeline>
     def test_collect_kpi(self, ssh, *args):
         mock_ssh(ssh)
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        vfw_approx_vnf = FWApproxVnf(name, vnfd)
+        vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
         vfw_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {vfw_approx_vnf.name: "mock"}
         }
@@ -290,7 +281,7 @@ pipeline>
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        vfw_approx_vnf = FWApproxVnf(name, vnfd)
+        vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
         vfw_approx_vnf.q_in = mock.MagicMock()
         vfw_approx_vnf.q_out = mock.MagicMock()
         vfw_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
@@ -302,7 +293,7 @@ pipeline>
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        vfw_approx_vnf = FWApproxVnf(name, vnfd)
+        vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
         vfw_approx_vnf.q_in = mock.MagicMock()
         vfw_approx_vnf.q_out = mock.MagicMock()
         vfw_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
@@ -322,7 +313,7 @@ pipeline>
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        vfw_approx_vnf = FWApproxVnf(name, vnfd)
+        vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
         vfw_approx_vnf._build_config = mock.MagicMock()
         vfw_approx_vnf.queue_wrapper = mock.MagicMock()
         vfw_approx_vnf.ssh_helper = mock.MagicMock()
@@ -344,7 +335,7 @@ pipeline>
         mock_ssh(ssh)
 
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
-        vfw_approx_vnf = FWApproxVnf(name, vnfd)
+        vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
         vfw_approx_vnf.ssh_helper = ssh
         vfw_approx_vnf.deploy_helper = mock.MagicMock()
         vfw_approx_vnf.resource_helper = mock.MagicMock()
index c1664f2..7b937df 100644 (file)
@@ -549,7 +549,7 @@ class TestVpeApproxVnf(unittest.TestCase):
         self._mock_time_sleep.stop()
 
     def test___init__(self):
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         self.assertIsNone(vpe_approx_vnf._vnf_process)
 
     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
@@ -563,7 +563,7 @@ class TestVpeApproxVnf(unittest.TestCase):
         resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234}
         resource.check_if_system_agent_running.return_value = (1, None)
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {vpe_approx_vnf.name: "mock"}
         }
@@ -592,7 +592,7 @@ class TestVpeApproxVnf(unittest.TestCase):
         resource.check_if_system_agent_running.return_value = 0, '1234'
         resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234}
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf.scenario_helper.scenario_cfg = {
             'nodes': {vpe_approx_vnf.name: "mock"}
         }
@@ -614,7 +614,7 @@ class TestVpeApproxVnf(unittest.TestCase):
     @mock.patch.object(sample_vnf, 'VnfSshHelper')
     def test_vnf_execute(self, ssh):
         test_base.mock_ssh(ssh)
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf.q_in = mock.MagicMock()
         vpe_approx_vnf.q_out = mock.MagicMock()
         vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
@@ -624,7 +624,7 @@ class TestVpeApproxVnf(unittest.TestCase):
     def test_run_vpe(self, ssh):
         test_base.mock_ssh(ssh)
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf.tc_file_name = get_file_abspath(TEST_FILE_YAML)
         vpe_approx_vnf.vnf_cfg = {
             'lb_config': 'SW',
@@ -707,7 +707,7 @@ class TestVpeApproxVnf(unittest.TestCase):
 
         mock_resource = mock.MagicMock()
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf._vnf_process = mock_process
         vpe_approx_vnf.q_out = mock_q_out
         vpe_approx_vnf.queue_wrapper = mock.Mock(
@@ -732,7 +732,7 @@ class TestVpeApproxVnf(unittest.TestCase):
 
         mock_resource = mock.MagicMock()
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf._vnf_process = mock_process
         vpe_approx_vnf.q_out = mock_q_out
         vpe_approx_vnf.queue_wrapper = mock.Mock(
@@ -751,7 +751,7 @@ class TestVpeApproxVnf(unittest.TestCase):
 
         mock_resource = mock.MagicMock()
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf._vnf_process = mock_process
         vpe_approx_vnf.resource_helper.resource = mock_resource
 
@@ -770,7 +770,7 @@ class TestVpeApproxVnf(unittest.TestCase):
 
         mock_resource = mock.MagicMock()
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf._vnf_process = mock_process
         vpe_approx_vnf.resource_helper.resource = mock_resource
 
@@ -795,7 +795,7 @@ class TestVpeApproxVnf(unittest.TestCase):
 
         mock_resource = mock.MagicMock()
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf._vnf_process = mock_process
         vpe_approx_vnf.q_out = mock_q_out
         vpe_approx_vnf.resource_helper.resource = mock_resource
@@ -809,7 +809,7 @@ class TestVpeApproxVnf(unittest.TestCase):
     def test_terminate(self, ssh):
         test_base.mock_ssh(ssh)
 
-        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0)
+        vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
         vpe_approx_vnf._vnf_process = mock.MagicMock()
         vpe_approx_vnf._resource_collect_stop = mock.Mock()
         vpe_approx_vnf.resource_helper = mock.MagicMock()
index 4323c02..a73a4a1 100644 (file)
@@ -66,7 +66,11 @@ service ssh restart;while true ; do sleep 10000; done"
                         ],
                         "nodeSelector": {
                             "kubernetes.io/hostname": "node-01"
-                        }
+                        },
+                        "restartPolicy": "Always",
+                        "tolerations": [
+                            {"operator": "Exists"}
+                        ]
                     }
                 }
             }
@@ -77,12 +81,21 @@ service ssh restart;while true ; do sleep 10000; done"
 service ssh restart;while true ; do sleep 10000; done'],
             'ssh_key': 'k8s-86096c30-key',
             'nodeSelector': {'kubernetes.io/hostname': 'node-01'},
-            'volumes': []
+            'volumes': [],
+            'restartPolicy': 'Always'
         }
         name = 'host-k8s-86096c30'
-        output_r = kubernetes.KubernetesObject(name, **input_s).get_template()
+        output_r = kubernetes.ReplicationControllerObject(
+            name, **input_s).get_template()
         self.assertEqual(output_r, output_t)
 
+    def test_get_template_invalid_restart_policy(self):
+        input_s = {'restartPolicy': 'invalid_option'}
+        name = 'host-k8s-86096c30'
+        with self.assertRaises(exceptions.KubernetesWrongRestartPolicy):
+            kubernetes.ReplicationControllerObject(
+                name, **input_s).get_template()
+
 
 class GetRcPodsTestCase(base.BaseUnitTestCase):
 
@@ -108,14 +121,14 @@ service ssh restart;while true ; do sleep 10000; done']
         self.assertEqual(pods, [])
 
 
-class KubernetesObjectTestCase(base.BaseUnitTestCase):
+class ReplicationControllerObjectTestCase(base.BaseUnitTestCase):
 
     def test__init_one_container(self):
         pod_name = 'pod_name'
         _kwargs = {'args': ['arg1', 'arg2'],
                    'image': 'fake_image',
                    'command': 'fake_command'}
-        k8s_obj = kubernetes.KubernetesObject(pod_name, **_kwargs)
+        k8s_obj = kubernetes.ReplicationControllerObject(pod_name, **_kwargs)
         self.assertEqual(1, len(k8s_obj._containers))
         container = k8s_obj._containers[0]
         self.assertEqual(['arg1', 'arg2'], container._args)
@@ -131,7 +144,7 @@ class KubernetesObjectTestCase(base.BaseUnitTestCase):
                                'image': 'fake_image_%s' % i,
                                'command': 'fake_command_%s' % i})
         _kwargs = {'containers': containers}
-        k8s_obj = kubernetes.KubernetesObject(pod_name, **_kwargs)
+        k8s_obj = kubernetes.ReplicationControllerObject(pod_name, **_kwargs)
         self.assertEqual(5, len(k8s_obj._containers))
         for i in range(5):
             container = k8s_obj._containers[i]
@@ -145,8 +158,8 @@ class KubernetesObjectTestCase(base.BaseUnitTestCase):
                    'configMap': {'name': 'fake_sshkey'}}
         volume2 = {'name': 'volume2',
                    'configMap': 'data'}
-        k8s_obj = kubernetes.KubernetesObject('name', ssh_key='fake_sshkey',
-                                              volumes=[volume2])
+        k8s_obj = kubernetes.ReplicationControllerObject(
+            'name', ssh_key='fake_sshkey', volumes=[volume2])
         k8s_obj._add_volumes()
         volumes = k8s_obj.template['spec']['template']['spec']['volumes']
         self.assertEqual(sorted([volume1, volume2], key=lambda k: k['name']),
@@ -155,7 +168,8 @@ class KubernetesObjectTestCase(base.BaseUnitTestCase):
     def test__add_volumes_no_volumes(self):
         volume1 = {'name': 'fake_sshkey',
                    'configMap': {'name': 'fake_sshkey'}}
-        k8s_obj = kubernetes.KubernetesObject('name', ssh_key='fake_sshkey')
+        k8s_obj = kubernetes.ReplicationControllerObject(
+            'name', ssh_key='fake_sshkey')
         k8s_obj._add_volumes()
         volumes = k8s_obj.template['spec']['template']['spec']['volumes']
         self.assertEqual([volume1], volumes)
@@ -163,7 +177,8 @@ class KubernetesObjectTestCase(base.BaseUnitTestCase):
     def test__create_ssh_key_volume(self):
         expected = {'name': 'fake_sshkey',
                     'configMap': {'name': 'fake_sshkey'}}
-        k8s_obj = kubernetes.KubernetesObject('name', ssh_key='fake_sshkey')
+        k8s_obj = kubernetes.ReplicationControllerObject(
+            'name', ssh_key='fake_sshkey')
         self.assertEqual(expected, k8s_obj._create_ssh_key_volume())
 
     def test__create_volume_item(self):
@@ -172,13 +187,76 @@ class KubernetesObjectTestCase(base.BaseUnitTestCase):
                       vol_type: 'data'}
             self.assertEqual(
                 volume,
-                kubernetes.KubernetesObject._create_volume_item(volume))
+                kubernetes.ReplicationControllerObject.
+                    _create_volume_item(volume))
 
     def test__create_volume_item_invalid_type(self):
         volume = {'name': 'vol_name',
                   'invalid_type': 'data'}
         with self.assertRaises(exceptions.KubernetesTemplateInvalidVolumeType):
-            kubernetes.KubernetesObject._create_volume_item(volume)
+            kubernetes.ReplicationControllerObject._create_volume_item(volume)
+
+    def test__add_security_context(self):
+        k8s_obj = kubernetes.ReplicationControllerObject('pod_name')
+        self.assertNotIn('securityContext',
+                         k8s_obj.template['spec']['template']['spec'])
+
+        k8s_obj._security_context = {'key_pod': 'value_pod'}
+        k8s_obj._add_security_context()
+        self.assertEqual(
+            {'key_pod': 'value_pod'},
+            k8s_obj.template['spec']['template']['spec']['securityContext'])
+
+    def test__add_security_context_by_init(self):
+        containers = []
+        for i in range(5):
+            containers.append(
+                {'securityContext': {'key%s' % i: 'value%s' % i}})
+        _kwargs = {'containers': containers,
+                   'securityContext': {'key_pod': 'value_pod'}}
+        k8s_obj = kubernetes.ReplicationControllerObject('pod_name', **_kwargs)
+        self.assertEqual(
+            {'key_pod': 'value_pod'},
+            k8s_obj.template['spec']['template']['spec']['securityContext'])
+        for i in range(5):
+            container = (
+                k8s_obj.template['spec']['template']['spec']['containers'][i])
+            self.assertEqual({'key%s' % i: 'value%s' % i},
+                             container['securityContext'])
+
+    def test__add_networks(self):
+        k8s_obj = kubernetes.ReplicationControllerObject(
+            'name', networks=['network1', 'network2', 'network3'])
+        k8s_obj._add_networks()
+        networks = k8s_obj.\
+            template['spec']['template']['metadata']['annotations']['networks']
+        expected = ('[{"name": "network1"}, {"name": "network2"}, '
+                    '{"name": "network3"}]')
+        self.assertEqual(expected, networks)
+
+    def test__add_tolerations(self):
+        _kwargs = {'tolerations': [{'key': 'key1',
+                                    'value': 'value2',
+                                    'effect': 'effect3',
+                                    'operator': 'operator4',
+                                    'wrong_key': 'error_key'}]
+                   }
+        k8s_obj = kubernetes.ReplicationControllerObject('pod_name', **_kwargs)
+        k8s_obj._add_tolerations()
+        _tol = k8s_obj.template['spec']['template']['spec']['tolerations']
+        self.assertEqual(1, len(_tol))
+        self.assertEqual({'key': 'key1',
+                          'value': 'value2',
+                          'effect': 'effect3',
+                          'operator': 'operator4'},
+                         _tol[0])
+
+    def test__add_tolerations_default(self):
+        k8s_obj = kubernetes.ReplicationControllerObject('pod_name')
+        k8s_obj._add_tolerations()
+        _tol = k8s_obj.template['spec']['template']['spec']['tolerations']
+        self.assertEqual(1, len(_tol))
+        self.assertEqual({'operator': 'Exists'}, _tol[0])
 
 
 class ContainerObjectTestCase(base.BaseUnitTestCase):
@@ -222,8 +300,342 @@ class ContainerObjectTestCase(base.BaseUnitTestCase):
             'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
             args=args)
         expected = {'args': args,
-                    'command': [kubernetes.ContainerObject.COMMAND_DEFAULT],
+                    'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
                     'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
                     'name': 'cname-container',
                     'volumeMounts': container_obj._create_volume_mounts()}
         self.assertEqual(expected, container_obj.get_container_item())
+
+    def test_get_container_item_with_security_context(self):
+        volume_mount = {'name': 'fake_name',
+                        'mountPath': 'fake_path'}
+        args = ['arg1', 'arg2']
+        container_obj = kubernetes.ContainerObject(
+            'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
+            args=args, securityContext={'key': 'value'})
+        expected = {'args': args,
+                    'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
+                    'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
+                    'name': 'cname-container',
+                    'volumeMounts': container_obj._create_volume_mounts(),
+                    'securityContext': {'key': 'value'}}
+        self.assertEqual(expected, container_obj.get_container_item())
+
+    def test_get_container_item_with_env(self):
+        volume_mount = {'name': 'fake_name',
+                        'mountPath': 'fake_path'}
+        args = ['arg1', 'arg2']
+        container_obj = kubernetes.ContainerObject(
+            'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
+            args=args, env=[{'name': 'fake_var_name',
+                             'value': 'fake_var_value'}])
+        expected = {'args': args,
+                    'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
+                    'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
+                    'name': 'cname-container',
+                    'volumeMounts': container_obj._create_volume_mounts(),
+                    'env': [{'name': 'fake_var_name',
+                             'value': 'fake_var_value'}]}
+        self.assertEqual(expected, container_obj.get_container_item())
+
+    def test_get_container_item_with_ports_multi_parameter(self):
+        volume_mount = {'name': 'fake_name',
+                        'mountPath': 'fake_path'}
+        args = ['arg1', 'arg2']
+        container_obj = kubernetes.ContainerObject(
+            'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
+            args=args, ports=[{'containerPort': 'fake_port_name',
+                               'hostPort': 'fake_host_port',
+                               'name': 'fake_name',
+                               'protocol': 'fake_protocol',
+                               'invalid_varible': 'fakeinvalid_varible',
+                               'hostIP': 'fake_port_number'}])
+        expected = {'args': args,
+                    'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
+                    'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
+                    'name': 'cname-container',
+                    'volumeMounts': container_obj._create_volume_mounts(),
+                    'ports': [{'containerPort': 'fake_port_name',
+                               'hostPort': 'fake_host_port',
+                               'name': 'fake_name',
+                               'protocol': 'fake_protocol',
+                               'hostIP': 'fake_port_number'}]}
+        self.assertEqual(expected, container_obj.get_container_item())
+
+    def test_get_container_item_with_ports_no_container_port(self):
+        with self.assertRaises(exceptions.KubernetesContainerPortNotDefined):
+            volume_mount = {'name': 'fake_name',
+                            'mountPath': 'fake_path'}
+            args = ['arg1', 'arg2']
+            container_obj = kubernetes.ContainerObject(
+                    'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
+                    args=args, ports=[{'hostPort': 'fake_host_port',
+                                       'name': 'fake_name',
+                                       'protocol': 'fake_protocol',
+                                       'hostIP': 'fake_port_number'}])
+            container_obj.get_container_item()
+
+    def test_get_container_item_with_resources(self):
+        volume_mount = {'name': 'fake_name',
+                        'mountPath': 'fake_path'}
+        args = ['arg1', 'arg2']
+        resources = {'requests': {'key1': 'val1'},
+                     'limits': {'key2': 'val2'},
+                     'other_key': {'key3': 'val3'}}
+        container_obj = kubernetes.ContainerObject(
+            'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
+            args=args, resources=resources)
+        expected = {'args': args,
+                    'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
+                    'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
+                    'name': 'cname-container',
+                    'volumeMounts': container_obj._create_volume_mounts(),
+                    'resources': {'requests': {'key1': 'val1'},
+                                  'limits': {'key2': 'val2'}}}
+        self.assertEqual(expected, container_obj.get_container_item())
+
+    def test_get_container_item_image_pull_policy(self):
+        container_obj = kubernetes.ContainerObject(
+            'cname', ssh_key='fake_sshkey', imagePullPolicy='Always')
+        expected = {'args': [],
+                    'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
+                    'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
+                    'name': 'cname-container',
+                    'volumeMounts': container_obj._create_volume_mounts(),
+                    'imagePullPolicy':'Always'}
+        self.assertEqual(expected, container_obj.get_container_item())
+
+    def test_get_container_item_with_tty_stdin(self):
+        args = ['arg1', 'arg2']
+        container_obj = kubernetes.ContainerObject(
+            'cname', 'fake_sshkey', args=args, tty=False, stdin=True)
+        expected = {'args': args,
+                    'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
+                    'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
+                    'name': 'cname-container',
+                    'volumeMounts': container_obj._create_volume_mounts(),
+                    'tty': False,
+                    'stdin': True}
+        self.assertEqual(expected, container_obj.get_container_item())
+
+    def test__parse_commands_string(self):
+        container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey')
+        self.assertEqual(['fake command'],
+                         container_obj._parse_commands('fake command'))
+
+    def test__parse_commands_list(self):
+        container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey')
+        self.assertEqual(['cmd1', 'cmd2'],
+                         container_obj._parse_commands(['cmd1', 'cmd2']))
+
+    def test__parse_commands_exception(self):
+        container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey')
+        with self.assertRaises(exceptions.KubernetesContainerCommandType):
+            container_obj._parse_commands({})
+
+
+class CustomResourceDefinitionObjectTestCase(base.BaseUnitTestCase):
+
+    def test__init(self):
+        template = {
+            'metadata': {
+                'name': 'newcrds.ctx_name.com'
+            },
+            'spec': {
+                'group': 'ctx_name.com',
+                'version': 'v2',
+                'scope': 'scope',
+                'names': {'plural': 'newcrds',
+                          'singular': 'newcrd',
+                          'kind': 'Newcrd'}
+            }
+        }
+        crd_obj = kubernetes.CustomResourceDefinitionObject(
+            'ctx_name', name='newcrd', version='v2', scope='scope')
+        self.assertEqual('newcrds.ctx_name.com', crd_obj._name)
+        self.assertEqual(template, crd_obj._template)
+
+    def test__init_missing_parameter(self):
+        with self.assertRaises(exceptions.KubernetesCRDObjectDefinitionError):
+            kubernetes.CustomResourceDefinitionObject('ctx_name',
+                                                      noname='name')
+
+
+class NetworkObjectTestCase(base.BaseUnitTestCase):
+
+    def setUp(self):
+        self.net_obj = kubernetes.NetworkObject(name='fake_name',
+                                                plugin='fake_plugin',
+                                                args='fake_args')
+
+    def test__init_missing_parameter(self):
+        with self.assertRaises(
+                exceptions.KubernetesNetworkObjectDefinitionError):
+            kubernetes.NetworkObject('network_name', plugin='plugin')
+        with self.assertRaises(
+                exceptions.KubernetesNetworkObjectDefinitionError):
+            kubernetes.NetworkObject('network_name', args='args')
+
+    @mock.patch.object(kubernetes_utils, 'get_custom_resource_definition')
+    def test_crd(self, mock_get_crd):
+        mock_crd = mock.Mock()
+        mock_get_crd.return_value = mock_crd
+        net_obj = copy.deepcopy(self.net_obj)
+        self.assertEqual(mock_crd, net_obj.crd)
+
+    def test_template(self):
+        net_obj = copy.deepcopy(self.net_obj)
+        expected = {'apiVersion': 'group.com/v2',
+                    'kind': kubernetes.NetworkObject.KIND,
+                    'metadata': {
+                        'name': 'fake_name'},
+                    'plugin': 'fake_plugin',
+                    'args': 'fake_args'}
+        crd = mock.Mock()
+        crd.spec.group = 'group.com'
+        crd.spec.version = 'v2'
+        net_obj._crd = crd
+        self.assertEqual(expected, net_obj.template)
+
+    def test_group(self):
+        net_obj = copy.deepcopy(self.net_obj)
+        net_obj._crd = mock.Mock()
+        net_obj._crd.spec.group = 'fake_group'
+        self.assertEqual('fake_group', net_obj.group)
+
+    def test_version(self):
+        net_obj = copy.deepcopy(self.net_obj)
+        net_obj._crd = mock.Mock()
+        net_obj._crd.spec.version = 'version_4'
+        self.assertEqual('version_4', net_obj.version)
+
+    def test_plural(self):
+        net_obj = copy.deepcopy(self.net_obj)
+        net_obj._crd = mock.Mock()
+        net_obj._crd.spec.names.plural = 'name_ending_in_s'
+        self.assertEqual('name_ending_in_s', net_obj.plural)
+
+    def test_scope(self):
+        net_obj = copy.deepcopy(self.net_obj)
+        net_obj._crd = mock.Mock()
+        net_obj._crd.spec.scope = 'Cluster'
+        self.assertEqual('Cluster', net_obj.scope)
+
+    @mock.patch.object(kubernetes_utils, 'create_network')
+    def test_create(self, mock_create_network):
+        net_obj = copy.deepcopy(self.net_obj)
+        net_obj._scope = 'scope'
+        net_obj._group = 'group'
+        net_obj._version = 'version'
+        net_obj._plural = 'plural'
+        net_obj._template = 'template'
+        net_obj.create()
+        mock_create_network.assert_called_once_with(
+            'scope', 'group', 'version', 'plural', 'template')
+
+    @mock.patch.object(kubernetes_utils, 'delete_network')
+    def test_delete(self, mock_delete_network):
+        net_obj = copy.deepcopy(self.net_obj)
+        net_obj._scope = 'scope'
+        net_obj._group = 'group'
+        net_obj._version = 'version'
+        net_obj._plural = 'plural'
+        net_obj._name = 'name'
+        net_obj.delete()
+        mock_delete_network.assert_called_once_with(
+            'scope', 'group', 'version', 'plural', 'name')
+
+
+class ServiceNodePortObjectTestCase(base.BaseUnitTestCase):
+
+    def test__init(self):
+        with mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port') \
+                as mock_add_port:
+            kubernetes.ServiceNodePortObject(
+                'fake_name', node_ports=[{'port': 80, 'name': 'web'}])
+
+        mock_add_port.assert_has_calls([mock.call(22, 'ssh', protocol='TCP'),
+                                        mock.call(80, 'web')])
+
+    @mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port')
+    def test__init_missing_mandatory_parameters(self, *args):
+        with self.assertRaises(
+                exceptions.KubernetesServiceObjectDefinitionError):
+            kubernetes.ServiceNodePortObject(
+                'fake_name', node_ports=[{'port': 80}])
+        with self.assertRaises(
+                exceptions.KubernetesServiceObjectDefinitionError):
+            kubernetes.ServiceNodePortObject(
+                'fake_name', node_ports=[{'name': 'web'}])
+
+    @mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port')
+    def test__init_missing_bad_name(self, *args):
+        with self.assertRaises(
+                exceptions.KubernetesServiceObjectNameError):
+            kubernetes.ServiceNodePortObject(
+                'fake_name', node_ports=[{'port': 80, 'name': '-web'}])
+        with self.assertRaises(
+                exceptions.KubernetesServiceObjectNameError):
+            kubernetes.ServiceNodePortObject(
+                'fake_name', node_ports=[{'port': 80, 'name': 'Web'}])
+        with self.assertRaises(
+                exceptions.KubernetesServiceObjectNameError):
+            kubernetes.ServiceNodePortObject(
+                'fake_name', node_ports=[{'port': 80, 'name': 'web-'}])
+
+    def test__add_port(self):
+        nodeport_object = kubernetes.ServiceNodePortObject('fake_name')
+        port_ssh = {'name': 'ssh',
+                    'port': 22,
+                    'protocol': 'TCP'}
+        port_definition = {'port': 80,
+                           'protocol': 'TCP',
+                           'name': 'web',
+                           'targetPort': 10080,
+                           'nodePort': 30080}
+        port = copy.deepcopy(port_definition)
+        _port = port.pop('port')
+        name = port.pop('name')
+        nodeport_object._add_port(_port, name, **port)
+        self.assertEqual([port_ssh, port_definition],
+                         nodeport_object.template['spec']['ports'])
+
+    @mock.patch.object(kubernetes_utils, 'create_service')
+    def test_create(self, mock_create_service):
+        nodeport_object = kubernetes.ServiceNodePortObject('fake_name')
+        nodeport_object.template = 'fake_template'
+        nodeport_object.create()
+        mock_create_service.assert_called_once_with('fake_template')
+
+    @mock.patch.object(kubernetes_utils, 'delete_service')
+    def test_delete(self, mock_delete_service):
+        nodeport_object = kubernetes.ServiceNodePortObject('fake_name')
+        nodeport_object.delete()
+        mock_delete_service.assert_called_once_with('fake_name-service')
+
+
+class KubernetesTemplate(base.BaseUnitTestCase):
+
+    def test_get_rc_by_name(self):
+        ctx_cfg = {
+            'servers': {
+                'host1': {'args': 'some data'}
+            }
+        }
+        k_template = kubernetes.KubernetesTemplate('k8s_name', ctx_cfg)
+        rc = k_template.get_rc_by_name('host1-k8s_name')
+        self.assertTrue(isinstance(rc, kubernetes.ReplicationControllerObject))
+
+    def test_get_rc_by_name_wrong_name(self):
+        ctx_cfg = {
+            'servers': {
+                'host1': {'args': 'some data'}
+            }
+        }
+        k_template = kubernetes.KubernetesTemplate('k8s_name', ctx_cfg)
+        self.assertIsNone(k_template.get_rc_by_name('wrong_host_name'))
+
+    def test_get_rc_by_name_no_rcs(self):
+        ctx_cfg = {'servers': {}}
+        k_template = kubernetes.KubernetesTemplate('k8s_name', ctx_cfg)
+        self.assertIsNone(k_template.get_rc_by_name('any_host_name'))