Merge "Add API(v2) to delete pod"
[yardstick.git] / yardstick / benchmark / scenarios / networking / iperf3.py
1 ##############################################################################
2 # Copyright (c) 2015 Ericsson AB and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 # iperf3 scenario
11 # iperf3 homepage at: http://software.es.net/iperf/
12
13 from __future__ import absolute_import
14 from __future__ import print_function
15
16 import logging
17
18 import pkg_resources
19 from oslo_serialization import jsonutils
20
21 import yardstick.ssh as ssh
22 from yardstick.common import utils
23 from yardstick.benchmark.scenarios import base
24
25 LOG = logging.getLogger(__name__)
26
27
28 class Iperf(base.Scenario):
29     """Execute iperf3 between two hosts
30
31 By default TCP is used but UDP can also be configured.
32 For more info see http://software.es.net/iperf
33
34   Parameters
35     bytes - number of bytes to transmit
36       only valid with a non duration runner, mutually exclusive with blockcount
37         type:    int
38         unit:    bytes
39         default: 56
40     udp - use UDP rather than TCP
41         type:    bool
42         unit:    na
43         default: false
44     nodelay - set TCP no delay, disabling Nagle's Algorithm
45         type:    bool
46         unit:    na
47         default: false
48     blockcount - number of blocks (packets) to transmit,
49       only valid with a non duration runner, mutually exclusive with bytes
50         type:    int
51         unit:    bytes
52         default: -
53     """
54     __scenario_type__ = "Iperf3"
55
56     def __init__(self, scenario_cfg, context_cfg):
57         self.scenario_cfg = scenario_cfg
58         self.context_cfg = context_cfg
59         self.setup_done = False
60
61     def setup(self):
62         host = self.context_cfg['host']
63         target = self.context_cfg['target']
64
65         LOG.info("user:%s, target:%s", target['user'], target['ip'])
66         self.target = ssh.SSH.from_node(target, defaults={"user": "ubuntu"})
67         self.target.wait(timeout=600)
68
69         LOG.info("user:%s, host:%s", host['user'], host['ip'])
70         self.host = ssh.SSH.from_node(host, defaults={"user": "ubuntu"})
71         self.host.wait(timeout=600)
72
73         cmd = "iperf3 -s -D"
74         LOG.debug("Starting iperf3 server with command: %s", cmd)
75         status, _, stderr = self.target.execute(cmd)
76         if status:
77             raise RuntimeError(stderr)
78
79         self.setup_done = True
80
81     def teardown(self):
82         LOG.debug("teardown")
83         self.host.close()
84         status, stdout, stderr = self.target.execute("pkill iperf3")
85         if status:
86             LOG.warning(stderr)
87         self.target.close()
88
89     def run(self, result):
90         """execute the benchmark"""
91         if not self.setup_done:
92             self.setup()
93
94         # if run by a duration runner, get the duration time and setup as arg
95         time = self.scenario_cfg["runner"].get("duration", None) \
96             if "runner" in self.scenario_cfg else None
97         options = self.scenario_cfg['options']
98
99         cmd = "iperf3 -c %s --json" % (self.context_cfg['target']['ipaddr'])
100
101         # If there are no options specified
102         if not options:
103             options = ""
104
105         use_UDP = False
106         if "udp" in options:
107             cmd += " --udp"
108             use_UDP = True
109             if "bandwidth" in options:
110                 cmd += " --bandwidth %s" % options["bandwidth"]
111         else:
112             # tcp obviously
113             if "nodelay" in options:
114                 cmd += " --nodelay"
115
116         # these options are mutually exclusive in iperf3
117         if time:
118             cmd += " %d" % time
119         elif "bytes" in options:
120             # number of bytes to transmit (instead of --time)
121             cmd += " --bytes %d" % options["bytes"]
122         elif "blockcount" in options:
123             cmd += " --blockcount %d" % options["blockcount"]
124
125         LOG.debug("Executing command: %s", cmd)
126
127         status, stdout, stderr = self.host.execute(cmd)
128         if status:
129             # error cause in json dict on stdout
130             raise RuntimeError(stdout)
131
132         # Note: convert all ints to floats in order to avoid
133         # schema conflicts in influxdb. We probably should add
134         # a format func in the future.
135         iperf_result = jsonutils.loads(stdout, parse_int=float)
136         result.update(utils.flatten_dict_key(iperf_result))
137
138         if "sla" in self.scenario_cfg:
139             sla_iperf = self.scenario_cfg["sla"]
140             if not use_UDP:
141                 sla_bytes_per_second = int(sla_iperf["bytes_per_second"])
142
143                 # convert bits per second to bytes per second
144                 bit_per_second = \
145                     int(iperf_result["end"]["sum_received"]["bits_per_second"])
146                 bytes_per_second = bit_per_second / 8
147                 assert bytes_per_second >= sla_bytes_per_second, \
148                     "bytes_per_second %d < sla:bytes_per_second (%d); " % \
149                     (bytes_per_second, sla_bytes_per_second)
150             else:
151                 sla_jitter = float(sla_iperf["jitter"])
152
153                 jitter_ms = float(iperf_result["end"]["sum"]["jitter_ms"])
154                 assert jitter_ms <= sla_jitter, \
155                     "jitter_ms  %f > sla:jitter %f; " % \
156                     (jitter_ms, sla_jitter)
157
158
159 def _test():
160     """internal test function"""
161     key_filename = pkg_resources.resource_filename('yardstick.resources',
162                                                    'files/yardstick_key')
163     ctx = {
164         'host': {
165             'ip': '10.229.47.137',
166             'user': 'root',
167             'key_filename': key_filename
168         },
169         'target': {
170             'ip': '10.229.47.137',
171             'user': 'root',
172             'key_filename': key_filename,
173             'ipaddr': '10.229.47.137',
174         }
175     }
176
177     logger = logging.getLogger('yardstick')
178     logger.setLevel(logging.DEBUG)
179
180     options = {'packetsize': 120}
181     args = {'options': options}
182     result = {}
183
184     p = Iperf(args, ctx)
185     p.run(result)
186     print(result)
187
188
189 if __name__ == '__main__':
190     _test()