-#!/usr/bin/env python
# -*- coding: utf-8 -*-
from constants import TESTBED_ID
import socket
import threading
import logging
+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.
self._master_passphrase = None
self._master_prk = None
self._master_puk = None
- self._master_token = ''.join(map(chr,[rng.randint(0,255)
- for rng in (random.SystemRandom(),)
- for i in xrange(8)] )).encode("hex")
+ self._master_token = os.urandom(8).encode("hex")
self._build_pid = None
self._build_ppid = None
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"
if self.node.slicename is None:
raise AssertionError, "Misconfigured application: unspecified slice"
+ def check_bad_host(self, out, err):
+ """
+ Called whenever an operation fails, it's given the output to be checked for
+ telltale signs of unhealthy hosts.
+ """
+ return False
+
def remote_trace_path(self, whichtrace):
if whichtrace in self.TRACES:
tracefile = os.path.join(self.home_path, whichtrace)
tracefile = None
return tracefile
-
+
+ def remote_trace_name(self, whichtrace):
+ if whichtrace in self.TRACES:
+ return whichtrace
+ return None
+
def sync_trace(self, local_dir, whichtrace):
tracefile = self.remote_trace_path(whichtrace)
if not tracefile:
raise exctyp,exval,exctrace
else:
raise RuntimeError, "Failed to setup application"
+ else:
+ self._logger.info("Setup ready: %s at %s", self, self.node.hostname)
else:
self.setup()
try:
self._popen_ssh_command(
"mkdir -p %(home)s && ( rm -f %(home)s/{pid,build-pid,nepi-build.sh} >/dev/null 2>&1 || /bin/true )" \
- % { 'home' : server.shell_escape(self.home_path) }
+ % { 'home' : server.shell_escape(self.home_path) },
+ timeout = 120,
+ retry = 3
)
except RuntimeError, e:
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') ),
)
.replace("${SOURCES}", root+server.shell_escape(self.home_path))
.replace("${BUILD}", root+server.shell_escape(os.path.join(self.home_path,'build'))) )
- def _launch_build(self):
+ def _launch_build(self, trial=0):
if self._master is not None:
- self._do_install_keys()
+ if not trial or self._master_prk is not None:
+ self._do_install_keys()
buildscript = self._do_build_slave()
else:
buildscript = self._do_build_master()
if buildscript is not None:
- self._logger.info("Building %s", self)
+ self._logger.info("Building %s at %s", self, self.node.hostname)
# upload build script
try:
if self.sources:
sources = self.sources.split(' ')
files.update(
- "%s@%s:%s" % (self._master.node.slicename, self._master.node.hostname,
+ "%s@%s:%s" % (self._master.node.slicename, self._master.node.hostip,
os.path.join(self._master.home_path, os.path.basename(source)),)
for source in sources
)
if self.build:
files.add(
- "%s@%s:%s" % (self._master.node.slicename, self._master.node.hostname,
+ "%s@%s:%s" % (self._master.node.slicename, self._master.node.hostip,
os.path.join(self._master.home_path, 'build.tar.gz'),)
)
+ sshopts = "-o ConnectTimeout=30 -o ConnectionAttempts=3 -o ServerAliveInterval=30 -o TCPKeepAlive=yes"
+
launch_agent = "{ ( echo -e '#!/bin/sh\\ncat' > .ssh-askpass ) && chmod u+x .ssh-askpass"\
" && export SSH_ASKPASS=$(pwd)/.ssh-askpass "\
" && ssh-agent > .ssh-agent.sh ; } && . ./.ssh-agent.sh && ( echo $NEPI_MASTER_PASSPHRASE | ssh-add %(prk)s ) && rm -rf %(prk)s %(puk)s" % \
kill_agent = "kill $SSH_AGENT_PID"
- waitmaster = "{ . ./.ssh-agent.sh ; while [[ $(ssh -q -o UserKnownHostsFile=%(hostkey)s %(master)s cat %(token_path)s) != %(token)s ]] ; do sleep 5 ; done ; }" % {
+ waitmaster = (
+ "{ "
+ "echo 'Checking master reachability' ; "
+ "if ping -c 3 %(master_host)s && (. ./.ssh-agent.sh > /dev/null ; ssh -o UserKnownHostsFile=%(hostkey)s %(sshopts)s %(master)s echo MASTER SAYS HI ) ; then "
+ "echo 'Master node reachable' ; "
+ "else "
+ "echo 'MASTER NODE UNREACHABLE' && "
+ "exit 1 ; "
+ "fi ; "
+ ". ./.ssh-agent.sh ; "
+ "while [[ $(. ./.ssh-agent.sh > /dev/null ; ssh -q -o UserKnownHostsFile=%(hostkey)s %(sshopts)s %(master)s cat %(token_path)s.retcode || /bin/true) != %(token)s ]] ; do sleep 5 ; done ; "
+ "if [[ $(. ./.ssh-agent.sh > /dev/null ; ssh -q -o UserKnownHostsFile=%(hostkey)s %(sshopts)s %(master)s cat %(token_path)s || /bin/true) != %(token)s ]] ; then echo BAD TOKEN ; exit 1 ; fi ; "
+ "}"
+ ) % {
'hostkey' : 'master_known_hosts',
- 'master' : "%s@%s" % (self._master.node.slicename, self._master.node.hostname),
+ 'master' : "%s@%s" % (self._master.node.slicename, self._master.node.hostip),
+ 'master_host' : self._master.node.hostip,
'token_path' : os.path.join(self._master.home_path, 'build.token'),
'token' : server.shell_escape(self._master._master_token),
+ 'sshopts' : sshopts,
}
- syncfiles = "scp -p -o UserKnownHostsFile=%(hostkey)s %(files)s ." % {
+ syncfiles = ". ./.ssh-agent.sh && scp -p -o UserKnownHostsFile=%(hostkey)s %(sshopts)s %(files)s ." % {
'hostkey' : 'master_known_hosts',
'files' : ' '.join(files),
+ 'sshopts' : sshopts,
}
if self.build:
syncfiles += " && tar xzf build.tar.gz"
syncfiles += " && ( echo %s > build.token )" % (server.shell_escape(self._master_token),)
+ syncfiles += " && ( echo %s > build.token.retcode )" % (server.shell_escape(self._master_token),)
syncfiles = "{ . ./.ssh-agent.sh ; %s ; }" % (syncfiles,)
cleanup = "{ . ./.ssh-agent.sh ; kill $SSH_AGENT_PID ; rm -rf %(prk)s %(puk)s master_known_hosts .ssh-askpass ; }" % {
'puk' : server.shell_escape(self._master_puk_name),
}
- slavescript = "( ( %(launch_agent)s && %(waitmaster)s && %(syncfiles)s && %(kill_agent)s && %(cleanup)s ) || %(cleanup)s )" % {
+ slavescript = "( ( %(launch_agent)s && %(waitmaster)s && %(syncfiles)s && %(kill_agent)s && %(cleanup)s ) || %(cleanup)s ) ; echo %(token)s > build.token.retcode" % {
'waitmaster' : waitmaster,
'syncfiles' : syncfiles,
'cleanup' : cleanup,
'kill_agent' : kill_agent,
'launch_agent' : launch_agent,
'home' : server.shell_escape(self.home_path),
+ 'token' : server.shell_escape(self._master_token),
}
-
+
return cStringIO.StringIO(slavescript)
def _do_launch_build(self):
user = self.node.slicename,
agent = None,
ident_key = self.node.ident_path,
- server_key = self.node.server_key
+ server_key = self.node.server_key,
+ hostip = self.node.hostip,
)
if proc.wait():
+ if self.check_bad_host(out, err):
+ self.node.blacklist()
raise RuntimeError, "Failed to set up build slave %s: %s %s" % (self.home_path, out,err,)
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,
ident_key = self.node.ident_path,
- server_key = self.node.server_key
+ server_key = self.node.server_key,
+ hostip = self.node.hostip
)
if pidtuple:
else:
raise RuntimeError, "Failed to set up build slave %s: cannot get pid" % (self.home_path,)
- self._logger.info("Deploying %s", self)
+ self._logger.info("Deploying %s at %s", self, self.node.hostname)
- def _do_wait_build(self):
+ def _do_wait_build(self, trial=0):
pid = self._build_pid
ppid = self._build_ppid
if pid and ppid:
delay = 1.0
first = True
+ bustspin = 0
while True:
status = rspawn.remote_status(
pid, ppid,
user = self.node.slicename,
agent = None,
ident_key = self.node.ident_path,
- server_key = self.node.server_key
+ server_key = self.node.server_key,
+ hostip = self.node.hostip
)
- if status is not rspawn.RUNNING:
+ if status is rspawn.FINISHED:
self._build_pid = self._build_ppid = None
break
+ elif status is not rspawn.RUNNING:
+ self._logger.warn("Busted waiting for %s to finish building at %s %s", self, self.node.hostname,
+ "(build slave)" if self._master is not None else "(build master)")
+ bustspin += 1
+ time.sleep(delay*(5.5+random.random()))
+ if bustspin > 12:
+ self._build_pid = self._build_ppid = None
+ break
else:
if first:
- self._logger.info("Waiting for %s to finish building %s", self,
+ self._logger.info("Waiting for %s to finish building at %s %s", self, self.node.hostname,
"(build slave)" if self._master is not None else "(build master)")
first = False
time.sleep(delay*(0.5+random.random()))
delay = min(30,delay*1.2)
-
+ bustspin = 0
+
# check build token
- (out, err), proc = self._popen_ssh_command(
- "cat %(token_path)s" % {
- 'token_path' : os.path.join(self.home_path, 'build.token'),
- },
- noerrors = True)
slave_token = ""
- if not proc.wait() and out:
- slave_token = out.strip()
+ for i in xrange(3):
+ (out, err), proc = self._popen_ssh_command(
+ "cat %(token_path)s" % {
+ 'token_path' : os.path.join(self.home_path, 'build.token'),
+ },
+ timeout = 120,
+ noerrors = True)
+ if not proc.wait() and out:
+ slave_token = out.strip()
+
+ if slave_token:
+ break
+ else:
+ time.sleep(2)
if slave_token != self._master_token:
# Get buildlog for the error message
'buildlog' : os.path.join(self.home_path, 'buildlog'),
'buildscript' : os.path.join(self.home_path, 'nepi-build.sh'),
},
+ timeout = 120,
noerrors = True)
proc.wait()
- raise RuntimeError, "Failed to set up application %s: "\
- "build failed, got wrong token from pid %s/%s "\
- "(expected %r, got %r), see buildlog: %s" % (
- self.home_path, pid, ppid, self._master_token, slave_token, buildlog)
+ if self.check_bad_host(buildlog, err):
+ self.node.blacklist()
+ elif self._master and trial < 3 and 'BAD TOKEN' in buildlog or 'BAD TOKEN' in err:
+ # bad sync with master, may try again
+ # but first wait for master
+ self._master.async_setup_wait()
+ self._launch_build(trial+1)
+ return self._do_wait_build(trial+1)
+ elif trial < 3:
+ return self._do_wait_build(trial+1)
+ else:
+ # No longer need'em
+ self._master_prk = None
+ self._master_puk = None
+
+ raise RuntimeError, "Failed to set up application %s: "\
+ "build failed, got wrong token from pid %s/%s "\
+ "(expected %r, got %r), see buildlog at %s:\n%s" % (
+ self.home_path, pid, ppid, self._master_token, slave_token, self.node.hostname, buildlog)
- self._logger.info("Built %s", self)
+ # No longer need'em
+ self._master_prk = None
+ self._master_puk = None
+
+ self._logger.info("Built %s at %s", self, self.node.hostname)
def _do_kill_build(self):
pid = self._build_pid
port = None,
user = self.node.slicename,
agent = None,
- ident_key = self.node.ident_path
+ ident_key = self.node.ident_path,
+ hostip = self.node.hostip
)
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,
buildscript = cStringIO.StringIO()
+ buildscript.write("(\n")
+
if self.buildDepends:
# Install build dependencies
buildscript.write(
buildscript.write("tar czf build.tar.gz build\n")
# Write token
- buildscript.write("echo %(master_token)s > build.token" % {
+ buildscript.write("echo %(master_token)s > build.token ) ; echo %(master_token)s > build.token.retcode" % {
'master_token' : server.shell_escape(self._master_token)
})
def _do_install(self):
if self.install:
- self._logger.info("Installing %s", self)
-
+ 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:
- raise RuntimeError, "Failed install build sources: %s %s" % (e.args[0], e.args[1],)
+ if self.check_bad_host(e.args[0], e.args[1]):
+ self.node.blacklist()
+ 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
try:
self._popen_scp(
cStringIO.StringIO('%s,%s %s\n' % (
- self._master.node.hostname, socket.gethostbyname(self._master.node.hostname),
+ self._master.node.hostname, self._master.node.hostip,
self._master.node.server_key)),
'%s@%s:%s' % (self.node.slicename, self.node.hostname,
os.path.join(self.home_path,"master_known_hosts") )
raise RuntimeError, "Failed to set up application deployment keys: %s %s" \
% (e.args[0], e.args[1],)
- # No longer need'em
- self._master_prk = None
- self._master_puk = None
def cleanup(self):
# make sure there's no leftover build processes
self._do_kill_build()
+
+ # No longer need'em
+ self._master_prk = None
+ self._master_puk = None
@server.eintr_retry
- def _popen_scp(self, src, dst, retry = True):
- (out,err),proc = server.popen_scp(
- src,
- dst,
- port = None,
- agent = None,
- ident_key = self.node.ident_path,
- server_key = self.node.server_key
- )
+ def _popen_scp(self, src, dst, retry = 3):
+ while 1:
+ try:
+ (out,err),proc = server.popen_scp(
+ src,
+ dst,
+ port = None,
+ agent = None,
+ ident_key = self.node.ident_path,
+ server_key = self.node.server_key
+ )
- if server.eintr_retry(proc.wait)():
- raise RuntimeError, (out, err)
- return (out, err), proc
+ if server.eintr_retry(proc.wait)():
+ raise RuntimeError, (out, err)
+ return (out, err), proc
+ except:
+ if retry <= 0:
+ raise
+ else:
+ retry -= 1
@server.eintr_retry
- def _popen_ssh_command(self, command, retry = True, noerrors=False):
+ def _popen_ssh_command(self, command, retry = 0, noerrors=False, timeout=None):
(out,err),proc = server.popen_ssh_command(
command,
host = self.node.hostname,
user = self.node.slicename,
agent = None,
ident_key = self.node.ident_path,
- server_key = self.node.server_key
+ server_key = self.node.server_key,
+ timeout = timeout,
+ retry = retry
)
if server.eintr_retry(proc.wait)():
It adds the output of that command as traces.
"""
- TRACES = ('stdout','stderr','buildlog')
+ TRACES = ('stdout','stderr','buildlog', 'output')
def __init__(self, api=None):
super(Application,self).__init__(api)
self.stdin = None
self.stdout = None
self.stderr = None
+ self.output = None
# Those are filled when the app is started
# Having both pid and ppid makes it harder
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,
)
if proc.wait():
+ if self.check_bad_host(out, err):
+ self.node.blacklist()
raise RuntimeError, "Failed to set up application: %s %s" % (out,err,)
self._started = True
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 .. && "
# 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 && "
"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 && "
"python setup.py install --install-lib ${BUILD}/target && "
"python setup.py clean && "
"cd ../ns3-src && "
- "./waf configure --prefix=${BUILD}/target --with-pybindgen=../pybindgen-src -d release --disable-examples --disable-tests --enable-threading && "
+ "./waf configure --prefix=${BUILD}/target --with-pybindgen=../pybindgen-src -d release --disable-examples --disable-tests && "
"./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),
"tar -C /var/cache/yum -rf ${BUILD}/packages.tar $(cd /var/cache/yum ; find -iname '*.rpm')"
" ) || /bin/true ) && "
"sudo -S sed -i -r 's/keepcache *= *1/keepcache=0/' /etc/yum.conf && "
- "sudo -S nice yum -y clean packages "
+ "( sudo -S nice yum -y clean packages || /bin/true ) "
) % ( depends, )
def _build_set(self, value):
# ignore
# unpack cached rpms into yum cache, install, and cleanup
return (
- "tar -k --keep-newer-files -C /var/cache/yum -xf packages.tar && "
+ "sudo -S tar -k --keep-newer-files -C /var/cache/yum -xf packages.tar && "
"sudo -S nice yum -y install %s && "
- "sudo -S nice yum -y clean packages "
+ "( sudo -S nice yum -y clean packages || /bin/true ) "
) % ( depends, )
def _install_set(self, value):
# ignore
return
install = property(_install_get, _install_set)
+ def check_bad_host(self, out, err):
+ badre = re.compile(r'(?:'
+ r'The GPG keys listed for the ".*" repository are already installed but they are not correct for this package'
+ r'|Error: Cannot retrieve repository metadata (repomd.xml) for repository: .*[.] Please verify its path and try again'
+ r'|Error: disk I/O error'
+ r'|MASTER NODE UNREACHABLE'
+ 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()
+