aboutsummaryrefslogtreecommitdiffstats
path: root/tools/docker/testcontrol/auto/controller/vsperf/vsperf_controller.py
blob: 1b088feac9d0698797008af24a88f38cb5986c01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# 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-controller
"""

# Fetching Environment Variable for controller, You can configure or
# modifies list.env file for setting your environment variable.

#pylint: disable=global-statement,no-else-continue
#pylint: disable=too-many-branches

import os
import time
import math
import ast
from utils import ssh

_ONE_DAY_IN_SECONDS = 60 * 60 * 24
TIMER = float()


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')

VSPERF_TEST = os.getenv('VSPERF_TESTS')
VSPERF_CONF = os.getenv('VSPERF_CONFFILE')
VSPERF_TRAFFICGEN_MODE = str(os.getenv('VSPERF_TRAFFICGEN_MODE'))

START_COLLECTD = os.getenv('START_COLLECTD')
START_BEATS = os.getenv('START_BEATS')
CLEAN_UP = os.getenv('CLEAN_UP')

DUT_CLIENT = None
TGEN_CLIENT = None
SANITY_CHECK_DONE_LIST = list()


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 Successfully Connected ..............................................[OK] \n ")

def upload_test_config_file():
    """
    #Upload Test Config File on DUT
    """
    localpath = '/usr/src/app/vsperf/vsperf.conf'
    if not os.path.exists(localpath):
        print("VSPERF Test config File does not exists.......................[Failed]")
        return
    remotepath = '~/vsperf.conf'
    check_test_config_cmd = "find ~/ -maxdepth 1 -name '{}'".format(
        remotepath[2:])
    check_test_result = str(DUT_CLIENT.execute(check_test_config_cmd)[1])
    if remotepath[2:] in check_test_result:
        DUT_CLIENT.run("rm -f {}".format(remotepath[2:]))
    DUT_CLIENT.put_file(localpath, remotepath)
    check_test_config_cmd_1= "find ~/ -maxdepth 1 -name '{}'".format(
        remotepath[2:])
    check_test_result_1= str(DUT_CLIENT.execute(check_test_config_cmd)[1])
    if remotepath[2:] in check_test_result_1:
    	print(
        "Test Configuration File Uploaded on DUT-Host.............................[OK] \n ")
    else:
    	print("VSPERF Test config file upload failed.....................................[Critical]")

def start_beats():
    """
    Start fileBeats on DUT
    """
    run_cmd = "echo '{}' | sudo -S service filebeat start".format(DUT_PWD)
    DUT_CLIENT.run(run_cmd, pty=True)
    print(
        "Beats are started on DUT-Host............................................[OK] \n")

def start_collectd():
    """
    start the collectd
    """
    run_cmd = "echo '{}' | sudo -S service collectd start".format(DUT_PWD)
    DUT_CLIENT.run(run_cmd, pty=True)
    print(
        "Collectd is started on DUT-Host............................................[OK] \n")

def run_vsperf_test():
    """
    Here we will perform the actual vsperf test
    """
    global TIMER
    rmv_cmd = "cd /mnt/huge && echo {} | sudo -S rm -rf *".format(DUT_PWD)
    DUT_CLIENT.run(rmv_cmd, pty=True)
    cmd = "source ~/vsperfenv/bin/activate ; "
    #cmd = "scl enable python33 bash ; "
    cmd += "cd vswitchperf && "
    cmd += "./vsperf "
    if VSPERF_CONF:
        cmd += "--conf-file ~/vsperf.conf "
    if "yes" in VSPERF_TRAFFICGEN_MODE.lower():
        cmd += "--mode trafficgen"
    vsperf_test_list = VSPERF_TEST.split(",")
    print(vsperf_test_list)
    for test in vsperf_test_list:
        atest = cmd
        atest += test
        DUT_CLIENT.run(atest, pty=True)
    print(
        "Test Successfully running................................................[OK]\n ")


def test_status():
    """
    Chechk for the test status after performing test
    """
    testtype_list = VSPERF_TEST.split(",")
    num_test = len(testtype_list)
    test_success = []
    test_failed = []
    testtype_list_len = len(testtype_list)
    for test in testtype_list:
        passed_minutes = 5
        latest_result_cmd = "find /tmp -mindepth 1 -type d -cmin -{} -printf '%f'".format(
            passed_minutes)
        test_result_dir = str(
            (DUT_CLIENT.execute(latest_result_cmd)[1]).split('find')[0])
        test_date_cmd = "date +%F"
        test_date = str(DUT_CLIENT.execute(test_date_cmd)[1]).replace("\n", "")
        if test_date in test_result_dir:
            testcase_check_cmd = "cd /tmp && cd `ls -t | grep results | head"
            testcase_check_cmd += " -{} | tail -1` && find . -maxdepth 1 -name '*{}*'".\
                                  format(testtype_list_len, test)
            testcase_check_output = str(
                DUT_CLIENT.execute(testcase_check_cmd)[1]).split('\n', 2)
            check = 0
            for i in testcase_check_output:
                if (".csv" in i) or (".md" in i) or (".rst" in i):
                    check += 1
            if check == 3:
                test_success.append(test)
            else:
                test_failed.append(test)
            testtype_list_len -= 1
    if num_test == len(test_success):
        print("All Test Successfully Completed on DUT-Host   Results... [OK]")
    elif not test_success:
        print("All Test Failed on DUT-Host \nResults... [Failed]")
    else:
        print(
            "Only {} Test failed    Results ... [Failed]\n"\
            "All other Test Successfully Completed on DUT-Host     Results... [OK] ".\
            format(test_failed))


def vsperf_remove():
    """
    Actual removal of the VSPERF
    """
    vsperf_rm_cmd = "echo '{}' | sudo -S rm -r ~/vswitchperf".format(DUT_PWD)
    DUT_CLIENT.run(vsperf_rm_cmd)
    vsperfenv_rm_cmd = "echo '{}' | sudo -S rm -r -f ~/vsperfenv".\
                        format(DUT_PWD)
    DUT_CLIENT.run(vsperfenv_rm_cmd)


def remove_uploaded_config():
    """
    Remove all the uploaded configuration files
    """
    vconfig_rm_cmd = "rm ~/vsperf.conf"
    DUT_CLIENT.run(vconfig_rm_cmd)
    cdconfig_rm_cmd = "echo '{}' | sudo -S rm /opt/collectd/etc/collectd.conf".\
                       format(DUT_PWD)
    DUT_CLIENT.run(cdconfig_rm_cmd)


def result_folders_remove():
    """
    Remove result folder on DUT
    """
    remove_cmd = "rm -r /tmp/*results*"
    DUT_CLIENT.run(remove_cmd)


def collectd_remove():
    """
    Remove collectd from DUT
    """
    collectd_dwn_rm_cmd = "echo '{}' | sudo -S rm -r -f ~/collectd".format(
        DUT_PWD)
    DUT_CLIENT.run(collectd_dwn_rm_cmd)
    collectd_rm_cmd = "echo '{}' | sudo -S rm -r -f /opt/collectd".format(
        DUT_PWD)
    DUT_CLIENT.run(collectd_rm_cmd)


def terminate_vsperf():
    """
    Terminate the VSPERF and kill processes
    """
    stress_kill_cmd = "echo '{}' | sudo -S pkill stress &> /dev/null".format(
        DUT_PWD)
    python3_kill_cmd = "echo '{}' | sudo -S pkill python3 &> /dev/null".format(
        DUT_PWD)
    qemu_kill_cmd = "echo '{}' | sudo -S killall -9 qemu-system-x86_64 &> /dev/null".format(
        DUT_PWD)
    DUT_CLIENT.run(stress_kill_cmd)
    DUT_CLIENT.run(python3_kill_cmd)
    DUT_CLIENT.run(qemu_kill_cmd)

    # sometimes qemu resists to terminate, so wait a bit and kill it again
    qemu_check_cmd = "pgrep qemu-system-x86_64"
    qemu_cmd_response = DUT_CLIENT.execute(qemu_check_cmd)[1]

    if qemu_cmd_response != '':
        time.sleep(5)
        DUT_CLIENT.run(qemu_kill_cmd)
        time.sleep(5)

    ovs_kill_cmd = "echo '{}' | sudo pkill ovs-vswitchd &> /dev/null".format(
        DUT_PWD)
    ovsdb_kill_cmd = "echo '{}' | sudo pkill ovsdb-server &> /dev/null".format(
        DUT_PWD)
    vppctl_kill_cmd = "echo '{}' | sudo pkill vppctl &> /dev/null".format(
        DUT_PWD)
    vpp_kill_cmd = "echo '{}' | sudo pkill vpp &> /dev/null".format(DUT_PWD)
    vpp_cmd = "echo '{}' | sudo pkill -9 vpp &> /dev/null".format(DUT_PWD)

    DUT_CLIENT.run(ovs_kill_cmd)
    time.sleep(1)
    DUT_CLIENT.run(ovsdb_kill_cmd)
    time.sleep(1)
    DUT_CLIENT.run(vppctl_kill_cmd)
    time.sleep(1)
    DUT_CLIENT.run(vpp_kill_cmd)
    time.sleep(1)
    DUT_CLIENT.run(vpp_cmd)
    time.sleep(1)

    print(
        "All the VSPERF related process terminated successfully..............[OK]")


def sanity_collectd_check():
    """
    Check and verify collectd is able to run and start properly
    """
    global SANITY_CHECK_DONE_LIST
    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:
            SANITY_CHECK_DONE_LIST.append(int(1))
            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_vnf_path():
    """
    Check if VNF image is available on the configured path in Test Config File
    """
    # fetch the VNF path we placed in vsperf.conf file
    global SANITY_CHECK_DONE_LIST
    vsperf_conf_path = open('/usr/src/app/vsperf/vsperf.conf')
    vsperf_conf_read = vsperf_conf_path.readlines()
    for i in vsperf_conf_read:
        if 'GUEST_IMAGE' in i:
            vnf_image_path = i.split("'")[1]
            vnf_path_check_cmd = "find {}".format(vnf_image_path)
            vnf_path_check_result = str(
                DUT_CLIENT.execute(vnf_path_check_cmd)[1])
            if vnf_image_path in vnf_path_check_result:
                SANITY_CHECK_DONE_LIST.append(int(2))
                print(
                    "Test Configratuion file has Correct VNF path information on DUT-Host.." \
                    "...[OK]\n ")
            else:
                print(
                    "Test Configuration file has incorrect VNF path information......" \
                    "....[FAILED]\n")

def sanity_vsperf_check():
    """
    We have to make sure that VSPERF is installed correctly
    """
    global SANITY_CHECK_DONE_LIST
    vsperf_check_command = "source ~/vsperfenv/bin/activate ; 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:
                SANITY_CHECK_DONE_LIST.append(int(3))
                print("VSPERF Installed Correctly and Working fine......................." \
                    ".......[OK]\n")
            else:
                print(
                    "VSPERF DID Not Installed Correctly , INSTALL IT AGAIN...........[Critical]\n")
        else:
            print(
                "VSPERF DID Not Installed Correctly , INSTALL IT AGAIN................[Critical]\n")
            break

def variable_from_test_config(aparameter):
    """This function can be use to read any configuration paramter from vsperf.conf"""
    read_cmd = 'cat ~/vsperf.conf | grep "{}"'.format(aparameter)
    read_cmd_output = str(DUT_CLIENT.execute(read_cmd)[1])
    print(read_cmd_output)
    if not read_cmd_output or '#' in read_cmd_output:
        return 0
    return read_cmd_output.split("=")[1].strip()

def cpumask2coreids(mask):
    """conver mask to coreids"""
    intmask = int(mask, 16)
    i = 1
    coreids = []
    while i < intmask:
        if i & intmask:
            coreids.append(str(math.frexp(i)[1]-1))
        i = i << 1
    return coreids

def sanity_cpu_allocation_check():
    """It will check the cpu allocation before run test"""
    global SANITY_CHECK_DONE_LIST
    read_setting_cmd = "source vsperfenv/bin/activate ; cd vswitchperf* && "
    read_setting_cmd += './vsperf --list-settings'
    default_vsperf_settings = ast.literal_eval(str(DUT_CLIENT.execute(read_setting_cmd)[1]))
    default_cpu_map = default_vsperf_settings["VSWITCH_VHOST_CPU_MAP"]
    default_vswitch_pmd_cpu_mask = str(default_vsperf_settings["VSWITCH_PMD_CPU_MASK"])
    default_vswitch_vhost_cpu_map = [str(x) for x in default_cpu_map]
    vswitch_pmd_cpu_mask = variable_from_test_config("VSWITCH_PMD_CPU_MASK")
    vswitch_cpu_map = (variable_from_test_config("VSWITCH_VHOST_CPU_MAP"))
    vswitch_vhost_cpu_map = 0
    if vswitch_cpu_map != 0:
        vswitch_vhost_cpu_map = [str(x) for x in  ast.literal_eval(vswitch_cpu_map)]

    if vswitch_pmd_cpu_mask == 0 and vswitch_vhost_cpu_map == 0:
        print("CPU allocation Check Done,"\
            "\nNo vswitch_pmd_cpu_mask or vswitch_vhost_cpu_map assign in test config file\n" \
            "Using Default Settings ..................................................[OK]\n")
    elif vswitch_pmd_cpu_mask != 0 and vswitch_vhost_cpu_map == 0:
        core_id = cpumask2coreids(vswitch_pmd_cpu_mask)
        print(core_id)
        if len(default_vswitch_vhost_cpu_map) >= len(core_id):
            if all(elem in default_vswitch_vhost_cpu_map  for elem in core_id):
                print("CPU allocation properly done on DUT-Host.................[OK]\n")
            else:
                print("CPU allocation not done properly on DUT-Host............[Failed]\n")
        else:
            print("CPU allocation not done properly on DUT-Host............[Failed]\n")
    elif vswitch_pmd_cpu_mask == 0 and vswitch_vhost_cpu_map != 0:
        core_id_1 = cpumask2coreids(default_vswitch_pmd_cpu_mask)
        print(core_id_1)
        if len(vswitch_vhost_cpu_map) >= len(core_id_1):
            if all(elem in vswitch_vhost_cpu_map  for elem in core_id_1):
                print("CPU allocation properly done on DUT-Host.................[OK]\n")
            else:
                print("CPU allocation not done properly on DUT-Host............[Failed]\n")
        else:
            print("CPU allocation not done properly on DUT-Host............[Failed]\n")
    else:
        core_id_2 = cpumask2coreids(vswitch_pmd_cpu_mask)
        print(core_id_2)
        if len(vswitch_vhost_cpu_map) >= len(core_id_2):
            if all(elem in vswitch_vhost_cpu_map  for elem in core_id_2):
                print("CPU allocation properly done on DUT-Host.................[OK]\n")
            else:
                print("CPU allocation not done properly on DUT-Host............[Failed]\n")
        else:
            print("CPU allocation not done properly on DUT-Host............[Failed]\n")



def sanity_dut_conn_tgen_check():
    """
    We should confirm the DUT connectivity with the Tgen and Traffic Generator is working or not
    """
    global SANITY_CHECK_DONE_LIST
    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:
        SANITY_CHECK_DONE_LIST.append(int(5))
        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")

if DUT_IP:
    host_connect()
if not DUT_CLIENT:
    print('Failed to connect to DUT ...............[Critical]')
    sys.exit()
else:
    upload_test_config_file()
    sanity_vnf_path()
    sanity_cpu_allocation_check()
    sanity_collectd_check()
    sanity_vsperf_check()
    sanity_dut_conn_tgen_check()
    if "yes" in START_COLLECTD.lower():
        start_collectd()
    if "yes" in START_BEATS.lower():
        start_beats()

if 'v' in VSPERF_TEST:
    if len(SANITY_CHECK_DONE_LIST) != 4:
        print("Certain Sanity Checks Failed\n" \
              "You can make changes based on the outputs and run" \
              "the testcontrol auto container again")
    else:
        run_vsperf_test()
        test_status()
else:
    if len(SANITY_CHECK_DONE_LIST) != 3:
        print("Certain Sanity Checks Failed\n" \
              "You can make changes based on the outputs and run" \
              "the testcontrol auto container again")
    else:
        run_vsperf_test()
        test_status()


if "yes" in CLEAN_UP.lower():
    vsperf_remove()
    remove_uploaded_config()
    result_folders_remove()
    collectd_remove()
    terminate_vsperf()