Add support for flent tool

Flent (http://flent.org/) is new version of netperf-wrapper.

Change-Id: Ib010cad688c2398bd2c146ca06f73fdc764d4a91
This commit is contained in:
Ilya Shakhat 2015-05-28 16:22:30 +03:00
parent 5104f6a4eb
commit e2e6483177
12 changed files with 197 additions and 19 deletions

View File

@ -22,9 +22,9 @@ execution:
bandwidth: 1000M bandwidth: 1000M
- -
title: TCP download title: TCP download
class: netperf_wrapper class: flent
method: tcp_download method: tcp_download
- -
title: TCP bi-directional title: TCP bi-directional
class: netperf_wrapper class: flent
method: tcp_bidirectional method: tcp_bidirectional

View File

@ -21,9 +21,9 @@ execution:
bandwidth: 1000M bandwidth: 1000M
- -
title: TCP download title: TCP download
class: netperf_wrapper class: flent
method: tcp_download method: tcp_download
- -
title: TCP bi-directional title: TCP bi-directional
class: netperf_wrapper class: flent
method: tcp_bidirectional method: tcp_bidirectional

View File

@ -22,9 +22,9 @@ execution:
bandwidth: 1000M bandwidth: 1000M
- -
title: TCP download title: TCP download
class: netperf_wrapper class: flent
method: tcp_download method: tcp_download
- -
title: TCP bi-directional title: TCP bi-directional
class: netperf_wrapper class: flent
method: tcp_bidirectional method: tcp_bidirectional

View File

@ -21,9 +21,9 @@ execution:
bandwidth: 1000M bandwidth: 1000M
- -
title: TCP download title: TCP download
class: netperf_wrapper class: flent
method: tcp_download method: tcp_download
- -
title: TCP bi-directional title: TCP bi-directional
class: netperf_wrapper class: flent
method: tcp_bidirectional method: tcp_bidirectional

View File

@ -21,9 +21,9 @@ execution:
bandwidth: 1000M bandwidth: 1000M
- -
title: TCP download title: TCP download
class: netperf_wrapper class: flent
method: tcp_download method: tcp_download
- -
title: TCP bi-directional title: TCP bi-directional
class: netperf_wrapper class: flent
method: tcp_bidirectional method: tcp_bidirectional

View File

@ -22,9 +22,9 @@ execution:
bandwidth: 1000M bandwidth: 1000M
- -
title: TCP download title: TCP download
class: netperf_wrapper class: flent
method: tcp_download method: tcp_download
- -
title: TCP bi-directional title: TCP bi-directional
class: netperf_wrapper class: flent
method: tcp_bidirectional method: tcp_bidirectional

View File

@ -72,7 +72,7 @@ def run_command(command):
fd = tempfile.mkstemp() fd = tempfile.mkstemp()
os.write(fd[0], command['data']) os.write(fd[0], command['data'])
os.close(fd[0]) os.close(fd[0])
LOG.debug('stored script into %s', fd[1]) LOG.debug('Stored script into %s', fd[1])
command_stdout, command_stderr = processutils.execute( command_stdout, command_stderr = processutils.execute(
*shlex.split('bash %s' % fd[1]), check_exit_code=False) *shlex.split('bash %s' % fd[1]), check_exit_code=False)

View File

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

View File

@ -23,19 +23,23 @@ from shaker.engine.aggregators import base
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
def _filter_none(array):
return [x for x in array if x]
def mean(array): def mean(array):
if not array: s = _filter_none(array)
return 0 return sum(s) / len(s) if s else 0
array = [x for x in array if x]
return sum(array) / len(array)
def safe_max(array): def safe_max(array):
return max(x for x in array if x) s = _filter_none(array)
return max(s) if s else None
def safe_min(array): def safe_min(array):
return min(x for x in array if x) s = _filter_none(array)
return min(s) if s else None
class TrafficAggregator(base.BaseAggregator): class TrafficAggregator(base.BaseAggregator):

View File

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from shaker.engine.executors import flent
from shaker.engine.executors import iperf from shaker.engine.executors import iperf
from shaker.engine.executors import netperf from shaker.engine.executors import netperf
from shaker.engine.executors import shell from shaker.engine.executors import shell
@ -24,6 +25,7 @@ EXECUTORS = {
'iperf': iperf.IperfExecutor, 'iperf': iperf.IperfExecutor,
'iperf_graph': iperf.IperfGraphExecutor, 'iperf_graph': iperf.IperfGraphExecutor,
'netperf_wrapper': netperf.NetperfWrapperExecutor, 'netperf_wrapper': netperf.NetperfWrapperExecutor,
'flent': flent.FlentExecutor,
'_default': shell.ShellExecutor, '_default': shell.ShellExecutor,
} }

