Beispiel #1
1
def create_app(environment=None):
    """
    Create an app instance
    """
    app = Flask("backend")
    app.url_map.converters["ObjectId"] = BSONObjectIdConverter

    # Config app for environment
    if not environment:
        environment = os.environ.get("BACKEND_ENVIRONMENT", "Local")

    app.config.from_object("backend.backend.settings.%s" % environment)

    # convert exceptions to JSON
    def make_json_error(ex):
        response = jsonify(message=str(ex))
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        return response

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    from backend.backend.views.api import api

    app.register_module(api)

    # initialize modules
    admin.init_app(app)
    db.init_app(app)
    login_manager.setup_app(app)
    mail.init_app(app)

    return app
Beispiel #2
1
    def create_app(environment=None):
        """
        Create an app instance
        """
        app = Flask("core")

        # Allow CORS for all domains on all routes
        CORS(app)

        # Config app for environment
        if not environment:
            environment = os.environ.get("BACKEND_ENVIRONMENT", "Dev")

        app.config.from_object("core.api.settings.%s" % environment)

        # convert exceptions to JSON
        def make_json_error(ex):
            response = jsonify(message=str(ex))
            response.status_code = ex.code if isinstance(ex, HTTPException) else 500

            return response

        for code in default_exceptions.items():
            app.error_handler_spec[None][code] = make_json_error

        from core.api.views.endpoints import api

        app.register_module(api)

        API.app = app
Beispiel #3
1
def make_app(**local_conf):
    """
    Entry point for Elastic Hadoop on OpenStack REST API server
    """
    app = Flask("eho.api")

    # reading defaults
    app.config.from_pyfile("etc/default.cfg", silent=True)
    app.config.from_pyfile("../etc/default.cfg", silent=True)

    # read local conf
    app.config.from_pyfile("etc/local.cfg", silent=True)
    app.config.from_pyfile("../etc/local.cfg", silent=True)

    app.config.from_envvar("EHO_API_CFG", silent=True)
    app.config.update(**local_conf)

    root_logger = logging.getLogger()
    ll = app.config.pop("LOG_LEVEL", "WARN")
    if ll:
        root_logger.setLevel(ll)

    app.register_blueprint(api_v02.rest, url_prefix="/v0.2")

    if app.config["DEBUG"]:
        print "Configuration:"
        for k in app.config:
            print "\t%s = %s" % (k, app.config[k])

    setup_storage(app)
    setup_defaults(app)
    setup_scheduler(app)
    setup_ops(app)
    setup_api(app)

    def make_json_error(ex):
        status_code = ex.code if isinstance(ex, HTTPException) else 500
        description = ex.description if isinstance(ex, HTTPException) else str(ex)
        return render({"error": status_code, "error_message": description}, status=status_code)

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    app.wsgi_app = auth_valid(app.config)(app.wsgi_app)

    app.wsgi_app = auth_token(
        app.config,
        auth_host=app.config["OS_AUTH_HOST"],
        auth_port=app.config["OS_AUTH_PORT"],
        auth_protocol=app.config["OS_AUTH_PROTOCOL"],
        admin_user=app.config["OS_ADMIN_USER"],
        admin_password=app.config["OS_ADMIN_PASSWORD"],
        admin_tenant=["OS_ADMIN_TENANT"],
    )(app.wsgi_app)

    return app
Beispiel #4
0
def make_json_app(import_name, **kwargs):
    """Creates a JSON-oriented Flask app.

    All error responses that you don't specifically manage yourself will have
    application/json content type, and will contain JSON that follows the
    libnetwork remote driver protocol.


    { "Err": "405: Method Not Allowed" }


    See:
      - https://github.com/docker/libnetwork/blob/3c8e06bc0580a2a1b2440fe0792fbfcd43a9feca/docs/remote.md#errors  # noqa
    """
    app = Flask(import_name, **kwargs)

    @app.errorhandler(NeutronClientException)
    def make_json_error(ex):
        response = jsonify({"Err": str(ex)})
        response.status_code = (
            ex.code
            if isinstance(ex, HTTPException)
            else ex.status_code
            if isinstance(ex, NeutronClientException)
            else 500
        )
        content_type = "application/vnd.docker.plugins.v1+json; charset=utf-8"
        response.headers["Content-Type"] = content_type
        return response

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    return app
def make_json_app(import_name, **kwargs):
    """
    Creates a JSON-oriented Flask app.

    All error responses that you don't specifically
    manage yourself will have application/json content
    type, and will contain JSON like this (just an example):

    { "message": "405: Method Not Allowed" }
    """

    def make_json_error(ex):
        pprint.pprint(ex)
        pprint.pprint(ex.code)
        # response = jsonify(message=str(ex))
        response = json.dumps(ex)
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        return response

    app = Flask(import_name, **kwargs)
    # app.debug = True
    app.secret_key = id_generator(24)

    for code in default_exceptions.keys():
        app.error_handler_spec[None][code] = make_json_error

    return app
