X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Ftestbeds%2Fplanetlab%2Fapplication.py;h=e9a823add53af26afcd1c8e31b91c0dc09c7af71;hb=3211c8a6e16cfaa828ed7e51e467ad44d5fa66fa;hp=e88343934cd1337363dd6ce00993b941f315d104;hpb=7cf48cdf39b271905e078b4be03d9b642c8c7f67;p=nepi.git diff --git a/src/nepi/testbeds/planetlab/application.py b/src/nepi/testbeds/planetlab/application.py index e8834393..e9a823ad 100644 --- a/src/nepi/testbeds/planetlab/application.py +++ b/src/nepi/testbeds/planetlab/application.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- from constants import TESTBED_ID @@ -20,6 +19,8 @@ import re from nepi.util.constants import ApplicationStatus as AS +_ccnre = re.compile("\s*(udp|tcp)\s+(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\s*$") + class Dependency(object): """ A Dependency is in every respect like an application. @@ -90,7 +91,10 @@ class Dependency(object): self.__class__.__name__, ' '.join(filter(bool,(self.depends, self.sources))) ) - + + def deployed(self): + return self._setup + def validate(self): if self.home_path is None: raise AssertionError, "Misconfigured application: missing home path" @@ -207,10 +211,13 @@ class Dependency(object): raise RuntimeError, "Failed to set up application %s: %s %s" % (self.home_path, e.args[0], e.args[1],) if self.stdin: + stdin = self.stdin + if not os.path.isfile(stdin): + stdin = cStringIO.StringIO(self.stdin) + # Write program input try: - self._popen_scp( - cStringIO.StringIO(self.stdin), + self._popen_scp(stdin, '%s@%s:%s' % (self.node.slicename, self.node.hostname, os.path.join(self.home_path, 'stdin') ), ) @@ -337,7 +344,7 @@ class Dependency(object): 'home' : server.shell_escape(self.home_path), 'token' : server.shell_escape(self._master_token), } - + return cStringIO.StringIO(slavescript) def _do_launch_build(self): @@ -375,7 +382,7 @@ class Dependency(object): for i in xrange(5): pidtuple = rspawn.remote_check_pid( os.path.join(self.home_path,'build-pid'), - host = self.node.hostname, + host = self.node.hostip, port = None, user = self.node.slicename, agent = None, @@ -436,7 +443,7 @@ class Dependency(object): time.sleep(delay*(0.5+random.random())) delay = min(30,delay*1.2) bustspin = 0 - + # check build token slave_token = "" for i in xrange(3): @@ -516,8 +523,24 @@ class Dependency(object): if self.sources: sources = self.sources.split(' ') - - # Copy all sources + + http_sources = list() + for source in list(sources): + if source.startswith("http") or source.startswith("https"): + http_sources.append(source) + sources.remove(source) + + # Download http sources + try: + for source in http_sources: + path = os.path.join(self.home_path, source.split("/")[-1]) + command = "wget -o %s %s" % (path, source) + self._popen_ssh(command) + except RuntimeError, e: + raise RuntimeError, "Failed wget source file %r: %s %s" \ + % (sources, e.args[0], e.args[1],) + + # Copy all other sources try: self._popen_scp( sources, @@ -565,20 +588,20 @@ class Dependency(object): def _do_install(self): if self.install: self._logger.info("Installing %s at %s", self, self.node.hostname) - + # Install application try: - self._popen_ssh_command( - "cd %(home)s && cd build && ( %(command)s ) > ${HOME}/%(home)s/installlog 2>&1 || ( tail ${HOME}/%(home)s/{install,build}log >&2 && false )" % \ - { - 'command' : self._replace_paths(self.install), - 'home' : server.shell_escape(self.home_path), - }, - ) + command = "cd %(home)s && cd build && ( %(command)s ) > ${HOME}/%(home)s/installlog 2>&1 || ( tail ${HOME}/%(home)s/{install,build}log >&2 && false )" % \ + { + 'command' : self._replace_paths(self.install), + 'home' : server.shell_escape(self.home_path), + } + self._popen_ssh_command(command) except RuntimeError, e: if self.check_bad_host(e.args[0], e.args[1]): self.node.blacklist() - raise RuntimeError, "Failed install build sources: %s %s" % (e.args[0], e.args[1],) + raise RuntimeError, "Failed install build sources on node %s: %s %s. COMMAND %s" % ( + self.node.hostname, e.args[0], e.args[1], command) def set_master(self, master): self._master = master @@ -746,7 +769,6 @@ class Application(Dependency): stdout = 'stdout' if self.stdout else '/dev/null', stderr = 'stderr' if self.stderr else '/dev/null', sudo = self.sudo, - host = self.node.hostname, port = None, user = self.node.slicename, @@ -898,13 +920,16 @@ class NS3Dependency(Dependency): def __init__(self, api = None): super(NS3Dependency, self).__init__(api) - self.buildDepends = 'make waf gcc gcc-c++ gccxml unzip' + self.buildDepends = 'make waf gcc gcc-c++ gccxml unzip bzr' # We have to download the sources, untar, build... - pybindgen_source_url = "http://yans.pl.sophia.inria.fr/trac/nepi/raw-attachment/wiki/WikiStart/pybindgen-r794.tar.gz" - pygccxml_source_url = "http://leaseweb.dl.sourceforge.net/project/pygccxml/pygccxml/pygccxml-1.0/pygccxml-1.0.0.zip" - ns3_source_url = "http://yans.pl.sophia.inria.fr/code/hgwebdir.cgi/ns-3.11-nepi/archive/tip.tar.gz" - passfd_source_url = "http://yans.pl.sophia.inria.fr/code/hgwebdir.cgi/python-passfd/archive/tip.tar.gz" + #pygccxml_source_url = "http://leaseweb.dl.sourceforge.net/project/pygccxml/pygccxml/pygccxml-1.0/pygccxml-1.0.0.zip" + pygccxml_source_url = "http://yans.pl.sophia.inria.fr/libs/pygccxml-1.0.0.zip" + ns3_source_url = "http://nepi.inria.fr/code/nepi-ns3.13/archive/tip.tar.gz" + passfd_source_url = "http://nepi.inria.fr/code/python-passfd/archive/tip.tar.gz" + + pybindgen_version = "797" + self.build =( " ( " " cd .. && " @@ -918,26 +943,23 @@ class NS3Dependency(Dependency): # Not working, rebuild # Archive SHA1 sums to check "echo '7158877faff2254e6c094bf18e6b4283cac19137 pygccxml-1.0.0.zip' > archive_sums.txt && " - "echo 'a18c2ccffd0df517bc37e2f3a2475092517c43f2 pybindgen-src.tar.gz' >> archive_sums.txt && " " ( " # check existing files " sha1sum -c archive_sums.txt && " " test -f passfd-src.tar.gz && " " test -f ns3-src.tar.gz " " ) || ( " # nope? re-download - " rm -f pybindgen-src.zip pygccxml-1.0.0.zip passfd-src.tar.gz ns3-src.tar.gz && " - " wget -q -c -O pybindgen-src.tar.gz %(pybindgen_source_url)s && " # continue, to exploit the case when it has already been dl'ed + " rm -rf pybindgen pygccxml-1.0.0.zip passfd-src.tar.gz ns3-src.tar.gz && " + " bzr checkout lp:pybindgen -r %(pybindgen_version)s && " # continue, to exploit the case when it has already been dl'ed " wget -q -c -O pygccxml-1.0.0.zip %(pygccxml_source_url)s && " " wget -q -c -O passfd-src.tar.gz %(passfd_source_url)s && " " wget -q -c -O ns3-src.tar.gz %(ns3_source_url)s && " " sha1sum -c archive_sums.txt " # Check SHA1 sums when applicable " ) && " "unzip -n pygccxml-1.0.0.zip && " - "mkdir -p pybindgen-src && " "mkdir -p ns3-src && " "mkdir -p passfd-src && " "tar xzf ns3-src.tar.gz --strip-components=1 -C ns3-src && " "tar xzf passfd-src.tar.gz --strip-components=1 -C passfd-src && " - "tar xzf pybindgen-src.tar.gz --strip-components=1 -C pybindgen-src && " "rm -rf target && " # mv doesn't like unclean targets "mkdir -p target && " "cd pygccxml-1.0.0 && " @@ -945,7 +967,7 @@ class NS3Dependency(Dependency): "python setup.py build && " "python setup.py install --install-lib ${BUILD}/target && " "python setup.py clean && " - "cd ../pybindgen-src && " + "cd ../pybindgen && " "export PYTHONPATH=$PYTHONPATH:${BUILD}/target && " "./waf configure --prefix=${BUILD}/target -d release && " "./waf && " @@ -962,12 +984,12 @@ class NS3Dependency(Dependency): "./waf &&" "./waf install && " "rm -f ${BUILD}/target/lib/*.so && " - "cp -a ${BUILD}/ns3-src/build/release/libns3*.so ${BUILD}/target/lib && " - "cp -a ${BUILD}/ns3-src/build/release/bindings/python/ns ${BUILD}/target/lib &&" + "cp -a ${BUILD}/ns3-src/build/libns3*.so ${BUILD}/target/lib && " + "cp -a ${BUILD}/ns3-src/build/bindings/python/ns ${BUILD}/target/lib &&" "./waf clean " " )" % dict( - pybindgen_source_url = server.shell_escape(pybindgen_source_url), + pybindgen_version = server.shell_escape(pybindgen_version), pygccxml_source_url = server.shell_escape(pygccxml_source_url), ns3_source_url = server.shell_escape(ns3_source_url), passfd_source_url = server.shell_escape(passfd_source_url), @@ -1091,3 +1113,132 @@ class YumDependency(Dependency): r')', re.I) return badre.search(out) or badre.search(err) or self.node.check_bad_host(out,err) + + +class CCNxDaemon(Application): + """ + An application also has dependencies, but also a command to be ran and monitored. + + It adds the output of that command as traces. + """ + + def __init__(self, api=None): + super(CCNxDaemon,self).__init__(api) + + # Attributes + self.ccnLocalPort = None + self.ccnRoutes = None + self.ccnxVersion = "0.7.1" + + #self.ccnx_0_6_0_sources = "http://yans.pl.sophia.inria.fr/libs/ccnx-0.6.0.tar.gz" + self.ccnx_sources = "http://www.ccnx.org/releases/ccnx-%s.tar.gz" + self.buildDepends = 'make gcc openssl-devel expat-devel libpcap-devel libxml2-devel' + + self.ccnx_build = ( + " ( " + " cd .. && " + " test -d ccnx-src/build/bin " + " ) || ( " + # Not working, rebuild + "(" + " mkdir -p ccnx-src && " + " wget -q -c -O ccnx-src.tar.gz %(ccnx_source_url)s &&" + " tar xf ccnx-src.tar.gz --strip-components=1 -C ccnx-src " + ") && " + "cd ccnx-src && " + "./configure && make" + " )") % dict( + ccnx_source_url = server.shell_escape(self.ccnx_sources % self.ccnxVersion), + ) + + self.ccnx_install = ( + " ( " + " test -d ${BUILD}/ccnx-src/bin && " + " cp -r ${BUILD}/ccnx-src/bin ${SOURCES}" + " )" + ) + + self.env['PATH'] = "$PATH:${SOURCES}/bin" + + def setup(self): + # setting ccn sources + if not self.build: + self.build = self.ccnx_build + + if not self.install: + self.install = self.ccnx_install + + super(CCNxDaemon, self).setup() + + def start(self): + self.command = "" + if self.ccnLocalPort: + self.command = "export CCN_LOCAL_PORT=%s ; " % self.ccnLocalPort + self.command += " ccndstart " + + # configure ccn routes + if self.ccnRoutes: + routes = self.ccnRoutes.split("|") + + if self.ccnLocalPort: + routes = map(lambda route: "%s %s" %(route, + self.ccnLocalPort) if _ccnre.match(route) else route, + routes) + + routes = map(lambda route: "ccndc add ccnx:/ %s" % route, + routes) + + routescmd = " ; ".join(routes) + self.command += " ; " + self.command += routescmd + + # Start will be invoked in prestart step + super(CCNxDaemon, self).start() + + def kill(self): + self._logger.info("Killing %s", self) + + command = "${SOURCES}/bin/ccndstop" + + if self.ccnLocalPort: + self.command = "export CCN_LOCAL_PORT=%s; %s" % (self.ccnLocalPort, command) + + cmd = self._replace_paths(command) + command = cStringIO.StringIO() + command.write(cmd) + command.seek(0) + + try: + self._popen_scp( + command, + '%s@%s:%s' % (self.node.slicename, self.node.hostname, + os.path.join(self.home_path, "kill.sh")) + ) + except RuntimeError, e: + raise RuntimeError, "Failed to kill ccndxdaemon: %s %s" \ + % (e.args[0], e.args[1],) + + + script = "bash ./kill.sh" + (out,err),proc = rspawn.remote_spawn( + script, + pidfile = 'kill-pid', + home = self.home_path, + stdin = '/dev/null', + stdout = 'killlog', + stderr = rspawn.STDOUT, + + host = self.node.hostname, + port = None, + user = self.node.slicename, + agent = None, + ident_key = self.node.ident_path, + server_key = self.node.server_key, + hostip = self.node.hostip, + ) + + if proc.wait(): + raise RuntimeError, "Failed to kill cnnxdaemon: %s %s" % (out,err,) + + super(CCNxDaemon, self).kill() +