/usr/share/pyshared/juju/lib/service.py is in juju-0.7 0.7-0ubuntu2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | from twisted.internet.defer import inlineCallbacks
from twisted.internet.threads import deferToThread
from juju.errors import ServiceError
import os
import subprocess
def _check_call(args, env=None, output_path=None):
if not output_path:
output_path = os.devnull
with open(output_path, "a") as f:
return subprocess.check_call(
args,
stdout=f.fileno(), stderr=f.fileno(),
env=env)
def _cat(filename, use_sudo=False):
args = ("cat", filename)
if use_sudo and not os.access(filename, os.R_OK):
args = ("sudo",) + args
p = subprocess.Popen(
args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout_data, _ = p.communicate()
r = p.returncode
return (r, stdout_data)
class TwistedDaemonService(object):
"""Manage the starting and stopping of an Agent.
This manager tracks the agent via its --pidfile. The pidfile argument
specifies the location of the pid file that is used to track this service.
"""
def __init__(self, name, pidfile, use_sudo=False):
self._name = name
self._use_sudo = use_sudo
self._description = None
self._environ = None
self._command = None
self._daemon = True
self._output_path = None
self._pid_path = pidfile
self._pid = None
@property
def output_path(self):
if self._output_path is not None:
return self._output_path
return "/tmp/%s.output" % self._name
@output_path.setter
def output_path(self, path):
self._output_path = path
def set_description(self, description):
self._description = description
def set_daemon(self, value):
self._daemon = bool(value)
def set_environ(self, environ):
for k, v in environ.items():
environ[k] = str(v)
self._environ = environ
def set_command(self, command):
if self._daemon:
if "--pidfile" not in command:
command += ["--pidfile", self._pid_path]
else:
# pid file is in command (consume it for get_pid)
idx = command.index("--pidfile")
self._pid_path = command[idx+1]
self._command = command
@inlineCallbacks
def _trash_output(self):
if os.path.exists(self.output_path):
# Just using os.unlink will fail when we're running TEST_SUDO
# tests which hit this code path (because root will own
# self.output_path)
yield self._call("rm", "-f", self.output_path)
if os.path.exists(self._pid_path):
yield self._call("rm", "-f", self._pid_path)
def _call(self, *args, **kwargs):
if self._use_sudo:
if self._environ:
_args = ["%s=%s" % (k, v) for k, v in self._environ.items()]
else:
_args = []
_args.insert(0, "sudo")
_args.extend(args)
args = _args
return deferToThread(_check_call, args, env=self._environ,
output_path=self.output_path)
def install(self):
if self._command is None:
raise ServiceError("Cannot manage agent: %s no command set" % (
self._name))
@inlineCallbacks
def start(self):
if (yield self.is_running()):
raise ServiceError(
"%s already running: pid (%s)" % (
self._name, self.get_pid()))
if not self.is_installed():
yield self.install()
yield self._trash_output()
yield self._call(*self._command, output_path=self.output_path)
@inlineCallbacks
def destroy(self):
if (yield self.is_running()):
yield self._call("kill", self.get_pid())
yield self._trash_output()
def get_pid(self):
if self._pid != None:
return self._pid
if not os.path.exists(self._pid_path):
return None
r, data = _cat(self._pid_path, use_sudo=self._use_sudo)
if r != 0:
return None
# verify that pid is a number but leave
# it as a string suitable for passing to kill
if not data.strip().isdigit():
return None
pid = data.strip()
self._pid = pid
return self._pid
def is_running(self):
pid = self.get_pid()
if not pid:
return False
proc_file = "/proc/%s" % pid
if not os.path.exists(proc_file):
return False
return True
def is_installed(self):
return False
|