def make_json_app(import_name, **kwargs):
    """
    Creates a JSON-oriented Flask app.

    All error responses that you don't specifically
    manage yourself will have application/json content
    type, and will contain JSON like this (just an example):

    { "message": "405: Method Not Allowed" }

    http://flask.pocoo.org/snippets/83/
    """
    def make_json_error(ex):
        response = jsonify(message=str(ex))
        response.status_code = (ex.code
                                if isinstance(ex, HTTPException)
                                else 500)
        return response

    app = Flask(import_name, **kwargs)

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    return app
Beispiel #7
0
def json_app(import_name, **kwargs):
    """
    Creates a JSON-oriented Flask app.

    All error responses that you don't specifically
    manage yourself will have application/json content
    type, and will contain JSON like this (just an example):

    {
        "message": "405: Method Not Allowed",
        "statuscode": 405
    }
    """

    def make_json_error(ex):
        if not isinstance(ex, ApplicationException):
            appexception = ApplicationException(message=str(ex), statuscode=ex.code)
        else:
            appexception = ex
        json_str = jsonpickle.encode(appexception, unpicklable=False)
        resp = make_response(json_str)
        resp.status_code = appexception.statuscode
        resp.mimetype = "application/json"
        return resp

        response = jsonpickle.encode(ex)
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        return response

    app = Flask(import_name, **kwargs)

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    return app
def json_flask_app(import_name, **kwargs):
    def make_json_error(ex):
        response = jsonify(message=str(ex), code=ex.code if isinstance(ex, HTTPException) else 500)
        return response

    app = Flask(import_name, **kwargs)
    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error
    return app
Beispiel #9
0
def create_app(option):
    app = Flask(__name__)
    config = config_factory.get(option)
    app.config.from_object(config)
    from common import create_jinja_filters, random_pwd

    create_jinja_filters(app)
    from webapp.api import api
    from webapp.client import client
    from webapp.media import media

    app.register_blueprint(client)
    app.register_blueprint(api, url_prefix=Constants.API_V1_URL_PREFIX)
    app.register_blueprint(media, url_prefix=Constants.MEDIA_URL_PREFIX)

    csrf.init_app(app)
    compress.init_app(app)
    gravatar.init_app(app)
    db.init_app(app)
    migrate.init_app(app, db)
    admin.init_app(app)
    mail.init_app(app)
    from models import User, Role
    from webapp.forms import ExtendedRegisterForm

    user_datastore = SQLAlchemyUserDatastore(db, User, Role)
    security.init_app(app, user_datastore, register_form=ExtendedRegisterForm)
    with app.app_context():
        api_manager.init_app(app, flask_sqlalchemy_db=db)

        @app.before_request
        def before_request():
            g.constants = Constants
            g.config = app.config
            g.mode = app.config.get("MODE")

        @app.after_request
        def redirect_if_next(response_class):
            payload = request.args if request.method == "GET" else request.form
            if "api_next" in payload:
                if not response_class.status_code == 200:
                    flash(response_class.data)
                    return redirect(request.referrer)
                return redirect(payload.get("api_next"))
            return response_class

    patch_request_class(app, Constants.MAX_FILE_SIZE)

    from webapp.common import make_json_error

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    configure_uploads(app, (user_images,))

    return app
Beispiel #10
0
def create_app(settings="realize.settings"):
    app = Flask(__name__, template_folder="templates")
    app.config.from_object(settings)
    db.app = app
    db.init_app(app)

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    return app
Beispiel #11
0
def create_json_app(config):
    app = Flask(__name__)
    CORS(app)
    app.config.from_object(config)
    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error
    db.init_app(app)
    with app.app_context():
        db.create_all()
    app.app_context().push()
    return app
Beispiel #12
0
def medea_app(import_name, **kwargs):
    def make_json_error(ex):
        response = jsonify(message=str(ex))
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        traceback.print_exc()
        return response

    app = Flask(import_name, **kwargs)
    for code in default_exceptions.keys():
        app.error_handler_spec[None][code] = make_json_error

    CORS(app)
    return app
Beispiel #13
0
def make_json_app(*args, **kwargs):
    """JSONify all error responses"""

    def make_json_error(ex):
        response = jsonify(error=str(ex))
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        return response

    app = Flask(*args, **kwargs)
    for code in default_exceptions:
        app.error_handler_spec[None][code] = make_json_error

    return app
