From f7d9a2b058fba82d51a6fde4ce399e92a7b8830f Mon Sep 17 00:00:00 2001 From: Adam Israel Date: Thu, 10 Nov 2016 11:20:46 -0500 Subject: [PATCH] Add initial support for iperf3, both in client and server modes. Signed-off-by: Adam Israel --- layers/netutils/README.md | 10 +++ layers/netutils/actions.yaml | 86 ++++++++++++++++++++++ layers/netutils/actions/iperf | 18 +++++ layers/netutils/config.yaml | 5 ++ layers/netutils/reactive/layer_netutils.py | 48 +++++++++++- 5 files changed, 163 insertions(+), 4 deletions(-) create mode 100755 layers/netutils/actions/iperf create mode 100644 layers/netutils/config.yaml diff --git a/layers/netutils/README.md b/layers/netutils/README.md index 525c2d7b..e8258c03 100644 --- a/layers/netutils/README.md +++ b/layers/netutils/README.md @@ -38,6 +38,16 @@ timing: enqueued: 2016-06-29 14:50:03 +0000 UTC started: 2016-06-29 14:50:03 +0000 UTC ``` +## iperf3 + +Because iperf3 has a client and server component, the netutils charm can operate +as both. Setting the iperf3 configuration value to True will start iperf3 in +server mode, running as a daemon. +``` +$ juju deploy cs:~nfv/netutils client +$ juju deploy cs:~nfv/netutils server iperf3=True +$ juju run-action client/0 iperf host= [...] +``` ## Scale out Usage diff --git a/layers/netutils/actions.yaml b/layers/netutils/actions.yaml index 5c99e21c..f4f78843 100644 --- a/layers/netutils/actions.yaml +++ b/layers/netutils/actions.yaml @@ -44,4 +44,90 @@ dig: type: string required: - host +iperf: + description: "" + params: + host: + description: "" + type: string + port: + description: "" + type: integer + default: 5201 + format: + description: "" + type: string + interval: + description: "" + type: string + affinity: + description: "" + type: string + udp: + description: "Use UDP rather than TCP" + type: boolean + default: False + bandwidth: + description: "Set the target bandwidth to n bits/sec (default 1Mbit/sec for UDP, unlimited for TCP)" + type: integer + default: 1 + time: + description: "Time, in seconds, to transmit for." + type: integer + default: 10 + blockcount: + description: "The number of blocks to transmit" + type: integer + length: + description: "The length of buffer to read or write (default 128KB for TCP, 8KB for UDP)" + type: integer + parallel: + description: "The number of parallel client streams to run" + type: integer + reverse: + description: "Run in reverse mode (server sends, client receives)." + type: boolean + default: false + window: + description: "Window size/socket buffer size." + type: integer + bind: + description: "Bind to a specific interface or multicast address" + type: string + mss: + description: "Set the TCP maximum segment size (MTU - 40 bytes)" + type: integer + no-delay: + description: "Set the TCP no delay, disabling Nagle's algorithm." + type: boolean + default: false + ipv4: + description: "Only use IPv4" + type: boolean + default: false + ipv6: + description: "Only use IPv6" + type: boolean + default: false + tos: + description: "Set the IP 'type of service'" + type: integer + flowlabel: + description: "Set the IPv6 flow label (linux-only)" + type: string + zerocopy: + description: "Use a 'zero copy' method of sending data, such as sendfile(s), instead of the usual write(2)." + type: boolean + default: false + omit: + description: "Omit the first n seconds of the test, to skip past the TCP slow-start period." + type: integer + title: + description: "Prefix every output line with this string." + type: string + congestion: + description: "Set the linux congestion control algorithm." + type: string + required: + - host diff --git a/layers/netutils/actions/iperf b/layers/netutils/actions/iperf new file mode 100755 index 00000000..750028e0 --- /dev/null +++ b/layers/netutils/actions/iperf @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +import sys +sys.path.append('lib') + +from charms.reactive import main +from charms.reactive import set_state +from charmhelpers.core.hookenv import action_fail + +""" +`set_state` only works here because it's flushed to disk inside the `main()` +loop. remove_state will need to be called inside the action method. +""" +set_state('actions.iperf3') + +try: + main() +except Exception as e: + action_fail(repr(e)) diff --git a/layers/netutils/config.yaml b/layers/netutils/config.yaml new file mode 100644 index 00000000..61010636 --- /dev/null +++ b/layers/netutils/config.yaml @@ -0,0 +1,5 @@ +options: + iperf3: + type: boolean + default: false + description: "Enabling this option will start iperf3 in server mode." diff --git a/layers/netutils/reactive/layer_netutils.py b/layers/netutils/reactive/layer_netutils.py index 697e83c9..1fd4cb24 100644 --- a/layers/netutils/reactive/layer_netutils.py +++ b/layers/netutils/reactive/layer_netutils.py @@ -1,17 +1,20 @@ from charmhelpers.core.hookenv import ( - status_set, action_get, - action_set, action_fail, + action_set, + config, + log, + status_set, ) from charms.reactive import ( + remove_state as remove_flag, + set_state as set_flag, when, when_not, - set_state as set_flag, - remove_state as remove_flag, ) import charms.sshproxy +from subprocess import CalledProcessError @when_not('netutils.ready') @@ -95,3 +98,40 @@ def traceroute(): action_set({'output': result}) finally: remove_flag('actions.traceroute') + + +@when('actions.iperf3') +def iperf3(): + err = '' + try: + # TODO: read all the flags via action_get and build the + # proper command line to run iperf3 + host = action_get('host') + + cmd = 'iperf3 -c {} --json'.format(host) + result, err = charms.sshproxy._run(cmd) + except CalledProcessError as e: + action_fail('iperf3 command failed:' + e.output) + else: + action_set({'outout': result}) + finally: + remove_flag('actions.iperf3') + + +@when('config.changed') +def config_changed(): + """ Handle configuration changes """ + cfg = config() + if cfg.changed('iperf3'): + if cfg['iperf3']: + # start iperf in server + daemon mode + cmd = "iperf3 -s -D" + else: + cmd = "killall iperf3" + try: + charms.sshproxy._run(cmd) + log("iperf3 stopped.") + except CalledProcessError: + log("iperf3 not running.") + else: + log("iperf3 started.") -- 2.25.1