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=<ip of server> [...]
+```
## Scale out Usage
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
--- /dev/null
+#!/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))
--- /dev/null
+options:
+ iperf3:
+ type: boolean
+ default: false
+ description: "Enabling this option will start iperf3 in server mode."
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')
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.")