Exemple #1
0
def load_paste_app(app_name=None):
    """
    Builds and returns a WSGI app from a paste config file.
    We assume the last config file specified in the supplied ConfigOpts
    object is the paste config file.
    :param app_name: name of the application to load
    :raises RuntimeError when config file cannot be located or application
            cannot be loaded from config file
    """
    if app_name is None:
        app_name = cfg.CONF.prog

    conf_file = _get_deployment_config_file()
    if conf_file is None:
        raise RuntimeError(_("Unable to locate config file"))

    try:
        app = paste_deploy_app(conf_file, app_name, cfg.CONF)

        # Log the options used when starting if we're in debug mode...
        if cfg.CONF.debug:
            cfg.CONF.log_opt_values(logging.getLogger(app_name),
                                    sys_logging.DEBUG)

        return app
    except (LookupError, ImportError) as e:
        raise RuntimeError(_("Unable to load %(app_name)s from "
                             "configuration file %(conf_file)s."
                             "\nGot: %(e)r") % {'app_name': app_name,
                                                'conf_file': conf_file,
                                                'e': e})
Exemple #2
0
def get_socket(conf, default_port):
    """
    Bind socket to bind ip:port in conf

    note: Mostly comes from Swift with a few small changes...

    :param conf: a cfg.ConfigOpts object
    :param default_port: port to bind to if none is specified in conf

    :returns : a socket object as returned from socket.listen or
               ssl.wrap_socket if conf specifies cert_file
    """
    bind_addr = get_bind_addr(conf, default_port)

    # TODO(jaypipes): eventlet's greened socket module does not actually
    # support IPv6 in getaddrinfo(). We need to get around this in the
    # future or monitor upstream for a fix
    address_family = [addr[0] for addr in socket.getaddrinfo(bind_addr[0],
                      bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM)
                      if addr[0] in (socket.AF_INET, socket.AF_INET6)][0]

    cert_file = conf.cert_file
    key_file = conf.key_file
    use_ssl = cert_file or key_file
    if use_ssl and (not cert_file or not key_file):
        raise RuntimeError(_("When running server in SSL mode, you must "
                             "specify both a cert_file and key_file "
                             "option value in your configuration file"))

    sock = None
    retry_until = time.time() + 30
    while not sock and time.time() < retry_until:
        try:
            sock = eventlet.listen(bind_addr, backlog=conf.backlog,
                                   family=address_family)
            if use_ssl:
                sock = ssl.wrap_socket(sock, certfile=cert_file,
                                       keyfile=key_file)
        except socket.error as err:
            if err.args[0] != errno.EADDRINUSE:
                raise
            eventlet.sleep(0.1)
    if not sock:
        raise RuntimeError(_("Could not bind to %(bind_addr)s"
                             "after trying for 30 seconds")
                           % {'bind_addr': bind_addr})
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # in my experience, sockets can hang around forever without keepalive
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

    # This option isn't available in the OS X version of eventlet
    if hasattr(socket, 'TCP_KEEPIDLE'):
        sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 600)

    return sock
Exemple #3
0
 def run_child(self):
     pid = os.fork()
     if pid == 0:
         signal.signal(signal.SIGHUP, signal.SIG_DFL)
         signal.signal(signal.SIGTERM, signal.SIG_DFL)
         self.run_server()
         self.LOG.info(_('Child %d exiting normally') % os.getpid())
         return
     else:
         self.LOG.info(_('Started child %s') % pid)
         self.children.append(pid)
Exemple #4
0
 def _single_run(self, application, sock):
     """Start a WSGI server in a new green thread."""
     self.LOG.info(_("Starting single process server"))
     eventlet.wsgi.server(sock, application,
                          custom_pool=self.pool,
                          url_length_limit=URL_LENGTH_LIMIT,
                          log=WritableLogger(self.LOG),
                          debug=cfg.CONF.debug)
Exemple #5
0
 def hup(*args):
     """
     Shuts down the server(s), but allows running requests to complete
     """
     self.LOG.error(_('SIGHUP received'))
     signal.signal(signal.SIGHUP, signal.SIG_IGN)
     os.killpg(0, signal.SIGHUP)
     signal.signal(signal.SIGHUP, hup)
Exemple #6
0
 def wait_on_children(self):
     while self.running:
         try:
             pid, status = os.wait()
             if os.WIFEXITED(status) or os.WIFSIGNALED(status):
                 self.LOG.error(_('Removing dead child %s') % pid)
                 self.children.remove(pid)
                 self.run_child()
         except OSError as err:
             if err.errno not in (errno.EINTR, errno.ECHILD):
                 raise
         except KeyboardInterrupt:
             self.LOG.info(_('Caught keyboard interrupt. Exiting.'))
             os.killpg(0, signal.SIGTERM)
             break
     eventlet.greenio.shutdown_safe(self.sock)
     self.sock.close()
     self.LOG.debug('Exited')