Beispiel #14
0
def app(import_name, **kwargs):
    """
    Creates a JSON-oriented Flask app.

    All error responses that you don't specifically
    manage yourself will have application/json content
    type, and will contain JSON like this (just an example):

    { "message": "405: Method Not Allowed" }
    """
    app = Flask(import_name, **kwargs)

    for code in default_exceptions.keys():
        app.error_handler_spec[None][code] = error

    return app
def make_json_app():
    """
    Creates a JSON-oriented Flask app.
    All error responses will contain JSON like this (just an example):
    { "message": "405: Method Not Allowed" }
    """

    def make_json_error(ex):
        response = jsonify(message=str(ex))
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        return response

    app = Flask(__name__)

    for code in default_exceptions.keys():
        app.error_handler_spec[None][code] = make_json_error

    return app
Beispiel #16
0
def JSONApp(import_name, **kwargs):
    def make_json_error(ex):
        response = jsonify(message=str(ex))
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        h = response.headers

        h["Access-Control-Allow-Origin"] = "*"
        h["Access-Control-Max-Age"] = str(21600)
        h["Access-Control-Allow-Headers"] = "CONTENT-TYPE"

        return response

    app = Flask(import_name, **kwargs)

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    return app
Beispiel #17
0
def create_app(config_name="development"):
    """Flask factory function"""

    # Configure from config.py
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    db.init_app(app)

    # Configure Flask-Admin
    admin = Admin(name="demo", template_mode="bootstrap3")
    from .admin_views import DbView

    admin.add_view(DbView(Group, db.session))
    admin.add_view(DbView(User, db.session))
    admin.init_app(app)

    # Blueprints
    from .api import groups_bp

    app.register_blueprint(groups_bp, url_prefix="/api/groups")

    from .api import users_bp

    app.register_blueprint(users_bp, url_prefix="/api/users")
    #

    @app.before_first_request
    def create_tables():
        db.create_all()

    # Ensure all errors thrown are json
    # http://flask.pocoo.org/snippets/83/
    def make_json_error(ex):
        response = jsonify(message=str(ex))
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        return response

    for code in default_exceptions.keys():
        app.error_handler_spec[None][code] = make_json_error

    return app
Beispiel #18
0
def create_app():
    app = Flask(__name__)
    app.config.from_object(bark.config)

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    # Component imports. Must be here to fix cyclical problems
    from auth import bp_auth

    app.register_blueprint(bp_auth)

    from swipes import bp_swipes

    app.register_blueprint(bp_swipes, url_prefix="/swipes")

    from events import bp_events

    app.register_blueprint(bp_events, url_prefix="/events")

    from devices import bp_devices

    app.register_blueprint(bp_devices, url_prefix="/devices")

    from persons import bp_persons

    app.register_blueprint(bp_persons, url_prefix="/persons")

    from groups import bp_groups

    app.register_blueprint(bp_groups, url_prefix="/groups")

    @app.route("/")
    def hello():
        return "Hello World"

    db.init_app(app)

    return app
def make_json_app(import_name, **kwargs):
    """
    Creates a JSON-oriented Flask app.

    All error responses that you don't specifically
    manage yourself will have application/json content
    type, and will contain JSON like this (just an example):

    { "Err": "405: Method Not Allowed" }
    """

    def make_json_error(ex):
        response = jsonify({"Err": str(ex)})
        response.status_code = ex.code if isinstance(ex, HTTPException) else 500
        return response

    wrapped_app = Flask(import_name, **kwargs)

    for code in default_exceptions.iterkeys():
        wrapped_app.error_handler_spec[None][code] = make_json_error

    return wrapped_app
Beispiel #20
0
def make_app():
    """
    Entry point for Savanna REST API server
    """
    app = Flask("savanna.api")

    app.config["SQLALCHEMY_DATABASE_URI"] = CONF.sqlalchemy.database_uri
    app.config["SQLALCHEMY_ECHO"] = CONF.sqlalchemy.echo

    app.register_blueprint(api_v02.rest, url_prefix="/v0.2")

    setup_storage(app)
    setup_defaults()
    setup_scheduler(app)

    def make_json_error(ex):
        status_code = ex.code if isinstance(ex, HTTPException) else 500
        description = ex.description if isinstance(ex, HTTPException) else str(ex)
        return render({"error": status_code, "error_message": description}, status=status_code)

    for code in default_exceptions.iterkeys():
        app.error_handler_spec[None][code] = make_json_error

    app.wsgi_app = auth_valid(app.config)(app.wsgi_app)

    app.wsgi_app = auth_token(
        app.config,
        auth_host=CONF.os_auth_host,
        auth_port=CONF.os_auth_port,
        auth_protocol=CONF.os_auth_protocol,
        admin_user=CONF.os_admin_username,
        admin_password=CONF.os_admin_password,
        admin_tenant=CONF.os_admin_tenant_name,
    )(app.wsgi_app)

    return app
