This file is indexed.

/usr/share/pyshared/juju/lib/upstart.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
161
162
163
164
165
166
import os
import subprocess
from tempfile import NamedTemporaryFile

from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.internet.threads import deferToThread
from twisted.internet.utils import getProcessOutput

from juju.errors import ServiceError
from juju.lib.twistutils import sleep


_CONF_TEMPLATE = """\
description "%s"
author "Juju Team <juju@lists.ubuntu.com>"

start on runlevel [2345]
stop on runlevel [!2345]
respawn

%s

exec %s >> %s 2>&1
"""

def _silent_check_call(args):
    with open(os.devnull, "w") as f:
        return subprocess.check_call(
            args, stdout=f.fileno(), stderr=f.fileno())


class UpstartService(object):

    # on class for ease of testing
    init_dir = "/etc/init"

    def __init__(self, name, init_dir=None, use_sudo=False):
        self._name = name
        if init_dir is not None:
            self.init_dir = init_dir
        self._use_sudo = use_sudo
        self._output_path = None
        self._description = None
        self._environ = {}
        self._command = None

    @property
    def _conf_path(self):
        return os.path.join(
            self.init_dir, "%s.conf" % self._name)

    @property
    def output_path(self):
        if self._output_path is not None:
            return self._output_path
        return "/tmp/%s.output" % self._name

    def set_description(self, description):
        self._description = description

    def set_environ(self, environ):
        self._environ = environ

    def set_command(self, command):
        self._command = command

    def set_output_path(self, path):
        self._output_path = path

    @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", self.output_path)

    def _render(self):
        if self._description is None:
            raise ServiceError("Cannot render .conf: no description set")
        if self._command is None:
            raise ServiceError("Cannot render .conf: no command set")
        return _CONF_TEMPLATE % (
            self._description,
            "\n".join('env %s="%s"' % kv
                      for kv in sorted(self._environ.items())),
            self._command,
            self.output_path)

    def _call(self, *args):
        if self._use_sudo:
            args = ("sudo",) + args
        return deferToThread(_silent_check_call, args)

    def get_cloud_init_commands(self):
        return ["cat >> %s <<EOF\n%sEOF\n" % (self._conf_path, self._render()),
                "/sbin/start %s" % self._name]

    @inlineCallbacks
    def install(self):
        with NamedTemporaryFile() as f:
            f.write(self._render())
            f.flush()
            yield self._call("cp", f.name, self._conf_path)
        yield self._call("chmod", "644", self._conf_path)

    @inlineCallbacks
    def start(self):
        if not self.is_installed():
            yield self.install()
        if (yield self.is_running()):
            return
        yield self._trash_output()
        yield self._call("/sbin/start", self._name)
        if (yield self.is_stable()):
            return

        output = None
        if os.path.exists(self.output_path):
            with open(self.output_path) as f:
                output = f.read()
        if not output:
            raise ServiceError(
                "Failed to start job %s; no output detected" % self._name)
        raise ServiceError(
            "Failed to start job %s; got output:\n%s" % (self._name, output))

    @inlineCallbacks
    def destroy(self):
        if (yield self.is_running()):
            yield self._call("/sbin/stop", self._name)
        if self.is_installed():
            yield self._call("rm", self._conf_path)
        yield self._trash_output()

    @inlineCallbacks
    def get_pid(self):
        if not self.is_installed():
            returnValue(None)
        status = yield getProcessOutput("/sbin/status", [self._name])
        if "start/running" not in status:
            returnValue(None)
        pid = status.split(" ")[-1]
        returnValue(int(pid))

    @inlineCallbacks
    def is_running(self):
        pid = yield self.get_pid()
        returnValue(pid is not None)

    @inlineCallbacks
    def is_stable(self):
        """Does the process continue to run with the same pid?

        (5 times in a row, with a gap of 0.1s between each check)
        """
        pid = yield self.get_pid()
        if pid is None:
            returnValue(False)
        for _ in range(4):
            yield sleep(0.1)
            if pid != (yield self.get_pid()):
                returnValue(False)
        returnValue(True)

    def is_installed(self):
        return os.path.exists(self._conf_path)