--- /dev/null
+#
+# Marta Carbone - UniPi
+# $Id$
+#
+# This script allows to configure a dummynet box from the central site.
+#
+# The authentication is done by a dummynet box key
+# located on the Central Site /usr/share/dummynet/dbox_key
+# The public key will be propagated to the dummynet boxes
+# by the same script used for users.
+
+from PLC.Faults import * # faults library
+from PLC.Method import Method # base class used for methods
+from PLC.Parameter import Parameter, Mixed # define input parameters
+from PLC.DummyBoxes import DummyBox, DummyBoxes # main class for a DummyBox
+from PLC.Sites import Site, Sites # manage authentication
+from PLC.Auth import Auth # import Auth parameter
+from PLC.Nodes import Node, Nodes # main class for Nodes
+from PLC.NodeNetworks import * # main class for Nodes
+from PLC.Persons import Person, Persons # main class for Persons
+from PLC.Slices import Slice, Slices # main class for Slices
+import os # ssh
+
+# basename for the Dummynet box public key
+# used to send configuration requests
+# to the dummynet box.
+DBOX_KEY="/usr/share/dummynet/dbox_key"
+
+DEFAULT_TIMEOUT= "1H"
+
+# return 1 if the value is present in the array
+def match(list, value):
+ for i in list:
+ if (value == i):
+ return 1
+ return 0
+
+# if the field key is set in the fields_list dict,
+# return the cmd_keyword string and the dict value
+def pipe_build(fields_list, field, cmd_keyword):
+ try:
+ a = fields_list[field]
+ except:
+ return ""
+ else:
+ return cmd_keyword + str(a)
+
+class ConfigureDummynetBox(Method):
+ """
+ This script will configure an emulated link.
+ WARNING: This method is experimental, so it
+ could _work_.
+
+ To do this it:
+ - takes as input the node_id, the slicename,
+ and other dummynet configuration parameters;
+ - make some permission checks;
+ - retrive other useful information from the database;
+ - send the emulated link configuration to the DummynetBox;
+ - wait for the remote execution and return the reply to the user.
+ """
+
+ roles = ['admin', 'pi', 'tech', 'user']
+ link_configuration_fields = {
+ 'node_id': Parameter(int, "Node identifier"),
+ 'slicename': Parameter(str, "Name of the slice"),
+ 'port': Parameter(int, "Port number"),
+ 'bw': Parameter(str, "dummynet, bandwidth limit"),
+ 'delay': Parameter(str, "dummynet, delay"),
+ 'plr': Parameter(str, "dummynet, packet loss rate"),
+ 'upload_extra-delay': Parameter(str, "dummynet, extra delay file"),
+ 'extra-delay': Parameter(str, "dummynet, extra delay, if above unset"),
+ 'timeout': Parameter(str, "Rules timeout"),
+ 'noerror': Parameter(str, "dummynet, if '0' do not propagate errors to the upper layer"),
+ }
+
+ accepts = [
+ Auth(),
+ link_configuration_fields,
+ ]
+
+ returns = Parameter(str, 'Remote command execution output');
+
+ def call(self, auth, link_configuration_fields):
+
+ # Only a person istance can send configuration commands
+ if not isinstance(self.caller, Person):
+ return "Authentication method not allowed to perform this operation";
+
+ # Get identity
+ email = str(self.caller['email']);
+
+ # Get mandatory arguments
+ node_id = link_configuration_fields['node_id']
+ slicename = link_configuration_fields['slicename']
+ port = link_configuration_fields['port']
+
+ # Check not mandatory, they will be done again on the dummynet box
+ if port <= 1024:
+ return "Port should be > 1024"
+
+ # Get the dummynet box connected to this node
+ nodes = Nodes(self.api, {'node_id': node_id}, ['dummybox_id','nodenetwork_ids'])
+ if not nodes:
+ return "Node not present"
+
+ dummybox_id = nodes[0]['dummybox_id']
+
+ if (dummybox_id == 0): # dummybox_id == 0 means empty
+ return "This node has no dummynet box connected"
+
+ dummyboxes = DummyBoxes(self.api, {'dummybox_id': dummybox_id}, ['ip'])
+ dbox_ip = str(dummyboxes[0]['ip'])
+
+ # Get the node ip address, we need to cross with the NodeNetworks table
+ nodenetwork_id = NodeNetworks(self.api, {'node_id': node_id, 'is_primary':'t'}, ['ip']);
+ if not nodenetwork_id or not nodenetwork_id[0]['ip']:
+ return "Network not configured on this node"
+
+ node_ip = nodenetwork_id[0]['ip']
+
+ # Search the person_id
+ person_id = Persons(self.api, {'email': email}, ['person_id'])
+ if not person_id:
+ return "User not found"
+
+ # Search slice information
+ slices = Slices(self.api, {'name': slicename}, ['node_ids', 'person_ids'])
+ if not slices:
+ return "No slices found"
+
+ # Check for permissions:
+ # - the person_id should own the slice
+ # - the slice should be istantiated on the node
+ if not match(slices[0]['node_ids'], node_id) or \
+ not match(slices[0]['person_ids'], person_id[0]['person_id']):
+ return "The slice %s and the user %s should be istantiated on the node %s" % \
+ (slicename, person_id[0]['person_id'], node_id)
+
+ # Manage the profile upload
+ # if upload_extra-delay is present, we upload the file and use it as profile
+ cmd_line = ""
+ file_to_upload = pipe_build(link_configuration_fields, "upload_extra-delay", "")
+ if file_to_upload:
+ cmd_line += "cat " + file_to_upload + " >> "
+
+ # start to build the command line
+ # the ssh command take as input
+ # the node_ip, the slicename, the port number
+ # a timeout and a filename (0 don't upload)
+
+ cmd_line += "ssh -i "+DBOX_KEY+" user@"+dbox_ip;
+ cmd_line += " "+str(node_ip)+" "+slicename+" "+str(port);
+
+ # add the timeout
+ cmd = pipe_build(link_configuration_fields, "timeout", "")
+ cmd_line += " "
+ if not cmd:
+ cmd_line += DEFAULT_TIMEOUT
+ else:
+ cmd_line += cmd
+
+ # add the filename to upload, "0" if not defined
+ cmd_line += " "
+ if file_to_upload:
+ cmd_line += file_to_upload
+ else:
+ cmd_line += "0"
+
+ # add the extra-delay parameter
+ # note that the upload_extra-delay, if present win
+ if file_to_upload:
+ cmd_line += pipe_build(link_configuration_fields, "upload_extra-delay", " extra-delay ")
+ else:
+ cmd_line += pipe_build(link_configuration_fields, "extra-delay", " extra-delay ")
+
+ # add plr, bw, delay, noerror
+ cmd_line += pipe_build(link_configuration_fields, "plr", " plr ")
+ cmd_line += pipe_build(link_configuration_fields, "bw", " bw ")
+ cmd_line += pipe_build(link_configuration_fields, "delay", " delay ")
+
+ # noerror should be malipulated in a different way
+ noerror = pipe_build(link_configuration_fields, "noerror", "")
+ if noerror == '0':
+ cmd_line += " noerror"
+
+ # send the command to the dummynetbox
+ # suppose that the key exist with right permissions
+
+ ret = os.system(cmd_line);
+ if ret == 0:
+ return "link configured"
+ else:
+ return "an error occurred link not configured"
+