Exemple #7
0
 def from_json(self, datastring):
     try:
         if len(datastring) > cfg.CONF.max_json_body_size:
             msg = _('JSON body size (%(len)s bytes) exceeds maximum '
                     'allowed size (%(limit)s bytes).') % \
                 {'len': len(datastring),
                  'limit': cfg.CONF.max_json_body_size}
             raise exception.RequestLimitExceeded(message=msg)
         return json.loads(datastring)
     except ValueError as ex:
         raise webob.exc.HTTPBadRequest(six.text_type(ex))
Exemple #8
0
    def __init__(self, **kwargs):
        self.kwargs = kwargs

        try:
            self.message = self.msg_fmt % kwargs
        except KeyError:
            exc_info = sys.exc_info()
            # kwargs doesn't match a variable in the message
            # log the issue and the kwargs
            LOG.exception(_('Exception in string format operation'))
            for name, value in six.iteritems(kwargs):
                LOG.error("%s: %s" % (name, value))  # noqa

            if _FATAL_EXCEPTION_FORMAT_ERRORS:
                raise exc_info[0], exc_info[1], exc_info[2]
Exemple #9
0
    def main():
        try:
            LOG.debug('starting inicialization')

            app = wsgi.load_paste_app("robotice.api")

            port = CONF.command.bind_port
            host = CONF.command.bind_host
            LOG.info(_('Starting Robotice ReST API on %(host)s:%(port)s'),
                     {'host': host, 'port': port})
            server = wsgi.Server()
            server.start(app, CONF.command, default_port=port)
            server.wait()
        except RuntimeError as e:
            msg = six.text_type(e)
            sys.exit("ERROR: %s" % msg)
Exemple #10
0
def print_list(objs, fields, formatters=None, sortby_index=0,
               mixed_case_fields=None, field_labels=None):
    """Print a list or objects as a table, one row per object.

    :param objs: iterable of :class:`Resource`
    :param fields: attributes that correspond to columns, in order
    :param formatters: `dict` of callables for field formatting
    :param sortby_index: index of the field for sorting table rows
    :param mixed_case_fields: fields corresponding to object attributes that
        have mixed case names (e.g., 'serverId')
    :param field_labels: Labels to use in the heading of the table, default to
        fields.
    """
    formatters = formatters or {}
    mixed_case_fields = mixed_case_fields or []
    field_labels = field_labels or fields
    if len(field_labels) != len(fields):
        raise ValueError(_("Field labels list %(labels)s has different number "
                           "of elements than fields list %(fields)s"),
                         {'labels': field_labels, 'fields': fields})

    if sortby_index is None:
        kwargs = {}
    else:
        kwargs = {'sortby': field_labels[sortby_index]}
    pt = prettytable.PrettyTable(field_labels)
    pt.align = 'l'

    for o in objs:
        row = []
        for field in fields:
            if field in formatters:
                row.append(formatters[field](o))
            else:
                if field in mixed_case_fields:
                    field_name = field.replace(' ', '_')
                else:
                    field_name = field.lower().replace(' ', '_')
                data = getattr(o, field_name, '')
                row.append(data)
        pt.add_row(row)

    if six.PY3:
        print(pt.get_string(**kwargs))
    else:
        print(pt.get_string(**kwargs))
Exemple #11
0
    def start(self, application, conf, default_port):
        """
        Run a WSGI server with the given application.

        :param application: The application to run in the WSGI server
        :param conf: a cfg.ConfigOpts object
        :param default_port: Port to bind to if none is specified in conf
        """
        def kill_children(*args):
            """Kills the entire process group."""
            self.LOG.error(_('SIGTERM received'))
            signal.signal(signal.SIGTERM, signal.SIG_IGN)
            self.running = False
            os.killpg(0, signal.SIGTERM)

        def hup(*args):
            """
            Shuts down the server(s), but allows running requests to complete
            """
            self.LOG.error(_('SIGHUP received'))
            signal.signal(signal.SIGHUP, signal.SIG_IGN)
            os.killpg(0, signal.SIGHUP)
            signal.signal(signal.SIGHUP, hup)

        eventlet.wsgi.MAX_HEADER_LINE = self.conf.max_header_line
        self.application = application
        
        self.sock = get_socket(self.conf, default_port)

        self.LOG = logging.getLogger('eventlet.wsgi.server')

        if self.conf.workers == 0:
            # Useful for profiling, test, debug etc.
            self.pool = eventlet.GreenPool(size=self.threads)
            self.pool.spawn_n(self._single_run, application, self.sock)
            return

        self.LOG.info(_("Starting %d workers") % self.conf.workers)
        signal.signal(signal.SIGTERM, kill_children)
        signal.signal(signal.SIGHUP, hup)
        while len(self.children) < self.conf.workers:
            self.run_child()
Exemple #12
0
import routes.middleware
import six
import webob.dec
import webob.exc

