1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
# Copyright [2010] [Anso Labs, LLC]
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
17
Twisted daemon helpers, specifically to parse out gFlags from twisted flags,
18
manage pid files and support syslogging.
27
import logging.handlers
29
from nova import vendor
30
from twisted.scripts import twistd
31
from twisted.python import log
32
from twisted.python import reflect
33
from twisted.python import runtime
34
from twisted.python import usage
36
from nova import flags
38
if runtime.platformType == "win32":
39
from twisted.scripts._twistw import ServerOptions
41
from twisted.scripts._twistd_unix import ServerOptions
47
class TwistdServerOptions(ServerOptions):
48
def parseArgs(self, *args):
52
def WrapTwistedOptions(wrapped):
53
class TwistedOptionsToFlags(wrapped):
56
# NOTE(termie): _data exists because Twisted stuff expects
57
# to be able to set arbitrary things that are
60
self._flagHandlers = {}
61
self._paramHandlers = {}
63
# Absorb the twistd flags into our FLAGS
65
self._absorbParameters()
66
self._absorbHandlers()
68
super(TwistedOptionsToFlags, self).__init__()
70
def _absorbFlags(self):
72
reflect.accumulateClassList(self.__class__, 'optFlags', twistd_flags)
73
for flag in twistd_flags:
74
key = flag[0].replace('-', '_')
75
flags.DEFINE_boolean(key, None, str(flag[-1]))
77
def _absorbParameters(self):
79
reflect.accumulateClassList(self.__class__, 'optParameters', twistd_params)
80
for param in twistd_params:
81
key = param[0].replace('-', '_')
82
flags.DEFINE_string(key, param[2], str(param[-1]))
84
def _absorbHandlers(self):
86
reflect.addMethodNamesToDict(self.__class__, twistd_handlers, "opt_")
88
# NOTE(termie): Much of the following is derived/copied from
89
# twisted.python.usage with the express purpose of
90
# providing compatibility
91
for name in twistd_handlers.keys():
92
method = getattr(self, 'opt_'+name)
94
takesArg = not usage.flagFunction(method, name)
95
doc = getattr(method, '__doc__', None)
100
if name not in FLAGS:
101
flags.DEFINE_boolean(name, None, doc)
102
self._flagHandlers[name] = method
104
if name not in FLAGS:
105
flags.DEFINE_string(name, None, doc)
106
self._paramHandlers[name] = method
109
def _doHandlers(self):
110
for flag, handler in self._flagHandlers.iteritems():
113
for param, handler in self._paramHandlers.iteritems():
114
if self[param] is not None:
120
def parseOptions(self, options=None):
124
options.insert(0, '')
126
args = FLAGS(options)
131
self.parseArgs(*argv)
133
raise usage.UsageError("Wrong number of arguments.")
138
def parseArgs(self, *args):
139
# TODO(termie): figure out a decent way of dealing with args
141
super(TwistedOptionsToFlags, self).parseArgs(*args)
143
def postOptions(self):
146
super(TwistedOptionsToFlags, self).postOptions()
148
def __getitem__(self, key):
149
key = key.replace('-', '_')
151
return getattr(FLAGS, key)
152
except (AttributeError, KeyError):
153
return self._data[key]
155
def __setitem__(self, key, value):
156
key = key.replace('-', '_')
158
return setattr(FLAGS, key, value)
159
except (AttributeError, KeyError):
160
self._data[key] = value
162
return TwistedOptionsToFlags
169
# Get the pid from the pidfile
171
pf = file(pidfile,'r')
172
pid = int(pf.read().strip())
178
message = "pidfile %s does not exist. Daemon not running?\n"
179
sys.stderr.write(message % pidfile)
180
return # not an error in a restart
182
# Try killing the daemon process
185
os.kill(pid, signal.SIGKILL)
189
if err.find("No such process") > 0:
190
if os.path.exists(pidfile):
198
logging.debug("Serving %s" % filename)
199
name = os.path.basename(filename)
200
OptionsClass = WrapTwistedOptions(TwistdServerOptions)
201
options = OptionsClass()
202
argv = options.parseOptions()
203
logging.getLogger('amqplib').setLevel(logging.WARN)
204
FLAGS.python = filename
206
if not FLAGS.pidfile:
207
FLAGS.pidfile = '%s.pid' % name
208
elif FLAGS.pidfile.endswith('twistd.pid'):
209
FLAGS.pidfile = FLAGS.pidfile.replace('twistd.pid', '%s.pid' % name)
211
if not FLAGS.logfile:
212
FLAGS.logfile = '%s.log' % name
221
elif action == 'restart':
223
elif action == 'start':
226
print 'usage: %s [options] [start|stop|restart]' % argv[0]
229
formatter = logging.Formatter(
230
name + '(%(name)s): %(levelname)s %(message)s')
231
handler = logging.StreamHandler(log.StdioOnnaStick())
232
handler.setFormatter(formatter)
233
logging.getLogger().addHandler(handler)
236
logging.getLogger().setLevel(logging.DEBUG)
238
logging.getLogger().setLevel(logging.WARNING)
241
syslog = logging.handlers.SysLogHandler(address='/dev/log')
242
syslog.setFormatter(formatter)
243
logging.getLogger().addHandler(syslog)
245
logging.debug("Full set of FLAGS:")
247
logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
249
twistd.runApp(options)