~rlane/nova/lp773690

« back to all changes in this revision

Viewing changes to nova/service.py

  • Committer: rlane at wikimedia
  • Date: 2011-04-29 22:30:40 UTC
  • mfrom: (382.1.655 nova)
  • Revision ID: rlane@wikimedia.org-20110429223040-i0x3ds9eqwrabyru
MergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#    License for the specific language governing permissions and limitations
18
18
#    under the License.
19
19
 
20
 
"""
21
 
Generic Node baseclass for all workers that run on hosts
22
 
"""
 
20
"""Generic Node baseclass for all workers that run on hosts."""
23
21
 
24
22
import inspect
25
23
import os
30
28
from eventlet import greenthread
31
29
from eventlet import greenpool
32
30
 
33
 
from sqlalchemy.exc import OperationalError
34
 
 
35
31
from nova import context
36
32
from nova import db
37
33
from nova import exception
 
34
from nova import flags
38
35
from nova import log as logging
39
 
from nova import flags
40
36
from nova import rpc
41
37
from nova import utils
42
38
from nova import version
79
75
 
80
76
    def start(self):
81
77
        vcs_string = version.version_string_with_vcs()
82
 
        logging.audit(_("Starting %(topic)s node (version %(vcs_string)s)"),
 
78
        logging.audit(_('Starting %(topic)s node (version %(vcs_string)s)'),
83
79
                      {'topic': self.topic, 'vcs_string': vcs_string})
84
80
        self.manager.init_host()
85
81
        self.model_disconnected = False
140
136
        return getattr(manager, key)
141
137
 
142
138
    @classmethod
143
 
    def create(cls,
144
 
               host=None,
145
 
               binary=None,
146
 
               topic=None,
147
 
               manager=None,
148
 
               report_interval=None,
149
 
               periodic_interval=None):
 
139
    def create(cls, host=None, binary=None, topic=None, manager=None,
 
140
               report_interval=None, periodic_interval=None):
150
141
        """Instantiates class and passes back application object.
151
142
 
152
 
        Args:
153
 
            host, defaults to FLAGS.host
154
 
            binary, defaults to basename of executable
155
 
            topic, defaults to bin_name - "nova-" part
156
 
            manager, defaults to FLAGS.<topic>_manager
157
 
            report_interval, defaults to FLAGS.report_interval
158
 
            periodic_interval, defaults to FLAGS.periodic_interval
 
143
        :param host: defaults to FLAGS.host
 
144
        :param binary: defaults to basename of executable
 
145
        :param topic: defaults to bin_name - 'nova-' part
 
146
        :param manager: defaults to FLAGS.<topic>_manager
 
147
        :param report_interval: defaults to FLAGS.report_interval
 
148
        :param periodic_interval: defaults to FLAGS.periodic_interval
 
149
 
159
150
        """
160
151
        if not host:
161
152
            host = FLAGS.host
162
153
        if not binary:
163
154
            binary = os.path.basename(inspect.stack()[-1][1])
164
155
        if not topic:
165
 
            topic = binary.rpartition("nova-")[2]
 
156
            topic = binary.rpartition('nova-')[2]
166
157
        if not manager:
167
158
            manager = FLAGS.get('%s_manager' % topic, None)
168
159
        if not report_interval:
175
166
        return service_obj
176
167
 
177
168
    def kill(self):
178
 
        """Destroy the service object in the datastore"""
 
169
        """Destroy the service object in the datastore."""
179
170
        self.stop()
180
171
        try:
181
172
            db.service_destroy(context.get_admin_context(), self.service_id)
182
173
        except exception.NotFound:
183
 
            logging.warn(_("Service killed that has no database entry"))
 
174
            logging.warn(_('Service killed that has no database entry'))
184
175
 
185
176
    def stop(self):
186
177
        for x in self.timers:
198
189
                pass
199
190
 
200
191
    def periodic_tasks(self):
201
 
        """Tasks to be run at a periodic interval"""
 
192
        """Tasks to be run at a periodic interval."""
202
193
        self.manager.periodic_tasks(context.get_admin_context())
203
194
 
204
195
    def report_state(self):
208
199
            try:
209
200
                service_ref = db.service_get(ctxt, self.service_id)
210
201
            except exception.NotFound:
211
 
                logging.debug(_("The service database object disappeared, "
212
 
                                "Recreating it."))
 
202
                logging.debug(_('The service database object disappeared, '
 
203
                                'Recreating it.'))
213
204
                self._create_service_ref(ctxt)
214
205
                service_ref = db.service_get(ctxt, self.service_id)
215
206
 
218
209
                             {'report_count': service_ref['report_count'] + 1})