Beispiel #21
0
    def boot(self, lifecycle, model=Reactive, tools=None, local=False):

        #
        # - quick check to make sure we get the right implementations
        #
        assert issubclass(model, Model), "model must derive from ochopod.api.Model"
        assert issubclass(lifecycle, LifeCycle), "lifecycle must derive from ochopod.api.LifeCycle"

        #
        # - instantiate our flask endpoint
        # - default to a json handler for all HTTP errors (including an unexpected 500)
        #
        def _handler(error):
            http = error.code if isinstance(error, HTTPException) else 500
            return "{}", http, {"Content-Type": "application/json; charset=utf-8"}

        web = Flask(__name__)
        for code in default_exceptions.iterkeys():
            web.error_handler_spec[None][code] = _handler

        #
        # - default presets in case we run outside of marathon (local vm testing)
        # - any environment variable prefixed with "ochopod." is of interest for us (e.g this is what the user puts
        #   in the marathon application configuration for instance)
        # - the other settings come from marathon (namely the port bindings & application/task identifiers)
        # - the MESOS_TASK_ID is important to keep around to enable task deletion via the marathon REST API
        #
        env = {
            "ochopod_application": "",
            "ochopod_cluster": "default",
            "ochopod_debug": "true",
            "ochopod_local": "false",
            "ochopod_namespace": "marathon",
            "ochopod_port": "8080",
            "ochopod_start": "true",
            "ochopod_task": "",
            "ochopod_zk": "",
            "PORT_8080": "8080",
        }

        env.update(os.environ)
        ochopod.enable_cli_log(debug=env["ochopod_debug"] == "true")
        try:

            #
            # - grab our environment variables (which are set by the marathon executor)
            # - extract the mesos PORT_* bindings and construct a small remapping dict
            #
            ports = {}
            logger.debug("environment ->\n%s" % "\n".join(["\t%s -> %s" % (k, v) for k, v in env.items()]))
            for key, val in env.items():
                if key.startswith("PORT_"):
                    ports[key[5:]] = int(val)

            #
            # - keep any "ochopod_" environment variable & trim its prefix
            # - default all our settings, especially the mandatory ones
            # - the ip and zookeeper are defaulted to localhost to enable easy testing
            #
            hints = {k[8:]: v for k, v in env.items() if k.startswith("ochopod_")}
            if local or hints["local"] == "true":

                #
                # - we are running in local mode (e.g on a dev workstation)
                # - default everything to localhost
                #
                logger.info("running in local mode (make sure you run a standalone zookeeper)")
                hints.update(
                    {
                        "fwk": "marathon (debug)",
                        "ip": "127.0.0.1",
                        "node": "local",
                        "ports": ports,
                        "public": "127.0.0.1",
                        "zk": "127.0.0.1:2181",
                    }
                )
            else:

                #
                # - extend our hints
                # - add the application + task
                #
                hints.update(
                    {
                        "application": env["MARATHON_APP_ID"][1:],
                        "fwk": "marathon",
                        "ip": "",
                        "node": "",
                        "ports": ports,
                        "public": "",
                        "task": env["MESOS_TASK_ID"],
                        "zk": "",
                    }
                )

                #
                # - use whatever subclass is implementing us to infer 'ip', 'node' and 'public'
                #
                hints.update(self.get_node_details())

                #
                # - lookup for the zookeeper connection string from environment variable or on disk
                # - we have to look into different places depending on how mesos was installed
                #
                def _1():

                    #
                    # - most recent DCOS release
                    # - $MESOS_MASTER is located in /opt/mesosphere/etc/mesos-slave-common
                    # - the snippet in there is prefixed by MESOS_ZK=zk://<ip:port>/mesos
                    #
                    logger.debug("checking /opt/mesosphere/etc/mesos-slave-common...")
                    _, lines = shell("grep MESOS_MASTER /opt/mesosphere/etc/mesos-slave-common")
                    return lines[0][18:].split("/")[0]

                def _2():

                    #
                    # - same as above except for slightly older DCOS releases
                    # - $MESOS_MASTER is located in /opt/mesosphere/etc/mesos-slave
                    #
                    logger.debug("checking /opt/mesosphere/etc/mesos-slave...")
                    _, lines = shell("grep MESOS_MASTER /opt/mesosphere/etc/mesos-slave")
                    return lines[0][18:].split("/")[0]

                def _3():

                    #
                    # - a regular package install will write the slave settings under /etc/mesos/zk (the snippet in
                    #   there looks like zk://10.0.0.56:2181/mesos)
                    #
                    logger.debug("checking /etc/mesos/zk...")
                    _, lines = shell("cat /etc/mesos/zk")
                    return lines[0][5:].split("/")[0]

                def _4():

                    #
                    # - look for ZK from environment variables
                    # - user can pass down ZK using $ochopod_zk
                    #
                    logger.debug("checking $ochopod_zk environment variable...")
                    if env["ochopod_zk"]:
                        logger.debug("found $ochopod_zk environment variable...")
                        return env["ochopod_zk"][5:].split("/")[0]

                #
                # - depending on how the slave has been installed we might have to look in various places
                #   to find out what our zookeeper connection string is
                # - warning, a URL like format such as zk://<ip:port>,..,<ip:port>/mesos is used
                # - just keep the ip & port part and discard the rest
                #
                for method in [_1, _2, _3, _4]:
                    try:
                        hints["zk"] = method()
                        break

                    except Exception:
                        pass

            #
            # - the cluster must be fully qualified with a namespace (which is defaulted anyway)
            #
            assert hints["zk"], "unable to determine where zookeeper is located (unsupported/bogus mesos setup ?)"
            assert hints["cluster"] and hints["namespace"], "no cluster and/or namespace defined (user error ?)"

            #
            # - load the tools
            #
            if tools:
                tools = {tool.tag: tool for tool in [clz() for clz in tools if issubclass(clz, Tool)] if tool.tag}
                logger.info("supporting tools %s" % ", ".join(tools.keys()))

            #
            # - start the life-cycle actor which will pass our hints (as a json object) to its underlying sub-process
            # - start our coordinator which will connect to zookeeper and attempt to lead the cluster
            # - upon grabbing the lock the model actor will start and implement the configuration process
            # - the hints are a convenient bag for any data that may change at runtime and needs to be returned (via
            #   the HTTP POST /info request)
            # - what's being registered in zookeeper is immutable though and decorated with additional details by
            #   the coordinator (especially the pod index which is derived from zookeeper)
            #
            latch = ThreadingFuture()
            logger.info("starting %s.%s (marathon) @ %s" % (hints["namespace"], hints["cluster"], hints["node"]))
            breadcrumbs = deepcopy(hints)
            hints["metrics"] = {}
            hints["dependencies"] = model.depends_on
            env.update({"ochopod": json.dumps(hints)})
            executor = lifecycle.start(env, latch, hints)
            coordinator = Coordinator.start(
                hints["zk"].split(","),
                hints["namespace"],
                hints["cluster"],
                int(hints["port"]),
                breadcrumbs,
                model,
                hints,
            )

            #
            # - external hook forcing a coordinator reset
            # - this will force a re-connection to zookeeper and pod registration
            # - please note this will not impact the pod lifecycle (e.g the underlying sub-process will be
            #   left running)
            #
            @web.route("/reset", methods=["POST"])
            def _reset():

                logger.debug("http in -> /reset")
                coordinator.tell({"request": "reset"})
                return "{}", 200, {"Content-Type": "application/json; charset=utf-8"}

            #
            # - external hook exposing information about our pod
            # - this is a subset of what's registered in zookeeper at boot-time
            # - the data is dynamic and updated from time to time by the model and executor actors
            # - from @pferro -> the pod's dependencies defined in the model are now added as well
            #
            @web.route("/info", methods=["POST"])
            def _info():

                logger.debug("http in -> /info")
                keys = [
                    "application",
                    "dependencies",
                    "ip",
                    "metrics",
                    "node",
                    "port",
                    "ports",
                    "process",
                    "public",
                    "state",
                    "status",
                    "task",
                ]

                subset = dict(filter(lambda i: i[0] in keys, hints.iteritems()))
                return json.dumps(subset), 200, {"Content-Type": "application/json; charset=utf-8"}

            #
            # - external hook exposing our circular log
            # - reverse and dump ochopod.log as a json array
            #
            @web.route("/log", methods=["POST"])
            def _log():

                logger.debug("http in -> /log")
                with open(ochopod.LOG, "r+") as log:
                    lines = [line for line in log]
                    return json.dumps(lines), 200, {"Content-Type": "application/json; charset=utf-8"}

            #
            # - RPC call to run a custom tool within the pod
            #
            @web.route("/exec", methods=["POST"])
            def _exec():

                logger.debug("http in -> /exec")

                #
                # - make sure the command (first token in the X-Shell header) maps to a tool
                # - if no match abort on a 404
                #
                line = request.headers["X-Shell"]
                tokens = line.split(" ")
                cmd = tokens[0]
                if not tools or cmd not in tools:
                    return "{}", 404, {"Content-Type": "application/json; charset=utf-8"}

                code = 1
                tool = tools[cmd]

                #
                # - make sure the parser does not sys.exit()
                #
                class _Parser(ArgumentParser):
                    def exit(self, status=0, message=None):
                        raise ValueError(message)

                #
                # - prep a temporary directory
                # - invoke define_cmdline_parsing()
                # - switch off parsing if NotImplementedError is raised
                #
                use_parser = 1
                parser = _Parser(prog=tool.tag)
                try:
                    tool.define_cmdline_parsing(parser)

                except NotImplementedError:
                    use_parser = 0

                tmp = tempfile.mkdtemp()
                try:

                    #
                    # - parse the command line
                    # - upload any attachment
                    #
                    args = parser.parse_args(tokens[1:]) if use_parser else " ".join(tokens[1:])
                    for tag, upload in request.files.items():
                        where = path.join(tmp, tag)
                        logger.debug("uploading %s @ %s" % (tag, tmp))
                        upload.save(where)

                    #
                    # - run the tool method
                    # - pass the temporary directory as well
                    #
                    logger.info('invoking "%s"' % line)
                    code, lines = tool.body(args, tmp)

                except ValueError as failure:

                    lines = [parser.format_help() if failure.message is None else failure.message]

                except Exception as failure:

                    lines = ["unexpected failure -> %s" % failure]

                finally:

                    #
                    # - make sure to cleanup our temporary directory
                    #
                    shutil.rmtree(tmp)

                out = {"code": code, "stdout": lines}

                return json.dumps(out), 200, {"Content-Type": "application/json; charset=utf-8"}

            #
            # - web-hook used to receive requests from the leader or the CLI tools
            # - those requests are passed down to the executor actor
            # - any non HTTP 200 response is a failure
            # - failure to acknowledge within the specified timeout will result in a HTTP 408 (REQUEST TIMEOUT)
            # - attempting to send a control request to a dead pod will result in a HTTP 410 (GONE)
            #
            @web.route("/control/<task>", methods=["POST"])
            @web.route("/control/<task>/<timeout>", methods=["POST"])
            def _control(task, timeout="60"):

                logger.debug("http in -> /control/%s" % task)
                if task not in ["check", "on", "off", "ok", "kill", "signal"]:

                    #
                    # - fail on a HTTP 400 if the request is not supported
                    #
                    return "{}", 400, {"Content-Type": "application/json; charset=utf-8"}

                try:

                    ts = time.time()
                    latch = ThreadingFuture()
                    executor.tell({"request": task, "latch": latch, "data": request.data})
                    js, code = latch.get(timeout=int(timeout))
                    ms = time.time() - ts
                    logger.debug("http out -> HTTP %s (%d ms)" % (code, ms))
                    return json.dumps(js), code, {"Content-Type": "application/json; charset=utf-8"}

                except Timeout:

                    #
                    # - we failed to match the specified timeout
                    # - gracefully fail on a HTTP 408
                    #
                    return "{}", 408, {"Content-Type": "application/json; charset=utf-8"}

                except ActorDeadError:

                    #
                    # - the executor has been shutdown (probably after a /control/kill)
                    # - gracefully fail on a HTTP 410
                    #
                    return "{}", 410, {"Content-Type": "application/json; charset=utf-8"}

            #
            # - internal hook required to shutdown the web-server
            # - it's not possible to do it outside of a request handler
            # - make sure this calls only comes from localhost (todo)
            #
            @web.route("/terminate", methods=["POST"])
            def _terminate():

                request.environ.get("werkzeug.server.shutdown")()
                return "{}", 200, {"Content-Type": "application/json; charset=utf-8"}

            #
            # - run werkzeug from a separate thread to avoid blocking the main one
            # - we'll have to shut it down using a dedicated HTTP POST
            #
            class _Runner(threading.Thread):
                def run(self):
                    web.run(host="0.0.0.0", port=int(hints["port"]), threaded=True)

            try:

                #
                # - block on the lifecycle actor until it goes down (usually after a /control/kill request)
                #
                _Runner().start()
                spin_lock(latch)
                logger.debug("pod is dead, idling")
                while 1:

                    #
                    # - simply idle forever (since the framework would restart any container that terminates)
                    # - /log and /hints HTTP requests will succeed (and show the pod as being killed)
                    # - any control request will now fail
                    #
                    time.sleep(60.0)

            finally:

                #
                # - when we exit the block first shutdown our executor (which may probably be already down)
                # - then shutdown the coordinator to un-register from zookeeper
                # - finally ask werkzeug to shutdown via a REST call
                #
                shutdown(executor)
                shutdown(coordinator)
                post("http://127.0.0.1:%s/terminate" % env["ochopod_port"])

        except KeyboardInterrupt:

            logger.fatal("CTRL-C pressed")

        except Exception as failure:

            logger.fatal("unexpected condition -> %s" % diagnostic(failure))
