X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Fresources%2Fplanetlab%2Ftap.py;h=6d1be501db703d046209fb94f441c7507960781f;hb=1e2eb157cb569e9c28a5b7888ed97076d27414cb;hp=ed6c2aae5c3bcb0573723d6530817d50a7bee0c7;hpb=a0eefc4e266c584dfa3363e30154b3fdaa5b4f60;p=nepi.git diff --git a/src/nepi/resources/planetlab/tap.py b/src/nepi/resources/planetlab/tap.py index ed6c2aae..6d1be501 100644 --- a/src/nepi/resources/planetlab/tap.py +++ b/src/nepi/resources/planetlab/tap.py @@ -18,7 +18,7 @@ # Author: Alina Quereilhac from nepi.execution.attribute import Attribute, Flags, Types -from nepi.execution.resource import ResourceManager, clsinit_copy, ResourceState, \ +from nepi.execution.resource import clsinit_copy, ResourceState, \ reschedule_delay from nepi.resources.linux.application import LinuxApplication from nepi.resources.planetlab.node import PlanetlabNode @@ -28,45 +28,49 @@ import os import time # TODO: - routes!!! -# - Make base clase 'virtual device' and redefine vif_type -# - Instead of doing an infinite loop, open a port for communication allowing -# to pass the fd to another process +# - CREATE GRE - PlanetlabGRE - it only needs to set the gre and remote +# properties when configuring the vif_up PYTHON_VSYS_VERSION = "1.0" @clsinit_copy class PlanetlabTap(LinuxApplication): _rtype = "PlanetlabTap" + _help = "Creates a TAP device on a PlanetLab host" + _backend = "planetlab" @classmethod def _register_attributes(cls): ip4 = Attribute("ip4", "IPv4 Address", - flags = Flags.ExecReadOnly) + flags = Flags.Design) mac = Attribute("mac", "MAC Address", - flags = Flags.ExecReadOnly) + flags = Flags.Design) prefix4 = Attribute("prefix4", "IPv4 network prefix", - flags = Flags.ExecReadOnly) + type = Types.Integer, + flags = Flags.Design) mtu = Attribute("mtu", "Maximum transmition unit for device", type = Types.Integer) devname = Attribute("deviceName", "Name of the network interface (e.g. eth0, wlan0, etc)", - flags = Flags.ReadOnly) + flags = Flags.NoWrite) - up = Attribute("up", "Link up", type = Types.Bool) + up = Attribute("up", "Link up", + type = Types.Bool) - snat = Attribute("snat", "Set SNAT=1", type = Types.Bool, - flags = Flags.ReadOnly) + snat = Attribute("snat", "Set SNAT=1", + type = Types.Bool, + flags = Flags.Design) pointopoint = Attribute("pointopoint", "Peer IP address", - flags = Flags.ReadOnly) + flags = Flags.Design) tear_down = Attribute("tearDown", "Bash script to be executed before " + \ "releasing the resource", - flags = Flags.ExecReadOnly) + flags = Flags.Design) cls._register_attribute(ip4) cls._register_attribute(mac) @@ -84,51 +88,62 @@ class PlanetlabTap(LinuxApplication): @property def node(self): - node = self.get_connected(PlanetlabNode.rtype()) + node = self.get_connected(PlanetlabNode.get_rtype()) if node: return node[0] return None def upload_sources(self): - depends = "mercurial make gcc" - self.set("depends", depends) + # upload vif-creation python script + pl_vif_create = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-create.py") - install = ( " ( " - " python -c 'import vsys, os; vsys.__version__ == \"%(version)s\" or os._exit(1)' " - " ) " - " ||" - " ( " - " cd ${SRC} ; " - " hg clone http://nepi.inria.fr/code/python-vsys ; " - " cd python-vsys ; " - " make all ; " - " sudo -S make install " - " )" ) % ({ - "version": PYTHON_VSYS_VERSION - }) + self.node.upload(pl_vif_create, + os.path.join(self.node.src_dir, "pl-vif-create.py"), + overwrite = False) - self.set("install", install) + # upload vif-stop python script + pl_vif_stop = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-stop.py") - def upload_start_command(self): - # upload tap-creation python script - start_script = self.replace_paths(self._start_script) - self.node.upload(start_script, - os.path.join(self.app_home, "tap_create.py"), - text = True, + self.node.upload(pl_vif_stop, + os.path.join(self.node.src_dir, "pl-vif-stop.py"), overwrite = False) - # upload start.sh - start_command = self.replace_paths(self._start_command) + # upload vif-connect python script + pl_vif_connect = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-udp-connect.py") - self.info("Uploading command '%s'" % start_command) - - self.set("command", start_command) - self.node.upload(start_command, - os.path.join(self.app_home, "start.sh"), - text = True, + self.node.upload(pl_vif_connect, + os.path.join(self.node.src_dir, "pl-vif-udp-connect.py"), overwrite = False) + # upload tun-connect python script + tunchannel = os.path.join(os.path.dirname(__file__), "..", "linux", + "scripts", "tunchannel.py") + + self.node.upload(tunchannel, + os.path.join(self.node.src_dir, "tunchannel.py"), + overwrite = False) + + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + self.node.upload(stop_command, + os.path.join(self.app_home, "stop.sh"), + text = True, + # Overwrite file every time. + # The stop.sh has the path to the socket, wich should change + # on every experiment run. + overwrite = True) + + def upload_start_command(self): + # Overwrite file every time. + # The stop.sh has the path to the socket, wich should change + # on every experiment run. + super(PlanetlabTap, self).upload_start_command(overwrite = True) + # We want to make sure the device is up and running - # before the experiment starts. + # before the deploy finishes (so things will be ready + # before other stuff starts running). # Run the command as a bash script in background, # in the host ( but wait until the command has # finished to continue ) @@ -138,47 +153,46 @@ class PlanetlabTap(LinuxApplication): if_name = self.wait_if_name() self.set("deviceName", if_name) - def deploy(self): + def do_deploy(self): if not self.node or self.node.state < ResourceState.PROVISIONED: self.ec.schedule(reschedule_delay, self.deploy) else: + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("depends"): + self.set("depends", self._dependencies) - try: - self.discover() - self.provision() - except: - self.fail() - raise - - self.debug("----- READY ---- ") - self._ready_time = tnow() - self._state = ResourceState.READY - - def start(self): - if self._state == ResourceState.READY: + if not self.get("install"): + self.set("install", self._install) + + self.do_discover() + self.do_provision() + + self.set_ready() + + def do_start(self): + if self.state == ResourceState.READY: command = self.get("command") self.info("Starting command '%s'" % command) - self._start_time = tnow() - self._state = ResourceState.STARTED + self.set_started() else: msg = " Failed to execute command '%s'" % command self.error(msg, out, err) - self._state = ResourceState.FAILED raise RuntimeError, msg - def stop(self): + def do_stop(self): command = self.get('command') or '' - state = self.state - if state == ResourceState.STARTED: + if self.state == ResourceState.STARTED: self.info("Stopping command '%s'" % command) - command = "rm %s" % os.path.join(self.run_home, "if_stop") - (out, err), proc = self.execute_command(command) + command = "bash %s" % os.path.join(self.app_home, "stop.sh") + (out, err), proc = self.execute_command(command, + blocking = True) - self._stop_time = tnow() - self._state = ResourceState.STOPPED + self.set_stopped() @property def state(self): @@ -192,19 +206,31 @@ class PlanetlabTap(LinuxApplication): if out.strip().find(self.get("deviceName")) == -1: # tap is not running is not running (socket not found) - self._state = ResourceState.FINISHED + self.set_stopped() self._last_state_check = tnow() return self._state + def do_release(self): + # Node needs to wait until all associated RMs are released + # to be released + from nepi.resources.linux.udptunnel import UdpTunnel + rms = self.get_connected(UdpTunnel.get_rtype()) + for rm in rms: + if rm.state < ResourceState.STOPPED: + self.ec.schedule(reschedule_delay, self.release) + return + + super(PlanetlabTap, self).do_release() + def wait_if_name(self): """ Waits until the if_name file for the command is generated, - and returns the if_name for the devide """ + and returns the if_name for the device """ if_name = None delay = 1.0 - for i in xrange(4): + for i in xrange(20): (out, err), proc = self.node.check_output(self.run_home, "if_name") if out: @@ -216,42 +242,103 @@ class PlanetlabTap(LinuxApplication): else: msg = "Couldn't retrieve if_name" self.error(msg, out, err) - self.fail() raise RuntimeError, msg return if_name + def udp_connect_command(self, remote_ip, local_port_file, + remote_port_file, ret_file, cipher, cipher_key, + bwlimit, txqueuelen): + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/pl-vif-udp-connect.py") + command.append("-t %s" % self.vif_type) + command.append("-S %s " % self.sock_name) + command.append("-l %s " % local_port_file) + command.append("-r %s " % remote_port_file) + command.append("-H %s " % remote_ip) + command.append("-R %s " % ret_file) + if cipher: + command.append("-c %s " % cipher) + if cipher_key: + command.append("-k %s " % cipher_key) + if txqueuelen: + command.append("-q %s " % txqueuelen) + if bwlimit: + command.append("-b %s " % bwlimit) + + command = " ".join(command) + command = self.replace_paths(command) + return command + @property def _start_command(self): - return "sudo -S python ${APP_HOME}/tap_create.py" + command = ["sudo -S python ${SRC}/pl-vif-create.py"] + + command.append("-t %s" % self.vif_type) + command.append("-a %s" % self.get("ip4")) + command.append("-n %d" % self.get("prefix4")) + command.append("-f %s " % self.if_name_file) + command.append("-S %s " % self.sock_name) + if self.get("snat") == True: + command.append("-s") + if self.get("pointopoint"): + command.append("-p %s" % self.get("pointopoint")) + + return " ".join(command) @property - def _start_script(self): - return ( "import vsys, time, os \n" - "(fd, if_name) = vsys.fd_tuntap(vsys.%(devtype)s)\n" - "vsys.vif_up(if_name, '%(ip)s', %(prefix)s%(snat)s%(pointopoint)s)\n" - "f = open('%(if_name_file)s', 'w')\n" - "f.write(if_name)\n" - "f.close()\n\n" - "f = open('%(if_stop_file)s', 'w')\n" - "f.close()\n\n" - "while os.path.exists('%(if_stop_file)s'):\n" - " time.sleep(2)\n" - ) % ({ - "devtype": self._vif_type, - "ip": self.get("ip4"), - "prefix": self.get("prefix4"), - "snat": ", snat=True" if self.get("snat") else "", - "pointopoint": ", pointopoint=%s" % self.get("pointopoint") \ - if self.get("pointopoint") else "", - "if_name_file": os.path.join(self.run_home, "if_name"), - "if_stop_file": os.path.join(self.run_home, "if_stop"), - }) + def _stop_command(self): + command = ["sudo -S python ${SRC}/pl-vif-stop.py"] + + command.append("-S %s " % self.sock_name) + return " ".join(command) @property - def _vif_type(self): + def vif_type(self): return "IFF_TAP" + @property + def if_name_file(self): + return os.path.join(self.run_home, "if_name") + + @property + def sock_name(self): + return os.path.join(self.run_home, "tap.sock") + + @property + def _dependencies(self): + return "mercurial make gcc" + + @property + def _install(self): + # Install python-vsys and python-passfd + install_vsys = ( " ( " + " python -c 'import vsys, os; vsys.__version__ == \"%(version)s\" or os._exit(1)' " + " ) " + " || " + " ( " + " cd ${SRC} ; " + " hg clone http://nepi.inria.fr/code/python-vsys ; " + " cd python-vsys ; " + " make all ; " + " sudo -S make install " + " )" ) % ({ + "version": PYTHON_VSYS_VERSION + }) + + install_passfd = ( " ( python -c 'import passfd' ) " + " || " + " ( " + " cd ${SRC} ; " + " hg clone http://nepi.inria.fr/code/python-passfd ; " + " cd python-passfd ; " + " make all ; " + " sudo -S make install " + " )" ) + + return "%s ; %s" % ( install_vsys, install_passfd ) + def valid_connection(self, guid): # TODO: Validate! return True