219
210
 
220
211
            # TODO(termie): make this pattern be more elegant.
221
 
            if getattr(self, "model_disconnected", False):
 
212
            if getattr(self, 'model_disconnected', False):
222
213
                self.model_disconnected = False
223
 
                logging.error(_("Recovered model server connection!"))
 
214
                logging.error(_('Recovered model server connection!'))
224
215
 
225
216
        # TODO(vish): this should probably only catch connection errors
226
217
        except Exception:  # pylint: disable=W0702
227
 
            if not getattr(self, "model_disconnected", False):
 
218
            if not getattr(self, 'model_disconnected', False):
228
219
                self.model_disconnected = True
229
 
                logging.exception(_("model server went away"))
 
220
                logging.exception(_('model server went away'))
230
221
 
231
222
 
232
223
class WsgiService(object):
233
224
    """Base class for WSGI based services.
234
225
 
235
226
    For each api you define, you must also define these flags:
236
 
    :<api>_listen:            The address on which to listen
237
 
    :<api>_listen_port:       The port on which to listen
 
227
    :<api>_listen: The address on which to listen
 
228
    :<api>_listen_port: The port on which to listen
 
229
 
238
230
    """
239
231
 
240
232
    def __init__(self, conf, apis):
250
242
 
251
243
 
252
244
class ApiService(WsgiService):
253
 
    """Class for our nova-api service"""
 
245
    """Class for our nova-api service."""
 
246
 
254
247
    @classmethod
255
248
    def create(cls, conf=None):
256
249
        if not conf:
257
250
            conf = wsgi.paste_config_file(FLAGS.api_paste_config)
258
251
            if not conf:
259
 
                message = (_("No paste configuration found for: %s"),
 
252
                message = (_('No paste configuration found for: %s'),
260
253
                           FLAGS.api_paste_config)
261
254
                raise exception.Error(message)
262
255
        api_endpoints = ['ec2', 'osapi']
280
273
        FLAGS.ParseNewFlags()
281
274
 
282
275
    name = '_'.join(x.binary for x in services)
283
 
    logging.debug(_("Serving %s"), name)
284
 
    logging.debug(_("Full set of FLAGS:"))
 
276
    logging.debug(_('Serving %s'), name)
 
277
    logging.debug(_('Full set of FLAGS:'))
285
278
    for flag in FLAGS:
286
279
        flag_get = FLAGS.get(flag, None)
287
 
        logging.debug("%(flag)s : %(flag_get)s" % locals())
 
280
        logging.debug('%(flag)s : %(flag_get)s' % locals())
288
281
 
289
282
    for x in services:
290
283
        x.start()
315
308
 
316
309
 
317
310
def _run_wsgi(paste_config_file, apis):
318
 
    logging.debug(_("Using paste.deploy config at: %s"), paste_config_file)
 
311
    logging.debug(_('Using paste.deploy config at: %s'), paste_config_file)
319
312
    apps = []
320
313
    for api in apis:
321
314
        config = wsgi.load_paste_configuration(paste_config_file, api)
322
315
        if config is None:
323
 
            logging.debug(_("No paste configuration for app: %s"), api)
 
316
            logging.debug(_('No paste configuration for app: %s'), api)
324
317
            continue
325
 
        logging.debug(_("App Config: %(api)s\n%(config)r") % locals())
326
 
        logging.info(_("Running %s API"), api)
 
318
        logging.debug(_('App Config: %(api)s\n%(config)r') % locals())
 
319
        logging.info(_('Running %s API'), api)
327
320
        app = wsgi.load_paste_app(paste_config_file, api)
328
 
        apps.append((app, getattr(FLAGS, "%s_listen_port" % api),
329
 
                     getattr(FLAGS, "%s_listen" % api)))
 
321
        apps.append((app, getattr(FLAGS, '%s_listen_port' % api),
 
322
                     getattr(FLAGS, '%s_listen' % api)))
330
323
    if len(apps) == 0:
331
 
        logging.error(_("No known API applications configured in %s."),
 
324
        logging.error(_('No known API applications configured in %s.'),
332
325
                      paste_config_file)
333
326
        return
334
327