aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Capitani <m.capitani@nextworks.it>2018-03-28 15:46:38 +0200
committerMarco Capitani <m.capitani@nextworks.it>2018-03-28 16:30:06 +0200
commita95c3b376053ed00f0e7184dbd228598a9aaf50f (patch)
tree994e3ccbb7ce8baf08dc9b934c63beefa87215f5
parent9d42e50b99993c3fa5b9724c09dd28be4c528add (diff)
downloadrumba-a95c3b376053ed00f0e7184dbd228598a9aaf50f.tar.gz
rumba-a95c3b376053ed00f0e7184dbd228598a9aaf50f.zip
model: make link quality changes scriptable
Added method accepting only ints and floats to allow scripting link quality changes (see example-script additions) Also added general purpose `sb.schedule_action` method
-rw-r--r--examples/example-script.rsb4
-rw-r--r--rumba/model.py93
-rw-r--r--rumba/storyboard.py54
3 files changed, 143 insertions, 8 deletions
diff --git a/examples/example-script.rsb b/examples/example-script.rsb
index f00ff42..1d49a66 100644
--- a/examples/example-script.rsb
+++ b/examples/example-script.rsb
@@ -37,6 +37,10 @@ echo2, 18 &ev4| $sb run_client_of $Server.server_b
14 | $Node.node_a set_link_state $ShimEthDIF.e1 'up'
+16 | $ShimEthDIF.e1 set_delay 30 10
+
+28 | $ShimEthDIF.e1 set_loss 2
+
diff --git a/rumba/model.py b/rumba/model.py
index 6d0af58..a8d4664 100644
--- a/rumba/model.py
+++ b/rumba/model.py
@@ -189,6 +189,65 @@ class ShimEthDIF(DIF):
def link_quality(self):
self._link_quality.deactivate(self)
+ def set_delay(self, delay=0,
+ jitter=None,
+ correlation=None,
+ distribution=None):
+ """
+ Set the delay parameters of the underlying link.
+ Parameters as in :py:meth:`.Delay.__init__`
+ :param delay: average delay in ms
+ :type delay: :py:class:`int`
+ :param jitter: jitter in ms
+ :type jitter: :py:class:`int`
+ :param correlation: correlation in %
+ :type correlation: :py:class:`int`
+ :param distribution: delay distribution, defaults to a Normal
+ distribution
+ :type distribution: :py:class:`.Distribution`
+ """
+ new_delay = Delay(delay, jitter, correlation, distribution)
+ new_quality = LinkQuality.clone(self.link_quality, delay=new_delay)
+ self.link_quality = new_quality
+
+ def set_loss(self,
+ loss=0,
+ correlation=None):
+ """
+ Set the loss parameter of the underlying link.
+ Parameters as in :py:meth:`.Loss.__init__`
+ :param loss: loss in percentage
+ :type loss: :py:class:`int` or :py:class:`float`
+ :param correlation: correlation in percentage
+ :type correlation: :py:class:`int` or :py:class:`float`
+ """
+ new_loss = Loss(loss, correlation)
+ new_quality = LinkQuality.clone(self.link_quality, loss=new_loss)
+ self.link_quality = new_quality
+
+ def set_rate(self, rate=None):
+ """
+ Set the rate parameter of the underlying link.
+ :param rate: The desired rate in mbps
+ :type rate: :py:class:`int`
+ """
+ new_quality = LinkQuality.clone(self.link_quality, rate=rate)
+ self.link_quality = new_quality
+
+ def set_quality(self, delay, loss, rate):
+ """
+ Configure the basic quality parameters of the
+ underlying link
+ :param delay: the link delay, in ms
+ :type delay: :py:class:`int`
+ :param loss: the link loss, as a percentage
+ :type loss: :py:class:`float` or :py:class:`int`
+ :param rate: the link rate in mbps
+ :type rate: :py:class:`int`
+ """
+ new_quality = LinkQuality(delay, loss, rate)
+ self.link_quality = new_quality
+
# Normal DIF
#
@@ -231,10 +290,14 @@ class Delay(object):
"""
Configure link delay
:param delay: average delay in ms
+ :type delay: :py:class:`int`
:param jitter: jitter in ms
+ :type jitter: :py:class:`int`
:param correlation: correlation in %
+ :type correlation: :py:class:`int`
:param distribution: delay distribution, defaults to a Normal
distribution
+ :type distribution: :py:class:`.Distribution`
"""
if delay < 0:
@@ -290,7 +353,9 @@ class Loss(object):
"""
Configure link loss
:param loss: loss in percentage
+ :type loss: :py:class:`int` or :py:class:`float`
:param correlation: correlation in percentage
+ :type correlation: :py:class:`int` or :py:class:`float`
"""
if loss and (loss < 0 or loss > 100):
raise ValueError("Loss needs to be between 0 and 100")
@@ -321,6 +386,34 @@ class Loss(object):
class LinkQuality(object):
_active = set()
+ @classmethod
+ def clone(cls, old_quality, delay=None, loss=None, rate=None):
+ """
+ Clone old_quality, updating it with the provided parameters
+ if present
+
+ :param old_quality: A :py:class`.LinkQuality` instance to
+ use as a base
+ :type old_quality: :py:class`.LinkQuality`
+ :param delay: Delay object holding delay configuration
+ or number corresponding to delay in ms
+ :type delay: :py:class:`.Delay` or :py:class:`int`
+ :param loss: Loss object holding delay configuration or
+ number corresponding to loss percentage
+ :type loss: :py:class:`.Loss` or :py:class:`float`
+ :param rate: The rate of the link in mbit
+ :type rate: :py:class:`int`
+ :return: a new :py:class`.LinkQuality` instance
+ :rtype :py:class`LinkQuality`
+ """
+ if delay is None:
+ delay = old_quality.delay
+ if loss is None:
+ loss = old_quality.loss
+ if rate is None:
+ rate = old_quality.rate
+ return LinkQuality(delay, loss, rate)
+
def __init__(self, delay=None, loss=None, rate=None):
"""
Link quality configuration
diff --git a/rumba/storyboard.py b/rumba/storyboard.py
index 9aff375..ba6883d 100644
--- a/rumba/storyboard.py
+++ b/rumba/storyboard.py
@@ -423,6 +423,39 @@ class StoryBoard(SBEntity):
del self.server_apps[server.id]
self._build_nodes_lists()
+ def schedule_action(self,
+ call,
+ args=None,
+ kwargs=None,
+ c_time=None,
+ trigger=None,
+ ev_id=None,):
+ """
+ Calls a function with the specified triggers and arguments.
+ :param call: the function to run
+ :type call: function (methods included)
+ :param c_time: the function will not be called before `c_time`
+ seconds have passed
+ :type c_time: :py:class:`float`
+ :param trigger: the function must not be called before the event
+ `trigger` has completed
+ :type trigger: :py:class:`.Event` or :py:class:`str`
+ :param ev_id: the ID to assign to the generated event
+ :type ev_id: :py:class:`str`
+ :param args: arguments to pass to the function
+ :param kwargs: keyword arguments to be passed
+ :return: the event representing the calling of the function
+ :rtype: :py:class:`.Event`
+ """
+ if args is None:
+ args = []
+ if kwargs is None:
+ kwargs = {}
+ action = functools.partial(call, *args, **kwargs)
+ event = Event(action, ev_id=ev_id, ev_time=c_time, trigger=trigger)
+ self.add_event(event)
+ return event
+
def schedule_command(self, t, node, command):
"""
Schedules the given command to be run at t seconds from the start.
@@ -846,14 +879,19 @@ class StoryBoard(SBEntity):
str(uuid.uuid4())[0:4] + ".pcap"
tcpd_client = Client(ap="tcpdump", options="-i %s -w %s" \
- % (ipcp.ifname, pcap_file))
- duration = end - start
- cb = functools.partial(node.fetch_file, pcap_file,
- self.experiment.log_dir, sudo=True)
- action = functools.partial(self.run_client, tcpd_client,
- duration=duration, node=node,
- callback = cb)
- self._script.add_event(Event(action, ev_time=start))
+ % (ipcp.ifname, pcap_file))\
+ .process(end-start, node, 'tcpdump_proc')
+
+ self.schedule_action(tcpd_client.run, c_time=start)
+ end_event = self.schedule_action(tcpd_client.stop, c_time=end)
+
+ self.schedule_action(
+ node.fetch_file,
+ args=[pcap_file, self.experiment.log_dir],
+ kwargs={'sudo': True},
+ trigger=end_event
+ )
+
class Event(object):