From 208dd89ae9fe29a643b4966ddc87d14506993590 Mon Sep 17 00:00:00 2001 From: Marta Carbone Date: Wed, 3 Sep 2008 14:42:09 +0000 Subject: [PATCH] Added a new Method that allows to configure the dummynet box from the Central Site. At the moment works if called from plcsh. Changed the image generation working dir, because of space problems. --- PLC/Methods/ConfigureDummynetBox.py | 195 ++++++++++++++++++++++++++++ PLC/Methods/GetDummyBoxMedium.py | 2 +- PLC/Methods/__init__.py | 1 + 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 PLC/Methods/ConfigureDummynetBox.py diff --git a/PLC/Methods/ConfigureDummynetBox.py b/PLC/Methods/ConfigureDummynetBox.py new file mode 100644 index 00000000..98f43064 --- /dev/null +++ b/PLC/Methods/ConfigureDummynetBox.py @@ -0,0 +1,195 @@ +# +# 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" + diff --git a/PLC/Methods/GetDummyBoxMedium.py b/PLC/Methods/GetDummyBoxMedium.py index 1a4252ac..c33d1366 100644 --- a/PLC/Methods/GetDummyBoxMedium.py +++ b/PLC/Methods/GetDummyBoxMedium.py @@ -18,7 +18,7 @@ from PLC.Auth import Auth # import the Auth parameter from PLC.DummyBoxes import DummyBox, DummyBoxes # main class for a DummyBox from PLC.Methods.GetBootMedium import compute_key # key generation function -WORK_DIR = "/tmp/DummynetBoxMedium" +WORK_DIR = "/var/tmp/DummynetBoxMedium" BASE_IMAGE = "/usr/share/dummynet/picobsd.bin" class GetDummyBoxMedium(Method): diff --git a/PLC/Methods/__init__.py b/PLC/Methods/__init__.py index 5489b27b..e6d6a8b0 100644 --- a/PLC/Methods/__init__.py +++ b/PLC/Methods/__init__.py @@ -105,6 +105,7 @@ BootCheckAuthentication BootGetNodeDetails BootNotifyOwners BootUpdateNode +ConfigureDummynetBox DeleteAddress DeleteAddressTypeFromAddress DeleteAddressType -- 2.47.0