From a34a5d7ec2e6aa59a0a0aa0daba62f7738a1749a Mon Sep 17 00:00:00 2001 From: Sander Vrijders Date: Tue, 9 May 2017 11:50:17 +0200 Subject: rumba: model: Add StoryBoard for automated testing This adds an initial draft of the API to automate tests on a RINA network. --- examples/example.py | 20 ++++++++-------- rumba/model.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/examples/example.py b/examples/example.py index 56193c2..383dbf1 100755 --- a/examples/example.py +++ b/examples/example.py @@ -17,7 +17,6 @@ import rumba.prototypes.irati as irati import rumba.log as log - log.set_logging_level('DEBUG') n1 = NormalDIF("n1", policies = {"rmt.pff": "lfa", @@ -27,19 +26,16 @@ e1 = ShimEthDIF("e1") a = Node("a", difs = [n1, e1], - dif_registrations = {n1 : [e1]}, - registrations = {"a.crap" : [n1]}, - bindings = {"a.crap" : "/usr/bin/crap"}) + dif_registrations = {n1 : [e1]}) b = Node("b", difs = [e1, n1], - dif_registrations = {n1 : [e1]}) + dif_registrations = {n1 : [e1]}, + end_user = True) -tb = qemu.Testbed(exp_name = "example1", - username = "root", - password = "root", - bzimage = '/home/vmaffione/git/rlite/demo/buildroot/bzImage', - initramfs = '/home/vmaffione/git/rlite/demo/buildroot/rootfs.cpio') +tb = jfed.Testbed(exp_name = "example1", + username = "user1", + cert_file = "/home/user1/cert.pem") exp = rl.Experiment(tb, nodes = [a, b]) @@ -48,5 +44,9 @@ print(exp) try: exp.swap_in() exp.bootstrap_prototype() + c1 = Client("rinaperf", options = "-t perf -s 1000 -c 10000") + s1 = Server("rinaperf", options = "-l", nodes = [a], clients = [c1]) + sb = StoryBoard(exp, 3600, servers = [s1]) + sb.start() finally: exp.swap_out() diff --git a/rumba/model.py b/rumba/model.py index 0b9fc7a..91f33a6 100644 --- a/rumba/model.py +++ b/rumba/model.py @@ -152,7 +152,7 @@ class SSHConfig: # class Node: def __init__(self, name, difs=None, dif_registrations=None, - registrations=None, bindings=None): + registrations=None, bindings=None, end_user=False): self.name = name if difs is None: difs = list() @@ -170,6 +170,7 @@ class Node: self.bindings = bindings self.ssh_config = SSHConfig(name) self.ipcps = [] + self.end_user = end_user self._validate() @@ -564,3 +565,67 @@ class Experiment: def swap_out(self): # Undo the testbed (testbed-specific) self.testbed.swap_out(self) + +# Base class for client programs +# +# @ap: Application Process binary +# @options: Options to pass to the binary +# +class Client: + def __init__(self, ap, options=None): + self.ap = ap + self.options = options + +# Base class for server programs +# +# @ap: Application Process binary +# @options: Options to pass to the binary +# @max_clients: Maximum number of clients to serve +# @clients: Client binaries that will use this server +# @nodes: Specific nodes to start this server on +# +class Server: + def __init__(self, ap, options=None, max_clients=None, + clients=None, nodes=None): + self.ap = ap + self.options = options + self.max_clients = max_clients + if clients is None: + clients = list() + self.clients = clients + self.nodes = nodes + + def add_client(self, client): + self.clients.append(client) + + def del_client(self, client): + self.clients.remove(client) + + def add_node(self, node): + self.nodes.append(node) + + def del_node(self, node): + self.nodes.remove(node) + +# Base class for ARCFIRE storyboards +# +# @experiment: Experiment to use as input +# @duration: Duration of the whole storyboard +# @servers: App servers available in the network +# +class StoryBoard: + def __init__(self, experiment, duration, servers=None): + self.experiment = experiment + self.duration = duration + if servers is None: + servers = list() + self.servers = servers + + def add_server(self, server): + self.servers.append(server) + + def del_server(self, server): + self.servers.remove(server) + + def start(self): + pass -- cgit v1.2.3 From 43d3dbafc78172030dee2545b25d4fe5a05d1eba Mon Sep 17 00:00:00 2001 From: Marco Capitani Date: Wed, 10 May 2017 18:09:56 +0200 Subject: Storyboard: additions to the model Means of distributions and other required fields. --- rumba/model.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/rumba/model.py b/rumba/model.py index 91f33a6..97af536 100644 --- a/rumba/model.py +++ b/rumba/model.py @@ -20,6 +20,7 @@ # MA 02110-1301 USA import abc +import random import rumba.log as log @@ -572,20 +573,23 @@ class Experiment: # @options: Options to pass to the binary # class Client: - def __init__(self, ap, options=None): + def __init__(self, ap, duration, options=None): self.ap = ap self.options = options + self.duration = duration # in seconds # Base class for server programs # # @ap: Application Process binary +# @arrival_rate: Average requests/s to be received by this server # @options: Options to pass to the binary # @max_clients: Maximum number of clients to serve # @clients: Client binaries that will use this server # @nodes: Specific nodes to start this server on # class Server: - def __init__(self, ap, options=None, max_clients=None, + def __init__(self, ap, arrival_rate, mean_duration, + options=None, max_clients=None, clients=None, nodes=None): self.ap = ap self.options = options @@ -594,6 +598,8 @@ class Server: clients = list() self.clients = clients self.nodes = nodes + self.arrival_rate = arrival_rate # mean requests/s + self.mean_duration = mean_duration # in seconds def add_client(self, client): self.clients.append(client) @@ -607,6 +613,24 @@ class Server: def del_node(self, node): self.nodes.remove(node) + def get_new_clients(self, interval): + """ + Returns a list of clients of size appropriate to the server's rate. + + The list's size should be a sample from Poisson(arrival_rate) over + interval seconds. + Hence, the average size should be interval * arrival_rate. + """ + pass + + def make_client(self): + """Returns a client of this server""" + if len(self.clients) == 0: + raise Exception("Server %s has empty client list," % (self,)) + placeholder = 10 # TODO: Should be a sample from Exp(mean_duration) + return Client(random.choice(self.clients), placeholder) + + # Base class for ARCFIRE storyboards # # @experiment: Experiment to use as input -- cgit v1.2.3 From ea1a4462a8b7a2fb7404e4652e0806795ba96863 Mon Sep 17 00:00:00 2001 From: Marco Capitani Date: Thu, 11 May 2017 10:51:26 +0200 Subject: Storyboard: added modifications to API to example.py --- examples/example.py | 4 ++-- rumba/model.py | 47 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/examples/example.py b/examples/example.py index 383dbf1..7fe130d 100755 --- a/examples/example.py +++ b/examples/example.py @@ -44,8 +44,8 @@ print(exp) try: exp.swap_in() exp.bootstrap_prototype() - c1 = Client("rinaperf", options = "-t perf -s 1000 -c 10000") - s1 = Server("rinaperf", options = "-l", nodes = [a], clients = [c1]) + c1 = ClientBinary("rinaperf", options = "-t perf -s 1000 -c 10000") + s1 = Server("rinaperf", arrival_rate=2, mean_duration=5, options = "-l", nodes = [a], clients = [c1]) sb = StoryBoard(exp, 3600, servers = [s1]) sb.start() finally: diff --git a/rumba/model.py b/rumba/model.py index 97af536..36ac5c3 100644 --- a/rumba/model.py +++ b/rumba/model.py @@ -22,6 +22,8 @@ import abc import random +import time + import rumba.log as log @@ -567,16 +569,50 @@ class Experiment: # Undo the testbed (testbed-specific) self.testbed.swap_out(self) + # Base class for client programs # # @ap: Application Process binary # @options: Options to pass to the binary # -class Client: - def __init__(self, ap, duration, options=None): +class ClientBinary(object): + def __init__(self, ap, options=None): self.ap = ap self.options = options - self.duration = duration # in seconds + + def start_process(self, node, duration, start_time): + return ClientProcess(self.ap, node, duration, start_time, self.options) + + +# Base class for client processes +# +# @ap: Application Process binary +# @node: The node on which this process should run +# @duration: The time (in seconds) this process should run +# @start_time: The time at which this process is started. +# @options: Options to pass to the binary +# +class ClientProcess(ClientBinary): + def __init__(self, ap, node, duration, start_time, options=None): + super(ClientProcess, self).__init__(ap, options=options) + self.node = node + self.duration = duration + self.start_time = start_time + self.run() + self.running = True + + def run(self): + pass # TODO to be implemented + + def stop(self): + pass # TODO to be implemented + + def check(self, now): + if not self.running: + return + if now - self.start_time >= self.duration: + self.stop() + # Base class for server programs # @@ -623,12 +659,11 @@ class Server: """ pass - def make_client(self): + def make_client_process(self): """Returns a client of this server""" if len(self.clients) == 0: raise Exception("Server %s has empty client list," % (self,)) - placeholder = 10 # TODO: Should be a sample from Exp(mean_duration) - return Client(random.choice(self.clients), placeholder) + pass # TODO should return a ClientProcess # Base class for ARCFIRE storyboards -- cgit v1.2.3 From e78c92993406bc4ca24a1c38db7d3195901b28d9 Mon Sep 17 00:00:00 2001 From: Marco Capitani Date: Thu, 11 May 2017 11:32:11 +0200 Subject: Storyboard: small fixes to API --- examples/example.py | 2 +- rumba/model.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/example.py b/examples/example.py index 7fe130d..a3fe5ec 100755 --- a/examples/example.py +++ b/examples/example.py @@ -44,7 +44,7 @@ print(exp) try: exp.swap_in() exp.bootstrap_prototype() - c1 = ClientBinary("rinaperf", options = "-t perf -s 1000 -c 10000") + c1 = Client("rinaperf", options ="-t perf -s 1000 -c 10000") s1 = Server("rinaperf", arrival_rate=2, mean_duration=5, options = "-l", nodes = [a], clients = [c1]) sb = StoryBoard(exp, 3600, servers = [s1]) sb.start() diff --git a/rumba/model.py b/rumba/model.py index 36ac5c3..285d937 100644 --- a/rumba/model.py +++ b/rumba/model.py @@ -155,7 +155,7 @@ class SSHConfig: # class Node: def __init__(self, name, difs=None, dif_registrations=None, - registrations=None, bindings=None, end_user=False): + registrations=None, bindings=None, client=False): self.name = name if difs is None: difs = list() @@ -173,7 +173,7 @@ class Node: self.bindings = bindings self.ssh_config = SSHConfig(name) self.ipcps = [] - self.end_user = end_user + self.client = client self._validate() @@ -575,7 +575,7 @@ class Experiment: # @ap: Application Process binary # @options: Options to pass to the binary # -class ClientBinary(object): +class Client(object): def __init__(self, ap, options=None): self.ap = ap self.options = options @@ -592,7 +592,7 @@ class ClientBinary(object): # @start_time: The time at which this process is started. # @options: Options to pass to the binary # -class ClientProcess(ClientBinary): +class ClientProcess(Client): def __init__(self, ap, node, duration, start_time, options=None): super(ClientProcess, self).__init__(ap, options=options) self.node = node @@ -618,6 +618,7 @@ class ClientProcess(ClientBinary): # # @ap: Application Process binary # @arrival_rate: Average requests/s to be received by this server +# @mean_duration: Average duration of a client connection (in seconds) # @options: Options to pass to the binary # @max_clients: Maximum number of clients to serve # @clients: Client binaries that will use this server -- cgit v1.2.3 From 10da73cd31a26ad2b4a95bb1ec3d02f6afc57dc6 Mon Sep 17 00:00:00 2001 From: Marco Capitani Date: Thu, 11 May 2017 12:03:08 +0200 Subject: Storyboard missing end_user->client change --- examples/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example.py b/examples/example.py index a3fe5ec..1acc883 100755 --- a/examples/example.py +++ b/examples/example.py @@ -31,7 +31,7 @@ a = Node("a", b = Node("b", difs = [e1, n1], dif_registrations = {n1 : [e1]}, - end_user = True) + client = True) tb = jfed.Testbed(exp_name = "example1", username = "user1", -- cgit v1.2.3