View File

@ -0,0 +1,63 @@
# 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 json
from shaker.engine.executors import base
FLENT_EXEC = 'zcat `%s 2>&1 | grep "se with" | grep -Po \'/\\S+\'`'
FLENT_EXTRA_TIME = 10 # by default flent adds by 5 secs before and after run
class FlentExecutor(base.BaseExecutor):
def get_command(self):
cmd = base.CommandLine('flent')
cmd.add('-H', self.agent['slave']['ip'])
cmd.add('-l', self.test_definition.get('time') or 60)
cmd.add('-s', self.test_definition.get('interval') or 1)
cmd.add(self.test_definition.get('method') or 'tcp_download')
flent_cmd = cmd.make()
return base.Script(FLENT_EXEC % flent_cmd['data']).make()
def get_expected_duration(self):
return (super(FlentExecutor, self).get_expected_duration() +
FLENT_EXTRA_TIME)
def process_reply(self, message):
result = super(FlentExecutor, self).process_reply(message)
stdout = result['stdout']
if not stdout:
raise base.ExecutorException(result, 'Empty result from flent')
data = json.loads(stdout)
series_meta = data['metadata']['SERIES_META']
columns = sorted(series_meta.keys())
meta = ([['time', 's']] +
[[k, series_meta[k]['UNITS']] for k in columns])
samples = []
for i in range(int(data['metadata']['TOTAL_LENGTH'])):
line = [data['x_values'][i]]
for el in columns:
line.append(data['results'][el][i])
samples.append(line)
result['meta'] = meta
result['samples'] = samples
return result

View File

@ -0,0 +1,108 @@
# 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 flent
IP = '10.0.0.10'
AGENT = {'slave': {'ip': IP}}
class TestFlentExecutor(testtools.TestCase):
def test_get_command(self):
executor = flent.FlentExecutor({}, AGENT)
expected = {'data': (flent.FLENT_EXEC % 'flent -H %s -l 60 -s 1 '
'tcp_download') % IP,
'type': 'script'}
self.assertEqual(expected, executor.get_command())
def test_get_command_with_params(self):
executor = flent.FlentExecutor(
dict(method='ping', time=10, interval=0.5), AGENT)
expected = {'data': (flent.FLENT_EXEC % 'flent -H %s -l 10 -s 0.5 '
'ping') % IP,
'type': 'script'}
self.assertEqual(expected, executor.get_command())
def test_get_expected_duration(self):
executor = flent.FlentExecutor(dict(method='ping', time=10), AGENT)
expected = 20
self.assertEqual(expected, executor.get_expected_duration())
def test_process_reply(self):
executor = flent.FlentExecutor({}, AGENT)
message = {
'stdout': """
{
"metadata": {
"SERIES_META": {
"Ping ICMP": {
"UNITS": "ms"
},
"TCP upload": {
"MEAN_VALUE": 14536.94,
"UNITS": "Mbps"
}
},
"TOTAL_LENGTH": 5
},
"results": {
"Ping ICMP": [
0.11,
0.08003925186913663,
0.08997269229670403,
0.07008327936919093,
0.07994293923635702
],
"TCP upload": [
null,
9789.93,
17333.075575393304,
18173.561165616233,
null
]
},
"x_values": [
0.0,
0.2,
0.4,
0.6000000000000001,
0.8
]
}
"""
}
expected = {
'samples': [
[0.0, 0.11, None],
[0.2, 0.08003925186913663, 9789.93],
[0.4, 0.08997269229670403, 17333.075575393304],
[0.6000000000000001, 0.07008327936919093, 18173.561165616233],
[0.8, 0.07994293923635702, None]
],
'meta': [
['time', 's'], ['Ping ICMP', 'ms'], ['TCP upload', 'Mbps'],
]
}
reply = executor.process_reply(message)
self.assertEqual(expected['samples'], reply['samples'],
message='Samples data')
self.assertEqual(expected['meta'], reply['meta'],
message='Metadata')