Add iperf3 support

Change-Id: Ic4d6751e749b37c7e312f1db8e2cd980c477bc46
This commit is contained in:
Ilya Shakhat 2015-07-30 19:38:17 +03:00
parent e3c57b34fa
commit 6cc4a185db
11 changed files with 345 additions and 141 deletions

View File

@ -75,11 +75,12 @@ simultaneously on all available agents. The level of concurrency can be controll
Tests are executed in order of definition. The exact action is defined by option ``class``, additional attributes are provided
by respective parameters. The following classes are available:
* ``iperf_graph`` - runs ``iperf`` tool and shows chart and statistics
* ``iperf3`` - runs ``iperf3`` tool and shows chart and statistics
* ``flent`` - runs ``flent`` (http://flent.org) and shows chart and statistics
* ``iperf`` - runs ``iperf`` tool and shows plain output
* ``netperf`` - runs ``netpers`` tool and shows plain output
* ``shell`` - runs any shell command or process and shows plain output
* ``iperf_graph`` - runs ``iperf`` tool and shows chart and statistics (deprecated)
Test classes
^^^^^^^^^^^^

View File

@ -19,6 +19,7 @@ from shaker.engine.aggregators import traffic
AGGREGATORS = {
'iperf_graph': traffic.TrafficAggregator,
'iperf3': traffic.TrafficAggregator,
'netperf_wrapper': traffic.TrafficAggregator,
'flent': traffic.TrafficAggregator,
'_default': base.BaseAggregator,

View File

@ -24,6 +24,7 @@ EXECUTORS = {
'netperf': netperf.NetperfExecutor,
'iperf': iperf.IperfExecutor,
'iperf_graph': iperf.IperfGraphExecutor,
'iperf3': iperf.Iperf3Executor,
'netperf_wrapper': netperf.NetperfWrapperExecutor,
'flent': flent.FlentExecutor,
'_default': shell.ShellExecutor,

View File

@ -14,32 +14,38 @@
# limitations under the License.
import csv
import json
import yaml
from shaker.engine.executors import base
def add_common_iperf_params(cmd, executor):
cmd.add('--client', executor.agent['slave']['ip'])
cmd.add('--format', 'm')
if executor.test_definition.get('mss'):
cmd.add('--mss', executor.test_definition.get('mss'))
if executor.test_definition.get('buffer_size'):
cmd.add('--len', executor.test_definition.get('buffer_size'))
if executor.test_definition.get('udp'):
cmd.add('--udp')
if executor.test_definition.get('bandwidth'):
cmd.add('--bandwidth', executor.test_definition.get('bandwidth'))
if executor.test_definition.get('datagram_size'):
cmd.add('--len', executor.test_definition.get('datagram_size'))
cmd.add('--time', executor.get_expected_duration())
cmd.add('--parallel', executor.test_definition.get('threads') or 1)
if executor.test_definition.get('interval'):
cmd.add('--interval', executor.test_definition.get('interval'))
class IperfExecutor(base.BaseExecutor):
def get_command(self):
cmd = base.CommandLine('sudo nice -n -20 iperf')
cmd.add('--client', self.agent['slave']['ip'])
cmd.add('--format', 'm')
add_common_iperf_params(cmd, self)
cmd.add('--nodelay')
if self.test_definition.get('mss'):
cmd.add('--mss', self.test_definition.get('mss'))
if self.test_definition.get('buffer_size'):
cmd.add('--len', self.test_definition.get('buffer_size'))
if self.test_definition.get('udp'):
cmd.add('--udp')
if self.test_definition.get('bandwidth'):
cmd.add('--bandwidth', self.test_definition.get('bandwidth'))
if self.test_definition.get('datagram_size'):
cmd.add('--len', self.test_definition.get('datagram_size'))
cmd.add('--time', self.get_expected_duration())
cmd.add('--parallel', self.test_definition.get('threads') or 1)
if self.test_definition.get('csv'):
cmd.add('--reportstyle', 'C')
if self.test_definition.get('interval'):
cmd.add('--interval', self.test_definition.get('interval'))
return cmd.make()
@ -74,3 +80,46 @@ class IperfGraphExecutor(IperfExecutor):
result['samples'] = samples
result['meta'] = [['time', 's'], ['bandwidth', 'bit/s']]
return result
class Iperf3Executor(base.BaseExecutor):
def get_command(self):
if not self.test_definition.get('interval'):
self.test_definition['interval'] = 1
cmd = base.CommandLine('sudo nice -n -20 iperf3')
add_common_iperf_params(cmd, self)
cmd.add('--json')
return cmd.make()
def process_reply(self, message):
result = super(Iperf3Executor, self).process_reply(message)
if not result['stdout']:
raise base.ExecutorException(result, 'Empty result from iperf')
data = json.loads(result['stdout'])
# store verbose data in result
result['verbose'] = yaml.safe_dump(
dict(start=data['start'], end=data['end']),
indent=2, default_flow_style=False)
if 'error' in data:
raise base.ExecutorException(result, data['error'])
if self.test_definition.get('udp'):
sampler = lambda p: [round(p['end'], 2), p['packets']]
meta = [['time', 's'], ['packets', 'pps']]
else:
sampler = lambda p: [round(p['end'], 2), p['bits_per_second'],
p['retransmits']]
meta = [['time', 's'], ['bandwidth', 'bit/s'], ['retransmits', '']]
samples = []
for point in data['intervals']:
samples.append(sampler(point['sum']))
result['samples'] = samples
result['meta'] = meta
return result

View File

@ -71,9 +71,12 @@ resources:
wget -O get-pip.py https://bootstrap.pypa.io/get-pip.py && sudo python get-pip.py
sudo pip install -U "pip<7.0"
sudo pip install pbr netperf-wrapper flent pyshaker-agent
sudo apt-add-repository "deb http://ftp.debian.org/debian/ jessie main" && sudo apt-get update
sudo apt-get -y --force-yes install iperf3
echo -e 'start on startup\ntask\nexec /usr/bin/screen -dmS sudo nice -n -20 /usr/bin/iperf -s' | sudo tee /etc/init/iperf-tcp.conf
echo -e 'start on startup\ntask\nexec /usr/bin/screen -dmS sudo nice -n -20 /usr/bin/iperf -s --udp' | sudo tee /etc/init/iperf-udp.conf
sudo shutdown -P -f now
echo -e 'start on startup\ntask\nexec /usr/bin/screen -dmS sudo nice -n -20 /usr/bin/iperf3 -s' | sudo tee /etc/init/iperf3.conf
sudo shutdown -P now
outputs:
server_info:

View File

@ -173,6 +173,7 @@
{record: $.extend({}, record, ext_options)}
));
if (record["chart"]) {
var meta = record["meta"];
c3.generate({
bindto: "#" + chart_id,
data: {
@ -181,8 +182,8 @@
types: {y: 'area'}
},
axis: {
x: {label: 'time, s'},
y: {label: 'Bandwidth, Mbit/s', min: 0}
x: {label: meta[0][0] + ", " + meta[0][1]},
y: {label: meta[1][0] + ", " + meta[1][1], min: 0}
}
});
}
@ -493,6 +494,10 @@
<h4>Stdout</h4>
<pre>{{ stdout }}</pre>
{{/if}}
{{#if verbose}}
<h4>Verbose Info</h4>
<pre>{{ verbose }}</pre>
{{/if}}
{{#if stderr}}
<h4>Stderr</h4>
<pre>{{ stderr }}</pre>

View File

@ -11,7 +11,7 @@ execution:
tests:
-
title: Iperf UDP
class: iperf
udp: 1
threads: 8
class: iperf3
udp: on
bandwidth: 1000M
datagram_size: 32

View File

@ -11,7 +11,7 @@ execution:
tests:
-
title: Iperf UDP
class: iperf
udp: 1
threads: 2
class: iperf3
udp: on
bandwidth: 1000M
datagram_size: 32

View File

@ -12,7 +12,7 @@ execution:
tests:
-
title: Iperf UDP
class: iperf
udp: 1
threads: 2
class: iperf3
udp: on
bandwidth: 1000M
datagram_size: 32

View File

@ -0,0 +1,256 @@
# Copyright (c) 2015 Mirantis Inc.
#
# 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 testtools
from shaker.engine.executors import base
from shaker.engine.executors import iperf
IP = '10.0.0.10'
AGENT = {'slave': {'ip': IP}}
class TestIperfGraphExecutor(testtools.TestCase):
def test_get_command(self):
executor = iperf.IperfGraphExecutor({}, AGENT)
expected = {'data': ('sudo nice -n -20 iperf --client %s --format m '
'--time 60 --parallel 1 --interval 1 --nodelay '
'--reportstyle C') % IP,
'type': 'program'}
self.assertEqual(expected, executor.get_command())
def test_get_command_udp(self):
executor = iperf.IperfGraphExecutor(
{'udp': True, 'bandwidth': '100M', 'time': 30,
'datagram_size': 1470}, AGENT)
expected = {'data': ('sudo nice -n -20 iperf --client %s --format m '
'--udp --bandwidth 100M --len 1470 '
'--time 30 --parallel 1 --interval 1 --nodelay '
'--reportstyle C') % IP,
'type': 'program'}
self.assertEqual(expected, executor.get_command())
def test_process_reply(self):
executor = iperf.IperfGraphExecutor({}, AGENT)
message = {
'stdout': """
20150224134955,172.1.7.77,47351,172.1.76.77,5001,3,0.0-1.0,50068684,399507456
20150224134956,172.1.7.77,47351,172.1.76.77,5001,3,1.0-2.0,51605504,412090368
20150224134957,172.1.7.77,47351,172.1.76.77,5001,3,2.0-3.0,50843648,405798912
20150224134957,172.1.7.77,47351,172.1.76.77,5001,3,0.0-3.0,150843648,400000002
"""
}
expected = {
'samples': [
[1.0, 399507456],
[2.0, 412090368],
[3.0, 405798912],
],
'meta': [
['time', 's'], ['bandwidth', 'bit/s']
]
}
reply = executor.process_reply(message)
self.assertEqual(expected['samples'], reply['samples'],
message='Samples data')
self.assertEqual(expected['meta'], reply['meta'],
message='Metadata')
def test_process_reply_multiple_threads(self):
executor = iperf.IperfGraphExecutor({'threads': 2}, AGENT)
message = {
'stdout': """
20150610102341,10.0.0.3,53479,10.0.0.2,5001,4,0.0-1.0,30277632,242221056
20150610102341,10.0.0.3,53478,10.0.0.2,5001,3,0.0-1.0,23461888,187695104
20150610102341,10.0.0.3,0,10.0.0.2,5001,-1,0.0-1.0,53739520,429916160
20150610102342,10.0.0.3,53479,10.0.0.2,5001,4,1.0-2.0,41418752,331350016
20150610102342,10.0.0.3,53478,10.0.0.2,5001,3,1.0-2.0,22806528,182452224
20150610102342,10.0.0.3,53478,10.0.0.2,5001,3,0.0-2.0,46268416,370147328
20150610102342,10.0.0.3,0,10.0.0.2,5001,-1,1.0-2.0,64225280,513802240
20150610102440,10.0.0.3,53479,10.0.0.2,5001,4,0.0-2.0,71696384,573571072
20150610102440,10.0.0.3,0,10.0.0.2,5001,-1,0.0-2.0,117964800,479810974\n
"""
}
expected = {
'samples': [
[1.0, 429916160],
[2.0, 513802240],
],
'meta': [
['time', 's'], ['bandwidth', 'bit/s']
]
}
reply = executor.process_reply(message)
self.assertEqual(expected['samples'], reply['samples'],
message='Samples data')
self.assertEqual(expected['meta'], reply['meta'],
message='Metadata')
def test_process_empty_reply(self):
executor = iperf.IperfGraphExecutor({}, AGENT)
message = {
'stdout': '',
'stderr': 'Error!',
}
self.assertRaises(
base.ExecutorException, executor.process_reply, message)
class TestIperf3Executor(testtools.TestCase):
def test_get_command(self):
executor = iperf.Iperf3Executor({}, AGENT)
expected = {'data': ('sudo nice -n -20 iperf3 --client %s --format m '
'--time 60 --parallel 1 --interval 1 '
'--json') % IP,
'type': 'program'}
self.assertEqual(expected, executor.get_command())
def test_get_command_udp(self):
executor = iperf.Iperf3Executor(
{'udp': True, 'bandwidth': '100M', 'time': 30,
'datagram_size': 1470}, AGENT)
expected = {'data': ('sudo nice -n -20 iperf3 --client %s --format m '
'--udp --bandwidth 100M --len 1470 '
'--time 30 --parallel 1 --interval 1 '
'--json') % IP,
'type': 'program'}
self.assertEqual(expected, executor.get_command())
def test_process_reply_tcp(self):
executor = iperf.Iperf3Executor({}, AGENT)
message = {
'stdout': """
{
"start": {},
"intervals": [
{
"streams": [],
"sum": {
"start": 0,
"end": 1.00002,
"seconds": 1.00002,
"bytes": 1712000,
"bits_per_second": 1.36958e+07,
"retransmits": 0
}
},
{
"streams": [],
"sum": {
"start": 1.00002,
"end": 2.00001,
"seconds": 0.999995,
"bytes": 2043392,
"bits_per_second": 1.63472e+07,
"retransmits": 1
}
},
{
"streams": [],
"sum": {
"start": 2.00001,
"end": 3.00002,
"seconds": 1,
"bytes": 2015872,
"bits_per_second": 1.61269e+07,
"retransmits": 0
}
}
],
"end": {}
}"""
}
expected = {
'samples': [
[1.0, 13695800.0, 0],
[2.0, 16347200.0, 1],
[3.0, 16126900.0, 0],
],
'meta': [
['time', 's'], ['bandwidth', 'bit/s'], ['retransmits', '']
]
}
reply = executor.process_reply(message)
self.assertEqual(expected['samples'], reply['samples'],
message='Samples data')
self.assertEqual(expected['meta'], reply['meta'],
message='Metadata')
def test_process_reply_udp(self):
executor = iperf.Iperf3Executor({'udp': True}, AGENT)
message = {
'stdout': """
{
"start": {},
"intervals": [
{
"streams": [],
"sum": {
"start": 0,
"end": 1.00002,
"seconds": 1.00002,
"bytes": 1712000,
"bits_per_second": 1.36958e+07,
"packets": 53500
}
},
{
"streams": [],
"sum": {
"start": 1.00002,
"end": 2.00001,
"seconds": 0.999995,
"bytes": 2043392,
"bits_per_second": 1.63472e+07,
"packets": 63856
}
},
{
"streams": [],
"sum": {
"start": 2.00001,
"end": 3.00002,
"seconds": 1,
"bytes": 2015872,
"bits_per_second": 1.61269e+07,
"packets": 62996
}
}
],
"end": {}
}"""
}
expected = {
'samples': [
[1.0, 53500],
[2.0, 63856],
[3.0, 62996],
],
'meta': [
['time', 's'], ['packets', 'pps']
]
}
reply = executor.process_reply(message)
self.assertEqual(expected['samples'], reply['samples'],
message='Samples data')
self.assertEqual(expected['meta'], reply['meta'],
message='Metadata')

View File

@ -1,112 +0,0 @@
# Copyright (c) 2015 Mirantis Inc.
#
# 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 testtools
from shaker.engine.executors import base
from shaker.engine.executors import iperf
IP = '10.0.0.10'
AGENT = {'slave': {'ip': IP}}
class TestIperfGraphExecutor(testtools.TestCase):
def test_get_command(self):
executor = iperf.IperfGraphExecutor({}, AGENT)
expected = {'data': ('sudo nice -n -20 iperf --client %s --format m '
'--nodelay --time 60 --parallel 1 '
'--reportstyle C --interval 1') % IP,
'type': 'program'}
self.assertEqual(expected, executor.get_command())
def test_get_command_udp(self):
executor = iperf.IperfGraphExecutor(
{'udp': True, 'bandwidth': '100M', 'time': 30,
'datagram_size': 1470}, AGENT)
expected = {'data': ('sudo nice -n -20 iperf --client %s --format m '
'--nodelay --udp --bandwidth 100M --len 1470 '
'--time 30 --parallel 1 '
'--reportstyle C --interval 1') % IP,
'type': 'program'}
self.assertEqual(expected, executor.get_command())
def test_process_reply(self):
executor = iperf.IperfGraphExecutor({}, AGENT)
message = {
'stdout': """
20150224134955,172.1.7.77,47351,172.1.76.77,5001,3,0.0-1.0,50068684,399507456
20150224134956,172.1.7.77,47351,172.1.76.77,5001,3,1.0-2.0,51605504,412090368
20150224134957,172.1.7.77,47351,172.1.76.77,5001,3,2.0-3.0,50843648,405798912
20150224134957,172.1.7.77,47351,172.1.76.77,5001,3,0.0-3.0,150843648,400000002
"""
}
expected = {
'samples': [
[1.0, 399507456],
[2.0, 412090368],
[3.0, 405798912],
],
'meta': [
['time', 's'], ['bandwidth', 'bit/s']
]
}
reply = executor.process_reply(message)
self.assertEqual(expected['samples'], reply['samples'],
message='Samples data')
self.assertEqual(expected['meta'], reply['meta'],
message='Metadata')
def test_process_reply_multiple_threads(self):
executor = iperf.IperfGraphExecutor({'threads': 2}, AGENT)
message = {
'stdout': """
20150610102341,10.0.0.3,53479,10.0.0.2,5001,4,0.0-1.0,30277632,242221056
20150610102341,10.0.0.3,53478,10.0.0.2,5001,3,0.0-1.0,23461888,187695104
20150610102341,10.0.0.3,0,10.0.0.2,5001,-1,0.0-1.0,53739520,429916160
20150610102342,10.0.0.3,53479,10.0.0.2,5001,4,1.0-2.0,41418752,331350016
20150610102342,10.0.0.3,53478,10.0.0.2,5001,3,1.0-2.0,22806528,182452224
20150610102342,10.0.0.3,53478,10.0.0.2,5001,3,0.0-2.0,46268416,370147328
20150610102342,10.0.0.3,0,10.0.0.2,5001,-1,1.0-2.0,64225280,513802240
20150610102440,10.0.0.3,53479,10.0.0.2,5001,4,0.0-2.0,71696384,573571072
20150610102440,10.0.0.3,0,10.0.0.2,5001,-1,0.0-2.0,117964800,479810974\n
"""
}
expected = {
'samples': [
[1.0, 429916160],
[2.0, 513802240],
],
'meta': [
['time', 's'], ['bandwidth', 'bit/s']
]
}
reply = executor.process_reply(message)
self.assertEqual(expected['samples'], reply['samples'],
message='Samples data')
self.assertEqual(expected['meta'], reply['meta'],
message='Metadata')
def test_process_empty_reply(self):
executor = iperf.IperfGraphExecutor({}, AGENT)
message = {
'stdout': '',
'stderr': 'Error!',
}
self.assertRaises(
base.ExecutorException, executor.process_reply, message)