Beispiel #22
0
# Note that we need to set this *before* registering the blueprint.
app.url_map.strict_slashes = False


def default_json_error(ex):
    """ Exception -> flask JSON responder """
    logger = get_logger()
    logger.error("Uncaught error thrown by Flask/Werkzeug", exc_info=ex)
    response = jsonify(message=str(ex), type="api_error")
    response.status_code = ex.code if isinstance(ex, HTTPException) else 500
    return response


# Patch all error handlers in werkzeug
for code in default_exceptions.iterkeys():
    app.error_handler_spec[None][code] = default_json_error


@app.before_request
def auth():
    """ Check for account ID on all non-root URLS """
    if request.path in ("/accounts", "/accounts/", "/", "/n", "/n/") or request.path.startswith("/w/"):
        return

    if request.path.startswith("/n/"):
        ns_parts = filter(None, request.path.split("/"))
        namespace_public_id = ns_parts[1]
        valid_public_id(namespace_public_id)

        with session_scope() as db_session:
            try:
Beispiel #23
0
app.config["SECRET_KEY"] = os.environ.get("WEBAPP_SESSION_SECRET_KEY", "oftg09jW2FtbXfcud9OS")


# Make this app a JSON app.
# Inspired from cf. http://flask.pocoo.org/snippets/83/
def make_json_error(ex):
    log.error(ex)
    log.error(traceback.format_exc())
    message = ex.description if isinstance(ex, HTTPException) else str(ex)
    message = message.replace("<p>", "").replace("</p>", "") if message else ""
    code = ex.code if isinstance(ex, HTTPException) else 500
    response = jsonify(message=message, status_code=code)
    response.status_code = code

    if code in [500]:
        notify(ex, code)

    return response


