2 # -*- coding: utf-8 -*-
4 from constants import TESTBED_ID
9 import nepi.util.server as server
14 from nepi.util.constants import STATUS_NOT_STARTED, STATUS_RUNNING, \
17 class Application(object):
18 def __init__(self, api=None):
29 self.buildDepends = None
37 # Those are filled when the app is configured
39 self.ident_path = None
42 # Those are filled when an actual node is connected
45 # Those are filled when the app is started
46 # Having both pid and ppid makes it harder
47 # for pid rollover to induce tracking mistakes
53 return "%s<command:%s%s>" % (
54 self.__class__.__name__,
55 "sudo " if self.sudo else "",
60 if self.home_path is None:
61 raise AssertionError, "Misconfigured application: missing home path"
62 if self.ident_path is None or not os.access(self.ident_path, os.R_OK):
63 raise AssertionError, "Misconfigured application: missing slice SSH key"
65 raise AssertionError, "Misconfigured application: unconnected node"
66 if self.node.hostname is None:
67 raise AssertionError, "Misconfigured application: misconfigured node"
68 if self.slicename is None:
69 raise AssertionError, "Misconfigured application: unspecified slice"
72 # Start process in a "daemonized" way, using nohup and heavy
73 # stdin/out redirection to avoid connection issues
74 (out,err),proc = rspawn.remote_spawn(
78 home = self.home_path,
79 stdin = 'stdin' if self.stdin is not None else '/dev/null',
80 stdout = 'stdout' if self.stdout else '/dev/null',
81 stderr = 'stderr' if self.stderr else '/dev/null',
84 host = self.node.hostname,
86 user = self.slicename,
88 ident_key = self.ident_path
92 raise RuntimeError, "Failed to set up application: %s %s" % (out,err,)
98 # NOTE: wait a bit for the pidfile to be created
99 if self._started and not self._pid or not self._ppid:
100 pidtuple = rspawn.remote_check_pid(
101 os.path.join(self.home_path,'pid'),
102 host = self.node.hostname,
104 user = self.slicename,
106 ident_key = self.ident_path
110 self._pid, self._ppid = pidtuple
114 if not self._started:
115 return STATUS_NOT_STARTED
116 elif not self._pid or not self._ppid:
117 return STATUS_NOT_STARTED
119 status = rspawn.remote_status(
120 self._pid, self._ppid,
121 host = self.node.hostname,
123 user = self.slicename,
125 ident_key = self.ident_path
128 if status is rspawn.NOT_STARTED:
129 return STATUS_NOT_STARTED
130 elif status is rspawn.RUNNING:
131 return STATUS_RUNNING
132 elif status is rspawn.FINISHED:
133 return STATUS_FINISHED
136 return STATUS_NOT_STARTED
139 status = self.status()
140 if status == STATUS_RUNNING:
141 # kill by ppid+pid - SIGTERM first, then try SIGKILL
143 self._pid, self._ppid,
144 host = self.node.hostname,
146 user = self.slicename,
148 ident_key = self.ident_path
151 def remote_trace_path(self, whichtrace):
152 if whichtrace in ('stdout','stderr'):
153 tracefile = os.path.join(self.home_path, whichtrace)
159 def sync_trace(self, local_dir, whichtrace):
160 tracefile = self.remote_trace_path(whichtrace)
164 local_path = os.path.join(local_dir, tracefile)
166 # create parent local folders
167 proc = subprocess.Popen(
168 ["mkdir", "-p", os.path.dirname(local_path)],
169 stdout = open("/dev/null","w"),
170 stdin = open("/dev/null","r"))
173 raise RuntimeError, "Failed to synchronize trace: %s %s" % (out,err,)
176 (out,err),proc = server.popen_scp(
177 '%s@%s:%s' % (self.slicename, self.node.hostname,
182 ident_key = self.ident_path
186 raise RuntimeError, "Failed to synchronize trace: %s %s" % (out,err,)
195 def _make_home(self):
196 # Make sure all the paths are created where
197 # they have to be created for deployment
198 (out,err),proc = server.popen_ssh_command(
199 "mkdir -p %s" % (server.shell_escape(self.home_path),),
200 host = self.node.hostname,
202 user = self.slicename,
204 ident_key = self.ident_path
208 raise RuntimeError, "Failed to set up application: %s %s" % (out,err,)
212 # Write program input
213 (out,err),proc = server.popen_scp(
214 cStringIO.StringIO(self.stdin),
215 '%s@%s:%s' % (self.slicename, self.node.hostname,
216 os.path.join(self.home_path, 'stdin') ),
219 ident_key = self.ident_path
223 raise RuntimeError, "Failed to set up application: %s %s" % (out,err,)
227 sources = self.sources.split(' ')
230 for source in sources:
231 (out,err),proc = server.popen_scp(
233 "%s@%s:%s" % (self.slicename, self.node.hostname,
234 os.path.join(self.home_path,'.'),),
235 ident_key = self.ident_path
239 raise RuntimeError, "Failed upload source file %r: %s %s" % (source, out,err,)
241 if self.buildDepends:
242 # Install build dependencies
243 (out,err),proc = server.popen_ssh_command(
244 "sudo -S yum -y install %(packages)s" % {
245 'packages' : self.buildDepends
247 host = self.node.hostname,
249 user = self.slicename,
251 ident_key = self.ident_path
255 raise RuntimeError, "Failed instal build dependencies: %s %s" % (out,err,)
259 # Install build dependencies
260 (out,err),proc = server.popen_ssh_command(
261 "cd %(home)s ; %(command)s" % {
262 'command' : self.build,
263 'home' : server.shell_escape(self.home_path),
265 host = self.node.hostname,
267 user = self.slicename,
269 ident_key = self.ident_path
273 raise RuntimeError, "Failed instal build sources: %s %s" % (out,err,)