Package wtf :: Package opi
[hide private]
[frames] | no frames]

Source Code for Package wtf.opi

  1  # -*- coding: ascii -*- 
  2  # 
  3  # Copyright 2006-2012 
  4  # Andr\xe9 Malo or his licensors, as applicable 
  5  # 
  6  # Licensed under the Apache License, Version 2.0 (the "License"); 
  7  # you may not use this file except in compliance with the License. 
  8  # You may obtain a copy of the License at 
  9  # 
 10  #     http://www.apache.org/licenses/LICENSE-2.0 
 11  # 
 12  # Unless required by applicable law or agreed to in writing, software 
 13  # distributed under the License is distributed on an "AS IS" BASIS, 
 14  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 15  # See the License for the specific language governing permissions and 
 16  # limitations under the License. 
 17  """ 
 18  OS Process Integration 
 19  ====================== 
 20   
 21  The modules in this package implement the different ways of integration 
 22  within other frameworks. Currently there are: 
 23   
 24  daemon 
 25    The application is running as a standalone daemon, optionally forking itself 
 26    into the background (Not forking is a both a debugging and production 
 27    feature -- imagine integration into djb's daemontools and stuff. 
 28   
 29   
 30  The typical way to load the proper implementation is:: 
 31   
 32      from wtf import opi 
 33      opi.factory(config, opts, args).work() 
 34   
 35  This evaluates the [wtf] section of the config, where the following options 
 36  are recognized: 
 37   
 38  protocol = ``scgi|http`` 
 39    Required option, because there's no sensible default. ``fastcgi`` also 
 40    handles regular CGI if: 
 41   
 42    - detach = no 
 43    - listen = stdin 
 44    - STDIN is a pipe 
 45   
 46    XXX: implement it! 
 47   
 48  mode = ``Integration mode`` 
 49    ``daemon`` is default. 
 50   
 51  basedir = ``path`` 
 52    The directory to change into immediatly after startup. Default is: ``/`` 
 53   
 54  umask = ``umask`` 
 55    The umask to apply. The default umask is 0. The value is interpreted as 
 56    octal number. You can specify ``inherit`` in order to inherit the umask 
 57    from the caller (e.g. the shell). 
 58   
 59  In daemon mode the following options are used to determine the behaviour 
 60  in detail: 
 61   
 62  detach = ``yes|no`` 
 63    Required option, because there's no sensible default. This option determines 
 64    whether the daemon should fork itself into the background or not. If this 
 65    option is set to ``yes``, command line parameters become interesting. 
 66    The last parameter is evaluated and has to be one of the following: 
 67   
 68    start 
 69      Start a new daemon. If there's already one running, this is a failure. 
 70   
 71    stop 
 72      Stop the daemon. If there's none running, this is not a failure. If 
 73      there's one running, this option is identical to sending a 
 74      SIGTERM + SIGCONT to the process in question. 
 75   
 76    logrotate|logreopen 
 77      Reopen the error log file. 
 78   
 79    The presence of another running daemon is determined by the pidfile (which 
 80    is advisory locked for this purpose). Furthermore a forked away daemon 
 81    does the usual detaching magic like closing all descriptors and stuff. This 
 82    especially means, that STDIN, STDOUT and STDERR all point to /dev/null. 
 83    If you specify an ``errorlog`` it will be attached to STDERR. 
 84   
 85  listen = ``[tcp:]host:port | [unix:]path[(perm)] ...`` 
 86    Required option, because there's no sensible default. This option determines 
 87    where the daemon should listen for requests. This is a list of socket 
 88    specifications which can be either TCP/IP or a unix domain sockets (you can 
 89    mix them, if you want.) The optional ``perm`` parameter for unix sockets is 
 90    an octal value and controls the permissions of the socket path. Note that 
 91    socket paths are limited in length by the OS. See ``unix(7)`` for details. 
 92   
 93  workermodel = ``model`` 
 94    Required option, because there's no sensible default. This option determines 
 95    the worker pool implementation. 
 96   
 97  errorlog = ``path`` 
 98    The file which STDERR should be attached to. By default STDERR goes to 
 99    ``/dev/null``. 
100   
101  pidfile = ``path`` 
102    The option is required. It contains the name of the file where the PID of 
103    the main process is written into. The file is also used to determine 
104    a concurrently running daemon by locking it (The lock is automatically 
105    cleared if the daemon dies). 
106   
107  user = ``id|name`` 
108    The user the working process should change to. If the application is 
109    started as root, it's strongly recommended to define such a user. See also 
110    ``group``. If the application is not started as root, the option is ignored. 
111   
112  group = ``id|name`` 
113    The group the working process should change to. If the application is 
114    started as root, it's strongly recommended to define such a group. See also 
115    ``user``. If the application is not started as root, the option is ignored. 
116  """ 
117  __author__ = u"Andr\xe9 Malo" 
118  __docformat__ = "restructuredtext en" 
119   
120  import os as _os 
121   
122  from wtf import Error 
123  from wtf.config import ConfigurationError 
124   
125   
126 -class OPIError(Error):
127 """ OPI error """ 128 exit_code = 1
129
130 -class OPIDone(OPIError):
131 """ OPI done """ 132 exit_code = 0
133 134
135 -class OPIInterface(object):
136 """ 137 Interface for OPI implementations 138 139 :Groups: 140 - `Running Modes`: `MODE_THREADED`, `MODE_FORKED`, `MODE_SINGLE`, 141 `MODE_ONCE` 142 143 :CVariables: 144 - `MODE_THREADED`: multithreaded mode 145 - `MODE_FORKED`: forked mode 146 - `MODE_SINGLE`: single process mode 147 - `MODE_ONCE`: run-once mode (like CGI) 148 149 :IVariables: 150 - `mode`: The running mode (one of the ``Running Modes``) 151 - `config`: The application config 152 153 :Types: 154 - `MODE_THREADED`: ``int`` 155 - `MODE_FORKED`: ``int`` 156 - `MODE_SINGLE`: ``int`` 157 - `MODE_ONCE`: ``int`` 158 159 - `mode`: ``int`` 160 - `config`: `wtf.config.Config` 161 """ 162 MODE_THREADED, MODE_FORKED, MODE_SINGLE, MODE_ONCE = xrange(4) 163
164 - def __init__(self, config, opts, args):
165 """ 166 Initialization 167 168 :Parameters: 169 - `config`: The application config 170 - `opts`: Command line option container 171 - `args`: Fixed commandline arguments 172 173 :Types: 174 - `config`: `wtf.config.Config` 175 - `opts`: ``optparse.OptionContainer`` 176 - `args`: ``list`` 177 """
178
179 - def work(self):
180 """ 181 Invoke the worker mechanism (if any) 182 183 This starts handling the incoming request(s) 184 """
185 186
187 -def factory(config, opts, args):
188 """ 189 Create the OPI instance selected by configuration 190 191 :Parameters: 192 - `config`: configuration 193 - `opts`: Option container 194 - `args`: Fixed arguments 195 196 :Types: 197 - `config`: `config.Config` 198 - `opts`: ``optparse.OptionContainer`` 199 - `args`: ``list`` 200 201 :return: OPI instance 202 :rtype: `OPIInterface` 203 """ 204 self = factory 205 206 basemode = config.wtf('mode', 'daemon') 207 if basemode not in self.basemodes: # pylint: disable = E1101 208 raise ConfigurationError("Unknown mode %s" % basemode) 209 210 basedir = _os.path.normpath( 211 _os.path.join(config.ROOT, config.wtf('basedir', '/'))) 212 _os.chdir(basedir) 213 214 if 'umask' in config.wtf: 215 umask = unicode(config.wtf.umask) 216 if umask.lower() == 'inherit': 217 uval = _os.umask(0) 218 else: 219 try: 220 uval = int(umask, 8) 221 except (ValueError, TypeError), e: 222 raise ConfigurationError("Invalid umask: %s" % str(e)) 223 else: 224 uval = 0 225 _os.umask(uval) 226 227 # pylint: disable = E1101 228 return self.basemodes[basemode](config, opts, args)
229 factory.basemodes = {} # pylint: disable = W0612 230 231
232 -def register(name, klass):
233 """ 234 Register an OPI implementation 235 236 :Parameters: 237 - `name`: The name (in the config) 238 - `klass`: The implementation class 239 240 :Types: 241 - `name`: ``str`` 242 - `klass`: `OPIInterface` 243 """ 244 factory.basemodes[name] = klass # pylint: disable = E1101
245