for code in default_exceptions.iterkeys():
    app.error_handler_spec[None][code] = make_json_error


def notify(exception, code=None):
    if not code:
        code = exception.code if isinstance(exception, HTTPException) else 500
    cloudly_notify("Exception: {}".format(code), "{}\n\n{}".format(exception, traceback.format_exc(exception)))


import birdlistn.views  # noqa
Beispiel #24
0
def create_app(name=__name__, enable_security=True, debug=False, **kwargs):
    """ Create the server istance for Flask application """

    #################################################
    # Flask app instance
    #################################################
    from confs import config

    template_dir = os.path.join(config.BASE_DIR, __package__)
    microservice = Flask(
        name,
        # Quick note:
        # i use the template folder from the current dir
        # just for Administration.
        # I expect to have 'admin' dir here to change
        # the default look of flask-admin
        template_folder=template_dir,
        **kwargs
    )

    ##############################
    # ERROR HANDLING

    # Handling exceptions with json
    for code in default_exceptions.keys():
        microservice.error_handler_spec[None][code] = make_json_error
    # Custom error handling: save to log
    got_request_exception.connect(log_exception, microservice)

    # Custom exceptions
    @microservice.errorhandler(RESTError)
    def handle_invalid_usage(error):
        # print("ERROR", error)
        response = jsonify(error.to_dict())
        response.status_code = error.status_code
        return response

    ##############################
    # Flask configuration from config file
    microservice.config.from_object(config)
    microservice.config["DEBUG"] = debug
    # // TO FIX:
    # development/production split?
    logger.info("FLASKING! Created application")

    #################################################
    # Other components
    #################################################

    ##############################
    # Cors
    from .cors import cors

    cors.init_app(microservice)
    logger.info("FLASKING! Injected CORS")

    ##############################
    # DB
    from .models import db

    db.init_app(microservice)
    logger.info("FLASKING! Injected sqlalchemy. (please use it)")

    ##############################
    # Flask security
    if enable_security:

        ############################################
        # Should open an issue on flask-admin!
        """
        # BUG!
         The following is how it should be, but we get infinite loop:
          File "/usr/local/lib/python3.4/dist-packages/flask_security/core.py"
          , line 450, in __getattr__
            return getattr(self._state, name, None)
        RuntimeError: maximum recursion depth exceeded
        """
        # from .security import security
        # security.init_app(microservice)
        # WORKAROUND
        from .security import udstore
        from flask_security import Security

        security = Security(microservice, udstore)
        # WORKAROUND
        ############################################

        logger.info("FLASKING! Injected security")

    ##############################
    # Restful plugin
    from .rest import epo, create_endpoints

    logger.info("FLASKING! Injected rest endpoints")
    epo = create_endpoints(epo, security, debug)

    # Restful init of the app
    epo.rest_api.init_app(microservice)

    ##############################
    # Prepare database and tables
    with microservice.app_context():
        try:
            if config.REMOVE_DATA_AT_INIT_TIME:
                db.drop_all()
            db.create_all()
            logger.info("DB: Connected and ready")
        except Exception as e:
            logger.critical("Database connection failure: %s" % str(e))
            exit(1)

        if enable_security:
            from .security import db_auth

            # Prepare user/roles
            db_auth()

    ##############################
    # Flask admin
    if enable_security:
        from .admin import admin, UserView, RoleView
        from .models import User, Role
        from flask_admin import helpers as admin_helpers

        admin.init_app(microservice)
        admin.add_view(UserView(User, db.session))
        admin.add_view(RoleView(Role, db.session))

        # Context processor for merging flask-admin's template context
        # into the flask-security views
        @security.context_processor
        def security_context_processor():
            return dict(admin_base_template=admin.base_template, admin_view=admin.index_view, h=admin_helpers)

        logger.info("FLASKING! Injected admin endpoints")

    ##############################
    # RETHINKDB
    # // TO FIX, not for every endpoint
    if RDB_AVAILABLE:

        @microservice.before_request
        def before_request():
            logger.debug("Hello request RDB")
            # === Connection ===
            # The RethinkDB server doesn’t use a thread-per-connnection approach,
            # so opening connections per request will not slow down your database.

            # Database should be already connected in "before_first_request"
            # But the post method fails to find the object!
            from .resources.services.rethink import try_to_connect

            try_to_connect()

    ##############################
    # Logging responses
    @microservice.after_request
    def log_response(response):
        logger.info("{} {} {}\n{}".format(request.method, request.url, request.data, response))
        return response

    # OR
    # http://www.wiredmonk.me/error-handling-and-logging-in-flask-restful.html
    # WRITE TO FILE
    # file_handler = logging.FileHandler('app.log')
    # app.logger.addHandler(file_handler)
    # app.logger.setLevel(logging.INFO)

    ##############################
    # App is ready
    return microservice
        code = error.code
        error_type = error.name
    else:
        code = 500
        error_type = error.__class__.__name__

    rv = {"status": code, "error": error_type}

    response = jsonify(rv)
    response.status_code = code

    return response


