from nepi.execution.attribute import Attribute, Flags, Types
from nepi.execution.trace import Trace, TraceAttr
from nepi.execution.resource import ResourceManager, clsinit, ResourceState, \
- reschedule_delay
+ reschedule_delay
from nepi.resources.linux.node import LinuxNode
from nepi.util.sshfuncs import ProcStatus
from nepi.util.timefuncs import tnow, tdiffsec
import subprocess
# TODO: Resolve wildcards in commands!!
+# TODO: When a failure occurs during deployment, scp and ssh processes are left running behind!!
@clsinit
class LinuxApplication(ResourceManager):
"""
_rtype = "LinuxApplication"
+ _help = "Runs an application on a Linux host with a BASH command "
+ _backend_type = "linux"
+
@classmethod
def _register_attributes(cls):
# Since provisioning takes a long time, before
# each step we check that the EC is still
for step in steps:
- if self.ec.finished:
+ if self.ec.abort:
raise RuntimeError, "EC finished"
ret = step()
depends = self.get("depends")
if depends:
self.info("Installing dependencies %s" % depends)
- self.node.install_packages(depends, self.app_home, self.run_home)
+ return self.node.install_packages_command(depends)
def build(self):
build = self.get("build")
self.provision()
except:
self.fail()
- raise
+ return
super(LinuxApplication, self).deploy()
-
+
def start(self):
command = self.get("command")
if not command:
# If no command was given (i.e. Application was used for dependency
# installation), then the application is directly marked as FINISHED
- self._state = ResourceState.FINISHED
+ self.set_finished()
else:
- if self.in_foreground:
- self._run_in_foreground()
- else:
- self._run_in_background()
+ try:
+ if self.in_foreground:
+ self._run_in_foreground()
+ else:
+ self._run_in_background()
+ except:
+ self.fail()
+ return
super(LinuxApplication, self).start()
blocking = False)
if self._proc.poll():
- self.fail()
self.error(msg, out, err)
raise RuntimeError, msg
msg = " Failed to start command '%s' " % command
if proc.poll():
- self.fail()
self.error(msg, out, err)
raise RuntimeError, msg
# Out is what was written in the stderr file
if err:
- self.fail()
msg = " Failed to start command '%s' " % command
self.error(msg, out, err)
raise RuntimeError, msg
if self.state == ResourceState.STARTED:
- self.info("Stopping command '%s'" % command)
+ self.info("Stopping command '%s' " % command)
# If the command is running in foreground (it was launched using
# the node 'execute' method), then we use the handler to the Popen
# process to kill it. Else we send a kill signal using the pid and ppid
# retrieved after running the command with the node 'run' method
- stopped = True
-
if self._proc:
self._proc.kill()
else:
(out, err), proc = self.node.kill(self.pid, self.ppid,
sudo = self._sudo_kill)
+ # TODO: check if execution errors occurred
if proc.poll() or err:
- # check if execution errors occurred
msg = " Failed to STOP command '%s' " % self.get("command")
self.error(msg, out, err)
self.fail()
-
- if self.state == ResourceState.STARTED:
+ return
+
super(LinuxApplication, self).stop()
def release(self):
self.stop()
- if self.state == ResourceState.STOPPED:
- self.info("Resource released")
-
- super(LinuxApplication, self).release()
-
+ super(LinuxApplication, self).release()
+
@property
def state(self):
""" Returns the state of the application
err = self._proc.stderr.read()
self.error(msg, out, err)
self.fail()
- elif retcode == 0:
- self._state = ResourceState.FINISHED
+ elif retcode == 0:
+ self.finish()
else:
# We need to query the status of the command we launched in
# background. In order to avoid overwhelming the remote host and
self.run_home)
if err:
- msg = " Failed to execute command '%s'" % \
+ msg = "Failed to execute command '%s'" % \
self.get("command")
self.error(msg, out, err)
self.fail()
else:
- self._state = ResourceState.FINISHED
+ self.finish()
self._last_state_check = tnow()