from paste import deploy

from robotice.common.i18n import _
from robotice.common import exception
from robotice.utils import serializers

URL_LENGTH_LIMIT = 50000

api_opts = [
    cfg.StrOpt('bind_host', default='0.0.0.0',
               help=_('Address to bind the server. Useful when '
                      'selecting a particular network interface.'),
               deprecated_group='DEFAULT'),
    cfg.IntOpt('bind_port', default=8004,
               help=_('The port on which the server will listen.'),
               deprecated_group='DEFAULT'),
    cfg.IntOpt('backlog', default=4096,
               help=_("Number of backlog requests "
                      "to configure the socket with."),
               deprecated_group='DEFAULT'),
    cfg.StrOpt('cert_file',
               help=_("Location of the SSL certificate file "
                      "to use for SSL mode."),
               deprecated_group='DEFAULT'),
    cfg.StrOpt('key_file',
               help=_("Location of the SSL key file to use "
                      "for enabling SSL mode."),
Exemple #13
0
 def __init__(self, missing):
     self.missing = missing
     msg = _("Missing arguments: %s") % ", ".join(missing)
     super(MissingArgs, self).__init__(msg)
Exemple #14
0
 def __init__(self, msg_fmt=_('Not found')):
     self.msg_fmt = msg_fmt
     super(NotFound, self).__init__()
Exemple #15
0
 def kill_children(*args):
     """Kills the entire process group."""
     self.LOG.error(_('SIGTERM received'))
     signal.signal(signal.SIGTERM, signal.SIG_IGN)
     self.running = False
     os.killpg(0, signal.SIGTERM)
Exemple #16
0
def log_exception(err, exc_info):
    args = {'exc_info': exc_info} if cfg.CONF.verbose or cfg.CONF.debug else {}
    logging.error(_("Unexpected error occurred serving API: %s") % err,
                  **args)
Exemple #17
0
    def __call__(self, request):
        """WSGI method that controls (de)serialization and method dispatch."""
        action_args = self.get_action_args(request.environ)
        action = action_args.pop('action', None)

        content_type = request.params.get("ContentType")

        try:
            deserialized_request = self.dispatch(self.deserializer,
                                                 action, request)
            action_args.update(deserialized_request)

            logging.debug(
                ('Calling %(controller)s : %(action)s'),
                {'controller': self.controller, 'action': action})

            action_result = self.dispatch(self.controller, action,
                                          request, **action_args)
        except TypeError as err:
            logging.error(_('Exception handling resource: %s') % err)
            msg = _('The server could not comply with the request since '
                    'it is either malformed or otherwise incorrect.')
            err = webob.exc.HTTPBadRequest(msg)
            http_exc = translate_exception(err, request.best_match_language())
            # NOTE(luisg): We disguise HTTP exceptions, otherwise they will be
            # treated by wsgi as responses ready to be sent back and they
            # won't make it into the pipeline app that serializes errors
            raise exception.HTTPExceptionDisguise(http_exc)
        except webob.exc.HTTPException as err:
            if not isinstance(err, webob.exc.HTTPError):
                # Some HTTPException are actually not errors, they are
                # responses ready to be sent back to the users, so we don't
                # error log, disguise or translate those
                raise
            if isinstance(err, webob.exc.HTTPServerError):
                logging.error(
                    _("Returning %(code)s to user: %(explanation)s"),
                    {'code': err.code, 'explanation': err.explanation})
            http_exc = translate_exception(err, request.best_match_language())
            raise exception.HTTPExceptionDisguise(http_exc)
        except exception.RoboticeException as err:
            raise translate_exception(err, request.best_match_language())
        except Exception as err:
            log_exception(err, sys.exc_info())
            raise translate_exception(err, request.best_match_language())
        # Here we support either passing in a serializer or detecting it
        # based on the content type.
        try:
            serializer = self.serializer
            if serializer is None:
                if content_type == "JSON":
                    serializer = serializers.JSONResponseSerializer()
                else:
                    serializer = serializers.XMLResponseSerializer()

            response = webob.Response(request=request)
            self.dispatch(serializer, action, response, action_result)
            return response

        # return unserializable result (typically an exception)
        except Exception:
            # Here we should get API exceptions derived from HeatAPIException
            # these implement get_unserialized_body(), which allow us to get
            # a dict containing the unserialized error response.
            # We only need to serialize for JSON content_type, as the
            # exception body is pre-serialized to the default XML in the
            # HeatAPIException constructor
            # If we get something else here (e.g a webob.exc exception),
            # this will fail, and we just return it without serializing,
            # which will not conform to the expected AWS error response format
            if content_type == "JSON":
                try:
                    err_body = action_result.get_unserialized_body()
                    serializer.default(action_result, err_body)
                except Exception:
                    logging.warning(_LW("Unable to serialize exception "
                                    "response"))

            return action_result