aboutsummaryrefslogtreecommitdiffstats
path: root/tools/docker/deployment
diff options
context:
space:
mode:
authorSridhar K. N. Rao <sridhar.rao@spirent.com>2019-10-02 17:50:23 +0530
committerSridhar K. N. Rao <sridhar.rao@spirent.com>2019-12-01 09:02:14 +0530
commit601b88e2c5dabaa7fe2035c7e433d2da5b860c4b (patch)
tree45d7336a3fc71907c19720127d154f8c44aa673a /tools/docker/deployment
parentb984a2f40bec349c802b631a69526590b34bd5de (diff)
Tools: Deployment and TestControl Containers
This patch add containerization of VSPERF support. The patch facilitates creation of 4 containers: 1. Interactive Deployment 2. Auto Deployment 3. Interactive TestControl 4. Auto TestControl. The patch also includes a minimal client to work with interactive containers. The docs folder provides detailed documentation. Fixed pylint errors in libs folder. Removed proto built python files, and added the build process in prepare.sh. Stability improvements for Auto versions of deployment and testcontrol. Enhance client with 'mode' feature, where client can run either to do only deploy/only test or both. Add sample configuration file for client Fixed few typos - as suggested by AL. JIRA: VSPERF-594 Signed-off-by: Sridhar K. N. Rao <sridhar.rao@spirent.com> Change-Id: Id40b02960f71a7f9183d9a53955e2483117fb9e2
Diffstat (limited to 'tools/docker/deployment')
-rw-r--r--tools/docker/deployment/auto/controller/Dockerfile23
-rw-r--r--tools/docker/deployment/auto/controller/list.env14
-rw-r--r--tools/docker/deployment/auto/controller/vsperf/__init__.py1
-rw-r--r--tools/docker/deployment/auto/controller/vsperf/collectd.conf49
-rw-r--r--tools/docker/deployment/auto/controller/vsperf/trex_cfg.yaml20
-rw-r--r--tools/docker/deployment/auto/controller/vsperf/vsperf_controller.py392
-rw-r--r--tools/docker/deployment/auto/docker-compose.yml22
-rw-r--r--tools/docker/deployment/interactive/controller/Dockerfile21
-rw-r--r--tools/docker/deployment/interactive/controller/vsperf/__init__.py1
-rw-r--r--tools/docker/deployment/interactive/controller/vsperf/vsperf_controller.py360
-rw-r--r--tools/docker/deployment/interactive/docker-compose.yml21
11 files changed, 924 insertions, 0 deletions
diff --git a/tools/docker/deployment/auto/controller/Dockerfile b/tools/docker/deployment/auto/controller/Dockerfile
new file mode 100644
index 00000000..e849d8f2
--- /dev/null
+++ b/tools/docker/deployment/auto/controller/Dockerfile
@@ -0,0 +1,23 @@
+FROM python:3.6
+LABEL maintainer="sridhar.rao@spirent.com"
+
+ENV GRPC_PYTHON_VERSION 1.4.0
+RUN apt-get update && apt-get -y install python3-pip && apt-get -y install openssh-server
+RUN pip3 install grpcio==${GRPC_PYTHON_VERSION} grpcio-tools==${GRPC_PYTHON_VERSION}
+RUN pip3 install paramiko
+RUN pip3 install chainmap
+RUN pip3 install oslo.utils
+RUN pip3 install scp
+
+WORKDIR /usr/src/app
+
+COPY ./vsperf ./vsperf
+
+VOLUME ["/usr/src/app/vsperf"]
+
+EXPOSE 50051
+
+CMD ["python3", "./vsperf/vsperf_controller.py"]
+
+#CMD tail -f /dev/null
+
diff --git a/tools/docker/deployment/auto/controller/list.env b/tools/docker/deployment/auto/controller/list.env
new file mode 100644
index 00000000..ab4404b7
--- /dev/null
+++ b/tools/docker/deployment/auto/controller/list.env
@@ -0,0 +1,14 @@
+DUT_IP_ADDRESS=10.10.120.24
+DUT_USERNAME=opnfv
+DUT_PASSWORD=opnfv
+
+TGEN_IP_ADDRESS=10.10.120.25
+TGEN_USERNAME=root
+TGEN_PASSWORD=P@ssw0rd
+TGEN_PARAMS= -i --no-scapy-server --nc --no-watchdog
+
+HUGEPAGE_MAX=8192
+HUGEPAGE_REQUESTED=1024
+
+SANITY_CHECK=NO
+
diff --git a/tools/docker/deployment/auto/controller/vsperf/__init__.py b/tools/docker/deployment/auto/controller/vsperf/__init__.py
new file mode 100644
index 00000000..ad0ebec3
--- /dev/null
+++ b/tools/docker/deployment/auto/controller/vsperf/__init__.py
@@ -0,0 +1 @@
+#### Empty
diff --git a/tools/docker/deployment/auto/controller/vsperf/collectd.conf b/tools/docker/deployment/auto/controller/vsperf/collectd.conf
new file mode 100644
index 00000000..9cefc8c5
--- /dev/null
+++ b/tools/docker/deployment/auto/controller/vsperf/collectd.conf
@@ -0,0 +1,49 @@
+Hostname "pod12-node4"
+Interval 1
+LoadPlugin intel_rdt
+LoadPlugin processes
+LoadPlugin interface
+LoadPlugin network
+LoadPlugin ovs_stats
+LoadPlugin cpu
+LoadPlugin memory
+LoadPlugin csv
+#LoadPlugin dpdkstat
+##############################################################################
+# Plugin configuration #
+##############################################################################
+<Plugin processes>
+ ProcessMatch "ovs-vswitchd" "ovs-vswitchd"
+ ProcessMatch "ovsdb-server" "ovsdb-server"
+ ProcessMatch "collectd" "collectd"
+</Plugin>
+<Plugin network>
+ Server "10.10.120.22" "25826"
+</Plugin>
+
+<Plugin ovs_stats>
+ Port "6640"
+ Address "127.0.0.1"
+ Socket "/usr/local/var/run/openvswitch/db.sock"
+ Bridges "vsperf-br0"
+</Plugin>
+
+<Plugin "intel_rdt">
+ Cores "2" "4-5" "6-7" "8" "9" "22" "23" "24" "25" "26" "27"
+</Plugin>
+
+<Plugin csv>
+ DataDir "/tmp/csv"
+ StoreRates false
+</Plugin>
+
+#<Plugin dpdkstat>
+# <EAL>
+# Coremask "0x1"
+# MemoryChannels "4"
+# FilePrefix "rte"
+# </EAL>
+# SharedMemObj "dpdk_collectd_stats_0"
+# EnabledPortMask 0xffff
+#</Plugin>
+
diff --git a/tools/docker/deployment/auto/controller/vsperf/trex_cfg.yaml b/tools/docker/deployment/auto/controller/vsperf/trex_cfg.yaml
new file mode 100644
index 00000000..8bb8e341
--- /dev/null
+++ b/tools/docker/deployment/auto/controller/vsperf/trex_cfg.yaml
@@ -0,0 +1,20 @@
+- port_limit : 2
+ version : 2
+ interfaces : ["81:00.0", "81:00.1"] # list of the interfaces to bind # node 4
+ port_bandwidth_gb : 10 #10G nics
+ port_info : # set eth mac addr
+ - dest_mac : "3c:fd:fe:b4:41:09" # port 0
+ src_mac : "3c:fd:fe:b4:41:08"
+ - dest_mac : "3c:fd:fe:b4:41:08" # port 1
+ src_mac : "3c:fd:fe:b4:41:09"
+ platform :
+ master_thread_id : 17
+ latency_thread_id : 16
+ dual_if :
+ - socket : 1
+ threads : [22,23,24,25,26,27]
+ - socket : 0
+ threads : [10,11,12,13,14,15]
+
+
+
diff --git a/tools/docker/deployment/auto/controller/vsperf/vsperf_controller.py b/tools/docker/deployment/auto/controller/vsperf/vsperf_controller.py
new file mode 100644
index 00000000..b6865272
--- /dev/null
+++ b/tools/docker/deployment/auto/controller/vsperf/vsperf_controller.py
@@ -0,0 +1,392 @@
+# Copyright 2018-19 Spirent Communications.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+VSPERF_deploy_auto
+"""
+# pylint: disable=W0603
+
+import os
+import sys
+from utils import ssh
+
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+
+DUT_IP = os.getenv('DUT_IP_ADDRESS')
+DUT_USER = os.getenv('DUT_USERNAME')
+DUT_PWD = os.getenv('DUT_PASSWORD')
+
+TGEN_IP = os.getenv('TGEN_IP_ADDRESS')
+TGEN_USER = os.getenv('TGEN_USERNAME')
+TGEN_PWD = os.getenv('TGEN_PASSWORD')
+TGEN_PARAM = os.getenv('TGEN_PARAMS')
+
+HPMAX = int(os.getenv('HUGEPAGE_MAX'))
+HPREQUESTED = int(os.getenv('HUGEPAGE_REQUESTED'))
+
+SANITY = str(os.getenv('SANITY_CHECK'))#
+
+DUT_CLIENT = None
+TGEN_CLIENT = None
+
+
+def host_connect():
+ """
+ Handle host connectivity to DUT
+ """
+ global DUT_CLIENT
+ DUT_CLIENT = ssh.SSH(host=DUT_IP, user=DUT_USER, password=DUT_PWD)
+ print("DUT-Host Successfully Connected .........................................[OK] \n ")
+
+def tgen_connect():
+ """
+ Handle Tgen Connection to Trex
+ """
+ global TGEN_CLIENT
+ TGEN_CLIENT = ssh.SSH(host=TGEN_IP, user=TGEN_USER, password=TGEN_PWD)
+ print("Traffic Generator Successfully Connected ...............................[OK] \n ")
+
+
+def vsperf_install():
+ """
+ Perform actual installation
+ """
+ vsperf_check_command = "source ~/vsperfenv/bin/activate ; "
+ vsperf_check_command += "cd vswitchperf && ./vsperf --help"
+ vsperf_check_cmd_result = str(DUT_CLIENT.execute(vsperf_check_command)[1])
+ vsperf_verify_list = [
+ 'usage',
+ 'positional arguments',
+ 'optional arguments',
+ 'test selection options',
+ 'test behavior options']
+ for idx, i in enumerate(vsperf_verify_list, start=1):
+ if str(i) in vsperf_check_cmd_result:
+ if idx < 5:
+ continue
+ elif idx == 5:
+ print(
+ "VSPERF is Already Installed on DUT-Host..........................."\
+ ".......[OK]\n")
+ else:
+ download_cmd = "git clone https://gerrit.opnfv.org/gerrit/vswitchperf"
+ DUT_CLIENT.run(download_cmd)
+ install_cmd = "cd vswitchperf/systems ; "
+ install_cmd += "echo '{}' | sudo -S ./build_base_machine.sh ".\
+ format(DUT_PWD)
+ DUT_CLIENT.run(install_cmd)
+ print(
+ "Vsperf Installed on DUT-Host ....................................[OK]\n")
+
+
+def tgen_install():
+ """
+ Install T-rex traffic gen on TGen
+ """
+ kill_cmd = "pkill -f ./t-rex"
+ TGEN_CLIENT.send_command(kill_cmd)
+ tgen_start_check = "cd trex/scripts && ./t-rex-64 -f cap2/dns.yaml -d 100 -m 1 --nc"
+ tgen_start_cmd_result = int(TGEN_CLIENT.execute(tgen_start_check)[0])
+ if tgen_start_cmd_result == 0:
+ print(
+ "The Host has T-rex Installed....................................[OK]\n")
+ else:
+ download_cmd = "git clone https://github.com/cisco-system-traffic-generator/trex-core trex"
+ TGEN_CLIENT.run(download_cmd)
+ install_cmd = "cd trex-core/linux_dpdk ; ./b configure ; ./b build"
+ TGEN_CLIENT.run(install_cmd)
+ print(
+ "The Host has now T-rex Installed...........................[OK]\n")
+
+def upload_tgen_config_file():
+ """
+ Upload Tgen Config File on T-rex
+ """
+ localpath = '/usr/src/app/vsperf/trex_cfg.yaml'
+ if not os.path.exists(localpath):
+ print("TGEN config File does not exist................[Failed]")
+ return
+ remotepath = '~/trex_cfg.yaml'
+ check_trex_config_cmd = "echo {} | sudo -S find /etc -maxdepth 1 -name '{}'".format(
+ TGEN_PWD, remotepath[2:])
+ check_test_result = str(TGEN_CLIENT.execute(check_trex_config_cmd)[1])
+ if remotepath[2:] in check_test_result:
+ DUT_CLIENT.run("rm -f /etc/{}".format(remotepath[2:]))
+ TGEN_CLIENT.put_file(localpath, remotepath)
+ TGEN_CLIENT.run(
+ "echo {} | sudo -S mv ~/{} /etc/".format(TGEN_PWD, remotepath[2:]), pty=True)
+ print(
+ "T-rex Configuration File Uploaded on TGen-Host...........................[OK]\n")
+
+
+def install_collectd():
+ """
+ installation of the collectd
+ """
+ check_collectd_config_cmd = "find /opt -maxdepth 1 -name 'collectd'"
+ check_test_result = str(DUT_CLIENT.execute(check_collectd_config_cmd)[1])
+ if "collectd" in check_test_result:
+ print(
+ 'Collectd Installed Successfully on DUT-Host..............................[OK]\n')
+ else:
+ download_cmd = "git clone https://github.com/collectd/collectd.git"
+ DUT_CLIENT.run(download_cmd)
+ build_cmd = "cd collectd ; "
+ build_cmd += "./build.sh"
+ DUT_CLIENT.run(build_cmd)
+ config_cmd = "cd collectd ; ./configure --enable-syslog --enable-logfile "
+ config_cmd += "--enable-hugepages --enable-debug ; "
+ DUT_CLIENT.run(config_cmd)
+ install_cmd = "cd collectd ; make ; "
+ install_cmd += "echo '{}' | sudo -S make install".format(DUT_PWD)
+ DUT_CLIENT.run(install_cmd, pty=True)
+ print(
+ 'Collectd Installed Successfully on DUT-Host.............................[OK]\n ')
+
+
+def collectd_upload_config():
+ """
+ Upload Configuration file of Collectd on DUT
+ """
+ localpath = '/usr/src/app/vsperf/collectd.conf'
+ if not os.path.exists(localpath):
+ print("Collectd config File does not exist.......................[Failed]")
+ return
+ remotepath = '~/collectd.conf'
+ collectd_config_cmd = "echo {} | sudo -S find /opt/collectd/etc -maxdepth 1 -name '{}'".\
+ format(DUT_PWD, remotepath[2:])
+ check_test_result = str(DUT_CLIENT.execute(collectd_config_cmd)[1])
+ if remotepath[2:] in check_test_result:
+ DUT_CLIENT.run(
+ "echo {} | sudo -S rm -f /opt/collectd/etc/{}".format(DUT_PWD, remotepath[2:]))
+ DUT_CLIENT.put_file(localpath, remotepath)
+ DUT_CLIENT.run("echo {} | sudo -S mv ~/{} /opt/collectd/etc/".\
+ format(DUT_PWD, remotepath[2:]), pty=True)
+ print(
+ "Collectd Configuration File Uploaded on DUT-Host.........................[OK]\n ")
+
+def start_tgen():
+ """
+ It will start the Traffic generetor
+ """
+ kill_cmd = "pkill -f ./t-rex"
+ TGEN_CLIENT.send_command(kill_cmd)
+ run_cmd = "cd trex_2.37/scripts && "
+ run_cmd += "screen ./t-rex-64 "
+ run_cmd += TGEN_PARAM
+ TGEN_CLIENT.send_command(run_cmd)
+ print(
+ "T-Rex Successfully running...............................................[OK]\n")
+
+
+def dut_hugepage_config():
+ """
+ Configure the DUT system hugepage parameter from client
+ """
+ if not HPMAX or not HPREQUESTED:
+ print("HPMAX and HPREQUESTED not defined ...................[Failed]")
+ return
+ hugepage_cmd = "echo '{}' | sudo -S mkdir -p /mnt/huge ; ".format(
+ DUT_PWD)
+ hugepage_cmd += "echo '{}' | sudo -S mount -t hugetlbfs nodev /mnt/huge".format(
+ DUT_PWD)
+ DUT_CLIENT.run(hugepage_cmd, pty=True)
+ hp_nr_cmd = "cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages"
+ hp_free_cmd = "cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/free_hugepages"
+ hp_nr = int(DUT_CLIENT.execute(hp_nr_cmd)[1])
+ hp_free = int(DUT_CLIENT.execute(hp_free_cmd)[1])
+ if hp_free <= HPREQUESTED:
+ hp_nr_new = hp_nr + (HPREQUESTED - hp_free)
+ if hp_nr_new > HPMAX:
+ hp_nr_new = HPMAX
+
+ nr_hugepage_cmd = "echo '{}' | sudo -S bash -c \"echo 'vm.nr_hugepages={}' >> ".\
+ format(DUT_PWD, hp_nr_new)
+ nr_hugepage_cmd += "/etc/sysctl.conf\""
+ DUT_CLIENT.run(nr_hugepage_cmd, pty=True)
+
+ dict_cmd = "cat /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages"
+ dict_check = int(DUT_CLIENT.execute(dict_cmd)[0])
+ if dict_check == 0:
+ node1_hugepage_cmd = "echo '{}' | sudo -s bash -c \"echo 0 > ".format(DUT_PWD)
+ node1_hugepage_cmd += "/sys/devices/system/node/node1/hugepages"
+ node1_hugepage_cmd += "/hugepages-2048kB/nr_hugepages\""
+ DUT_CLIENT.run(node1_hugepage_cmd, pty=True)
+ print("DUT-Host system configured with {} No of Hugepages.....................[OK] \n ".\
+ format(hp_nr_new))
+
+
+def sanity_nic_check():
+ """
+ Check either NIC PCI ids are Correctly placed or not
+ """
+ trex_conf_path = "cat /etc/trex_cfg.yaml | grep interfaces"
+ trex_conf_read = TGEN_CLIENT.execute(trex_conf_path)[1]
+ nic_pid_ids_list = [trex_conf_read.split("\"")[1], trex_conf_read.split("\"")[3]]
+ trex_nic_pic_id_cmd = "lspci | egrep -i --color 'network|ethernet'"
+ trex_nic_pic_id = str(TGEN_CLIENT.execute(trex_nic_pic_id_cmd)[1]).split('\n')
+ acheck = 0
+ for k in trex_nic_pic_id:
+ for j in nic_pid_ids_list:
+ if j in k:
+ acheck += 1
+ else:
+ pass
+ if acheck == 2:
+ print("Both the NIC PCI Ids are Correctly"\
+ " configured on TGen-Host...............[OK]\n")
+ else:
+ print("You configured NIC PCI Ids Wrong in "\
+ "TGen-Host............................[OK]\n")
+
+
+def sanity_collectd_check():
+ """
+ Check and verify collectd is able to run and start properly
+ """
+ check_collectd_cmd = "find /opt -maxdepth 1 -name 'collectd'"
+ check_test_result = str(DUT_CLIENT.execute(check_collectd_cmd)[1])
+ if "collectd" in check_test_result:
+ check_collectd_run_cmd = "echo {} | sudo -S service collectd start".format(
+ DUT_PWD)
+ DUT_CLIENT.run(check_collectd_run_cmd, pty=True)
+ check_collectd_status_cmd = "ps aux | grep collectd"
+ check_collectd_status = str(
+ DUT_CLIENT.execute(check_collectd_status_cmd)[1])
+ if "/sbin/collectd" in check_collectd_status:
+ print(
+ "Collectd is working Fine ................................................[OK] \n ")
+ else:
+ print(
+ "Collectd Fail to Start, Install correctly before running Test....[Failed]\n ")
+ else:
+ print(
+ "Collectd is not installed yet........................................[Failed]\n")
+
+def sanity_vsperf_check():
+ """
+ We have to make sure that VSPERF install correctly
+ """
+ if not DUT_CLIENT:
+ print("The Client is disconnected................................[Failed]")
+ return
+ vsperf_check_cmd = "source ~/vsperfenv/bin/activate ; cd vswitchperf && ./vsperf --help"
+ vsperf_check_cmd_result = str(DUT_CLIENT.execute(vsperf_check_cmd)[1])
+ vsperf_verify_list = [
+ 'usage',
+ 'positional arguments',
+ 'optional arguments',
+ 'test selection options',
+ 'test behavior options']
+ for idx, i in enumerate(vsperf_verify_list, start=1):
+ if str(i) in vsperf_check_cmd_result:
+ if idx < 5:
+ continue
+ elif idx == 5:
+ print(
+ "VSPERF Installed Correctly and Working fine.........................."\
+ "....[OK]\n")
+ else:
+ print(
+ "VSPERF Does Not Installed Correctly , INSTALL IT AGAIN........[Critical]\n")
+ else:
+ print(
+ "VSPERF Does Not Installed Correctly , INSTALL IT AGAIN............[Critical]\n")
+ break
+
+
+def sanity_tgen_conn_dut_check():
+ """
+ We should confirm the DUT connectivity with the Tgen and Traffic Generator is working or not
+ """
+ if not DUT_CLIENT or not TGEN_CLIENT:
+ print("The Client is disconnected................................[Failed]")
+ return
+ tgen_connectivity_check_cmd = "ping {} -c 1".format(TGEN_IP)
+ tgen_connectivity_check_result = int(
+ DUT_CLIENT.execute(tgen_connectivity_check_cmd)[0])
+ if tgen_connectivity_check_result == 0:
+ print(
+ "DUT-Host is successfully reachable to Traffic Generator Host.............[OK]\n")
+ else:
+ print(
+ "DUT-host is unsuccessful to reach the Traffic Generator Host..............[Failed]")
+ print(
+ "Make sure to establish connection before running Test...............[Critical]\n")
+
+
+def sanity_tgen_check():
+ """
+ It will check Trex properly running or not
+ """
+ if not TGEN_CLIENT:
+ print("The Client is disconnected................................[Failed]")
+ return
+ tgen_start_cmd_check = "cd trex/scripts &&"
+ tgen_start_cmd_check += " ./t-rex-64 -f cap2/dns.yaml -d 100 -m 1 --nc"
+ tgen_start_cmd_result = int(TGEN_CLIENT.execute(tgen_start_cmd_check)[0])
+ if tgen_start_cmd_result == 0:
+ print(
+ "TGen-Host successfully running........................................[OK]\n")
+ else:
+ print("TGen-Host is unable to start t-rex ..................[Failed]")
+ print("Make sure you install t-rex correctly ...............[Critical]\n")
+
+
+def dut_vsperf_test_availability():
+ """
+ Before running test we have to make sure there is no other test running
+ """
+ vsperf_ava_cmd = "ps -ef | grep -v grep | grep ./vsperf | awk '{print $2}'"
+ vsperf_ava_result = len(
+ (DUT_CLIENT.execute(vsperf_ava_cmd)[1]).split("\n"))
+ if vsperf_ava_result == 1:
+ print("DUT-Host is available for performing VSPERF Test\n\
+ You can perform Test!")
+ else:
+ print("DUT-Host is busy right now, Wait for some time\n\
+ Always Check availability before Running Test!\n")
+
+if DUT_IP:
+ host_connect()
+if not DUT_CLIENT:
+ print('Failed to connect to DUT ...............[Critical]')
+ sys.exit()
+else:
+ vsperf_install()
+ install_collectd()
+ collectd_upload_config()
+ dut_hugepage_config()
+ dut_vsperf_test_availability()
+if TGEN_IP:
+ tgen_connect()
+if not TGEN_CLIENT:
+ print('Failed to connect to TGEN_HOST.............[Critical]')
+ sys.exit()
+else:
+ tgen_install()
+ upload_tgen_config_file()
+ sanity_nic_check()
+ start_tgen()
+
+print("\n\nIF you are getting any Failed or Critical message!!!\n" \
+ "Please follow this steps:\n"
+ "1. Make necessory changes before running VSPERF TEST\n"\
+ "2. Re-Run the auto deployment container")
+
+if SANITY and 'yes' in SANITY.lower():
+ sanity_collectd_check()
+ sanity_vsperf_check()
+ sanity_tgen_check()
+ sanity_tgen_conn_dut_check()
diff --git a/tools/docker/deployment/auto/docker-compose.yml b/tools/docker/deployment/auto/docker-compose.yml
new file mode 100644
index 00000000..b5b808d2
--- /dev/null
+++ b/tools/docker/deployment/auto/docker-compose.yml
@@ -0,0 +1,22 @@
+version: '2'
+
+services:
+ deploy:
+ build:
+ context: ./controller
+ volumes:
+ - ./controller/vsperf:/vsperf
+ env_file:
+ - ./controller/list.env
+ ports:
+ - 50051
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/docker/deployment/interactive/controller/Dockerfile b/tools/docker/deployment/interactive/controller/Dockerfile
new file mode 100644
index 00000000..3d9fca42
--- /dev/null
+++ b/tools/docker/deployment/interactive/controller/Dockerfile
@@ -0,0 +1,21 @@
+FROM python:3.6
+LABEL maintainer="sridhar.rao@spirent.com"
+
+ENV GRPC_PYTHON_VERSION 1.4.0
+RUN apt-get update && apt-get -y install python3-pip
+RUN pip3 install grpcio==${GRPC_PYTHON_VERSION} grpcio-tools==${GRPC_PYTHON_VERSION}
+RUN pip3 install paramiko
+RUN pip3 install chainmap
+RUN pip3 install oslo.utils
+RUN pip3 install scp
+
+WORKDIR /usr/src/app
+
+COPY ./vsperf ./vsperf
+
+VOLUME ["/usr/src/app/vsperf"]
+
+CMD ["python3", "./vsperf/vsperf_controller.py"]
+
+
+
diff --git a/tools/docker/deployment/interactive/controller/vsperf/__init__.py b/tools/docker/deployment/interactive/controller/vsperf/__init__.py
new file mode 100644
index 00000000..ad0ebec3
--- /dev/null
+++ b/tools/docker/deployment/interactive/controller/vsperf/__init__.py
@@ -0,0 +1 @@
+#### Empty
diff --git a/tools/docker/deployment/interactive/controller/vsperf/vsperf_controller.py b/tools/docker/deployment/interactive/controller/vsperf/vsperf_controller.py
new file mode 100644
index 00000000..b192c493
--- /dev/null
+++ b/tools/docker/deployment/interactive/controller/vsperf/vsperf_controller.py
@@ -0,0 +1,360 @@
+# Copyright 2018-19 Spirent Communications.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# pylint: disable=R0902
+# Sixteen is reasonable instance attributes
+# pylint: disable=W0221
+"""
+VSPER docker-controller.
+"""
+
+import io
+import time
+from concurrent import futures
+import grpc
+
+from proto import vsperf_pb2
+from proto import vsperf_pb2_grpc
+from utils import ssh
+
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+
+
+# pylint: disable=too-few-public-methods,no-self-use
+class PseudoFile(io.RawIOBase):
+ """
+ Handle ssh command output.
+ """
+
+ def write(self, chunk):
+ """
+ Write to file
+ """
+ if "error" in chunk:
+ return
+ with open("./output.txt", "a") as fref:
+ fref.write(chunk)
+
+
+class VsperfController(vsperf_pb2_grpc.ControllerServicer):
+ """
+ Main Controller Class
+ """
+
+ def __init__(self):
+ """
+ Initialization
+ """
+ self.client = None
+ self.dut = None
+ self.dut_check = None
+ self.tgen_check = None
+ self.user = None
+ self.pwd = None
+ self.tgen_client = None
+ self.tgen = None
+ self.tgen_user = None
+ self.tgenpwd = None
+ self.tgen_conf = None
+ self.scenario = None
+ self.hpmax = None
+ self.hprequested = None
+ self.tgen_ip_address = None
+ self.trex_conf = None
+ # Default TGen is T-Rex
+ self.trex_conffile = "trex_cfg.yml"
+ self.collectd_conffile = "collectd.conf"
+
+ def setup(self):
+ """
+ Performs Setup of the client.
+ """
+ # Just connect to VM.
+ self.client = ssh.SSH(host=self.dut, user=self.user,
+ password=self.pwd)
+ self.client.wait()
+
+ def install_vsperf(self):
+ """
+ Perform actual installation
+ """
+ download_cmd = "git clone https://gerrit.opnfv.org/gerrit/vswitchperf"
+ self.client.run(download_cmd)
+ install_cmd = "cd vswitchperf/systems ; "
+ install_cmd += "echo '{}' | sudo -S ./build_base_machine.sh ".format(
+ self.pwd)
+ #install_cmd += "./build_base_machine.sh"
+ self.client.run(install_cmd)
+
+ def VsperfInstall(self, request, context):
+ """
+ Handle VSPERF install command from client
+ """
+ # print("Installing VSPERF")
+ if self.dut_check != 0:
+ return vsperf_pb2.StatusReply(message="DUT-Host is not Connected [!]" \
+ "\nMake sure to establish connection with" \
+ " DUT-Host.")
+ vsperf_check_cmd = "source ~/vsperfenv/bin/activate ; cd vswitchperf* && ./vsperf --help"
+ vsperf_check_cmd_result = str(self.client.execute(vsperf_check_cmd)[1])
+ vsperf_verify_list = [
+ 'usage',
+ 'positional arguments',
+ 'optional arguments',
+ 'test selection options',
+ 'test behavior options']
+ for idx, i in enumerate(vsperf_verify_list, start=1):
+ if str(i) in vsperf_check_cmd_result:
+ if idx < 5:
+ continue
+ elif idx == 5:
+ return vsperf_pb2.StatusReply(
+ message="VSPERF is Already Installed on DUT-Host")
+ self.install_vsperf()
+ return vsperf_pb2.StatusReply(message="VSPERF Successfully Installed DUT-Host")
+
+ def HostConnect(self, request, context):
+ """
+ Handle host connectivity command from client
+ """
+ self.dut = request.ip
+ self.user = request.uname
+ self.pwd = request.pwd
+ self.setup()
+ check_cmd = "ls -l"
+ self.dut_check = int(self.client.execute(check_cmd)[0])
+ return vsperf_pb2.StatusReply(message="Successfully Connected")
+
+ def save_chunks_to_file(self, chunks, filename):
+ """
+ Write the output to file
+ """
+ with open(filename, 'wb') as fref:
+ for chunk in chunks:
+ fref.write(chunk.Content)
+
+###### Traffic Generator Related functions ####
+ def TGenHostConnect(self, request, context):
+ """
+ Connect to TGen-Node
+ """
+ self.tgen = request.ip
+ self.tgen_user = request.uname
+ self.tgenpwd = request.pwd
+ self.tgen_setup()
+ check_tgen_cmd = "ls"
+ self.tgen_check = int(self.tgen_client.execute(check_tgen_cmd)[0])
+ return vsperf_pb2.StatusReply(message="Successfully Connected")
+
+ def tgen_setup(self):
+ """
+ Setup the T-Gen Client
+ """
+ # Just connect to VM.
+ self.tgen_client = ssh.SSH(host=self.tgen, user=self.tgen_user,
+ password=self.tgenpwd)
+ self.tgen_client.wait()
+
+ def TGenInstall(self, request, context):
+ """
+ Install Traffic generator on the node.
+ """
+ if self.tgen_check != 0:
+ return vsperf_pb2.StatusReply(message="TGen-Host is not Connected [!]" \
+ "\nMake sure to establish connection with" \
+ " TGen-Host.")
+ kill_cmd = "pkill -f t-rex"
+ self.tgen_client.send_command(kill_cmd)
+ tgen_start_cmd = "cd trex_2.37/scripts && ./t-rex-64 -f cap2/dns.yaml -d 100 -m 1 --nc"
+ tgen_start_cmd_result = int(self.tgen_client.execute(tgen_start_cmd)[0])
+ kill_cmd = "pkill -f t-rex"
+ self.tgen_client.send_command(kill_cmd)
+ if tgen_start_cmd_result == 0:
+ return vsperf_pb2.StatusReply(
+ message="Traffic Generetor has T-rex Installed")
+ download_cmd = "git clone https://github.com/cisco-system-traffic-generator/trex-core"
+ self.tgen_client.run(download_cmd)
+ install_cmd = "cd trex-core/linux_dpdk ; ./b configure ; ./b build"
+ self.tgen_client.run(install_cmd)
+ # before you setup your trex_cfg.yml make sure to do sanity check
+ # NIC PICs and establish route between your DUT and Test Device.
+ return vsperf_pb2.StatusReply(message="Traffic Generetor has now T-rex Installed")
+
+ def TGenUploadConfigFile(self, request, context):
+ """
+ Handle upload config-file command from client
+ """
+ if self.tgen_check != 0:
+ return vsperf_pb2.StatusReply(message="TGen-Host is not Connected [!]" \
+ "\nMake sure to establish connection with" \
+ " TGen-Host.")
+ filename = self.trex_conffile
+ self.save_chunks_to_file(request, filename)
+ check_trex_config_cmd = "echo {} | sudo -S find /etc -maxdepth 1 -name trex_cfg.yaml".\
+ format(self.tgenpwd)
+ check_test_result = str(
+ self.tgen_client.execute(check_trex_config_cmd)[1])
+ if "trex_cfg.yaml" in check_test_result:
+ self.tgen_client.run("rm -f /etc/trex_cfg.yaml")
+ self.upload_tgen_config()
+ self.tgen_client.run(
+ "echo {} | sudo -S mv ~/trex_cfg.yaml /etc/".format(self.tgenpwd), pty=True)
+ return vsperf_pb2.UploadStatus(Message="Successfully Uploaded",
+ Code=1)
+
+ def upload_tgen_config(self):
+ """
+ Perform file upload.
+ """
+ self.tgen_client.put_file(self.trex_conffile, '/root/trex_cfg.yaml')
+
+# Tool-Chain related Functions####3
+
+ def install_collectd(self):
+ """
+ installation of the collectd
+ """
+ check_collectd_config_cmd = "find /opt -maxdepth 1 -name 'collectd'"
+ check_test_result = str(
+ self.client.execute(check_collectd_config_cmd)[1])
+ if "collectd" in check_test_result:
+ pass
+ else:
+ download_cmd = "git clone https://github.com/collectd/collectd.git"
+ self.client.run(download_cmd)
+ build_cmd = "cd collectd ; "
+ build_cmd += "./build.sh"
+ self.client.run(build_cmd)
+ config_cmd = "cd collectd ; ./configure --enable-syslog "
+ config_cmd += "--enable-logfile --enable-hugepages --enable-debug ; "
+ self.client.run(config_cmd)
+ install_cmd = "cd collectd ; make ; "
+ install_cmd += "echo '{}' | sudo -S make install".format(self.pwd)
+ self.client.run(install_cmd, pty=True)
+
+ def CollectdInstall(self, request, context):
+ """
+ Install Collectd on DUT
+ """
+ if self.dut_check != 0:
+ return vsperf_pb2.StatusReply(message="DUT-Host is not Connected [!]" \
+ "\nMake sure to establish connection with" \
+ " DUT-Host.")
+ self.install_collectd()
+ return vsperf_pb2.StatusReply(
+ message="Collectd Successfully Installed on DUT-Host")
+
+ def upload_collectd_config(self):
+ """
+ Perform file upload.
+ """
+ self.client.put_file(self.collectd_conffile, '~/collectd.conf')
+ move_cmd = "echo '{}' | sudo -S mv ~/collectd.conf /opt/collectd/etc".format(
+ self.pwd)
+ self.client.run(move_cmd, pty=True)
+
+ def CollectdUploadConfig(self, request, context):
+ """
+ Upload collectd config-file on DUT
+ """
+ if self.dut_check != 0:
+ return vsperf_pb2.StatusReply(message="DUT-Host is not Connected [!]" \
+ "\nMake sure to establish connection with" \
+ " DUT-Host.")
+ filename = self.collectd_conffile
+ self.save_chunks_to_file(request, filename)
+ self.upload_collectd_config()
+ return vsperf_pb2.UploadStatus(
+ Message="Successfully Collectd Configuration Uploaded", Code=1)
+
+###System Configuration related functions###
+
+ def DutHugepageConfig(self, request, context):
+ """
+ Configure the DUT system hugepage parameter from client
+ """
+ if self.dut_check != 0:
+ return vsperf_pb2.StatusReply(message="DUT-Host is not Connected [!]" \
+ "\nMake sure to establish connection with" \
+ " DUT-Host.")
+ self.hpmax = int(request.hpmax)
+ self.hprequested = int(request.hprequested)
+ hugepage_cmd = "echo '{}' | sudo -S mkdir -p /mnt/huge ; ".format(
+ self.pwd)
+ hugepage_cmd += "echo '{}' | sudo -S mount -t hugetlbfs nodev /mnt/huge".format(
+ self.pwd)
+ self.client.run(hugepage_cmd, pty=True)
+ hp_nr_cmd = "cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages"
+ hp_free_cmd = "cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/free_hugepages"
+ hp_nr = int(self.client.execute(hp_nr_cmd)[1])
+ hp_free = int(self.client.execute(hp_free_cmd)[1])
+ if hp_free <= self.hprequested:
+ hp_nr_new = hp_nr + (self.hprequested - hp_free)
+ if hp_nr_new > self.hpmax:
+ hp_nr_new = self.hpmax
+
+ nr_hugepage_cmd = "echo '{}' | sudo -S bash -c \"echo 'vm.nr_hugepages={}' >>".\
+ format(self.pwd, hp_nr_new)
+ nr_hugepage_cmd += " /etc/sysctl.conf\""
+ self.client.run(nr_hugepage_cmd, pty=True)
+
+ dict_cmd = "cat /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages"
+ dict_check = int(self.client.execute(dict_cmd)[0])
+ if dict_check == 0:
+ node1_hugepage_cmd = "echo '{}' | sudo -s bash -c \"echo 0 >".format(self.pwd)
+ node1_hugepage_cmd += " /sys/devices/system/node/node1/"
+ node1_hugepage_cmd += "hugepages/hugepages-2048kB/nr_hugepages\""
+ return vsperf_pb2.StatusReply(
+ message="DUT-Host system configured with {} No of Hugepages".format(hp_nr_new))
+
+ def CheckDependecies(self, request, context):
+ """
+ Check and Install required packages on DUT
+ """
+ if self.dut_check != 0:
+ return vsperf_pb2.StatusReply(message="DUT-Host is not Connected [!]" \
+ "\nMake sure to establish connection with" \
+ " DUT-Host.")
+ packages = ['python34-tkinter', 'sysstat', 'bc']
+ for pkg in packages:
+ # pkg_check_cmd = "dpkg -s {}".format(pkg) for ubuntu
+ pkg_check_cmd = "rpm -q {}".format(pkg)
+ pkg_cmd_response = self.client.execute(pkg_check_cmd)[0]
+ if pkg_cmd_response == 1:
+ install_pkg_cmd = "echo '{}' | sudo -S yum install -y {}".format(
+ self.pwd, pkg)
+ #install_pkg_cmd = "echo '{}' | sudo -S apt-get install -y {}".format(self.pwd,pkg)
+ self.client.run(install_pkg_cmd, pty=True)
+
+ return vsperf_pb2.StatusReply(message="Python34-tkinter, sysstat and bc Packages"\
+ "are now Installed")
+
+def serve():
+ """
+ Start servicing the client
+ """
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+ vsperf_pb2_grpc.add_ControllerServicer_to_server(
+ VsperfController(), server)
+ server.add_insecure_port('[::]:50051')
+ server.start()
+ try:
+ while True:
+ time.sleep(_ONE_DAY_IN_SECONDS)
+ except (SystemExit, KeyboardInterrupt, MemoryError, RuntimeError):
+ server.stop(0)
+
+
+if __name__ == "__main__":
+ serve()
diff --git a/tools/docker/deployment/interactive/docker-compose.yml b/tools/docker/deployment/interactive/docker-compose.yml
new file mode 100644
index 00000000..cbf894c5
--- /dev/null
+++ b/tools/docker/deployment/interactive/docker-compose.yml
@@ -0,0 +1,21 @@
+version: '2'
+
+services:
+ deploy:
+ build:
+ context: ./controller
+ volumes:
+ - ./controller/vsperf:/vsperf
+ ports:
+ - 50051:50051
+
+
+
+
+
+
+
+
+
+
+