for code in default_exceptions.keys():
    app.error_handler_spec[None][code] = handle_error

from hackathon.api import blueprints

for bp in blueprints:
    app.register_blueprint(bp)

db.create_all()


def send_mandrill_email(recipient, template_name, global_merge_vars):
    """Send email using Mandrill template"""

    mandrill_client = mandrill.Mandrill(app.config["MANDRILL_KEY"])
    template_content = []
    message = {
Beispiel #26
0
                "Access-Control-Allow-Headers"
            ] = "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)

    return decorator


app = Flask(__name__)

app.debug = True

for code in default_exceptions.iterkeys():
    app.error_handler_spec[None][code] = error_json_handler

"""
END IGNORE
"""

################################################################################

# Setup PyMongo
client = pymongo.MongoClient("0.0.0.0", 27017)

# Variable que contiene la base de datos
db = client.shop

# Variables que contienen cada una de las colecciones
catalog_col = db.catalog
Beispiel #27
0
    system = expanduser("/etc/pugstar/config.py")

    paths = filter(lambda x: x and os.access(x, os.R_OK), (home, system))
    return next(paths)


app = Flask(__name__)
app.config.from_pyfile(find_config(), silent=True)

file_handler = FileHandler(app.config.get("LOG_FILE", "/var/log/pugstar/app.log"))
file_handler.setLevel(getattr(logging, app.config.get("LOG_LEVEL", "WARNING").upper()))

app.logger.addHandler(file_handler)

for code in default_exceptions.keys():
    app.error_handler_spec[None][code] = podhub.meh.util.make_json_error

db = SQLAlchemy(app)
oid = OpenID(app, app.config.get("OPENID_STORE"))
cache = MemcachedCache(
    servers=app.config.get("MEMCACHED_HOSTS", ["127.0.0.1"]),
    default_timeout=app.config.get("MEMCACHED_DEFAULT_TIMEOUT", 300),
)

migrate = Migrate(app, db)

steam.api.key.set(app.config.get("STEAM_API_KEY"))

manager = Manager(app)
manager.add_command("db", MigrateCommand)