示例#1
0
    def project_initialization(self, instances):
        """ Custom initialization of your project

        Please define your class Initializer in
        vanilla/project/initialization.py
        """

        try:
            meta = Meta()
            module_path = "%s.%s.%s" % \
                (CUSTOM_PACKAGE, 'initialization', 'initialization')
            module = meta.get_module_from_string(
                module_path,
                debug_on_fail=False,
            )
            Initializer = meta.get_class_from_string('Initializer',
                                                     module,
                                                     skip_error=True)
            if Initializer is None:
                log.debug("No custom init available")
            else:
                try:
                    Initializer(instances)
                except BaseException as e:
                    log.error("Errors during custom initialization: %s", e)
                else:
                    log.info("Vanilla project has been initialized")

        except BaseException:
            log.debug("No custom init available")
    def get(self, test_num, task_id=None):
        celery = self.get_service_instance('celery')

        meta = Meta()
        methods = meta.get_methods_inside_instance(self)
        method_name = "test_%s" % test_num
        if method_name not in methods:
            raise RestApiException("Test %d not found" % test_num)
        method = methods[method_name]
        out = method(celery, task_id)
        return self.force_response(out)
示例#3
0
    def __init__(self, config_file_name='services'):

        self.authentication_service = None
        self.authentication_name = 'authentication'
        self.task_service_name = 'celery'
        self.modules = []
        self.services_configuration = []
        self.services = {}
        self.services_classes = {}
        self.extensions_instances = {}
        self.available_services = {}
        self.meta = Meta()
        self.check_configuration(config_file_name)
        self.load_classes()
示例#4
0
def test():
    meta = Meta()
    cls_name = "Meta"

    import utilities
    modules = meta.get_submodules_from_package(utilities)
    assert "meta" in modules

    sub_modules = meta.import_submodules_from_package("utilities")
    assert sub_modules is not None
    assert isinstance(sub_modules, list)
    assert len(sub_modules) > 0

    module = meta.get_module_from_string("utilities.meta")
    assert module is not None
    assert hasattr(module, cls_name)

    classes = meta.get_classes_from_module(module)
    assert classes is not None
    assert isinstance(classes, dict)
    assert cls_name in classes
    assert classes[cls_name].__name__ == cls_name

    new_classes = meta.get_new_classes_from_module(module)
    assert new_classes is not None
    assert isinstance(new_classes, dict)
    assert cls_name in new_classes
    assert new_classes[cls_name].__name__ == cls_name

    meta_class = meta.get_class_from_string(cls_name, module)
    assert meta_class is not None
    assert meta_class.__name__ == cls_name

    methods = meta.get_methods_inside_instance(meta, private_methods=True)
    assert methods is not None
    assert isinstance(methods, dict)
    # it is a static method
    assert "get_methods_inside_instance" not in methods
    assert "get_authentication_module" in methods

    metacls = meta.metaclassing(Meta, "Test")
    assert metacls is not None
    assert metacls.__name__ == "Test"

    self_ref = meta.get_self_reference_from_args(meta, "test", 1)
    assert self_ref == meta
示例#5
0
    def custom_connection(self, **kwargs):

        if len(kwargs) > 0:
            print("TODO: use args for connection?", kwargs)

        uri = 'postgresql://%s:%s@%s:%s/%s' % (
            self.variables.get('user'), self.variables.get('password'),
            self.variables.get('host'), self.variables.get('port'),
            self.variables.get('db'))

        log.very_verbose("URI IS %s" % re_obscure_pattern(uri))

        # TODO: in case we need different connection binds
        # (multiple connections with sql) then:
        # SQLALCHEMY_BINDS = {
        #     'users':        'mysqldb://localhost/users',
        #     'appmeta':      'sqlite:////path/to/appmeta.db'
        # }

        self.app.config['SQLALCHEMY_POOL_TIMEOUT'] = 3
        self.app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
        self.app.config['SQLALCHEMY_DATABASE_URI'] = uri

        pool_size = self.variables.get('poolsize')
        if pool_size is not None:
            # sqlalchemy docs: http://j.mp/2xT0GOc
            # defaults: overflow=10, pool_size=5
            self.app.config['SQLALCHEMY_MAX_OVERFLOW'] = 0
            self.app.config['SQLALCHEMY_POOL_SIZE'] = int(pool_size)

        obj_name = 'db'
        m = Meta()
        # search the original sqlalchemy object into models
        db = m.obj_from_models(obj_name, self.name, CUSTOM_PACKAGE)
        if db is None:
            log.warning("No sqlalchemy db imported in custom package")
            db = m.obj_from_models(obj_name, self.name, BACKEND_PACKAGE)
        if db is None:
            log.critical_exit("Could not get %s within %s models" %
                              (obj_name, self.name))

        return db
示例#6
0
    def custom_post_handle_user_input(self, user_node, input_data):
        meta = Meta()
        module_path = "%s.%s.%s" % \
            (CUSTOM_PACKAGE, 'initialization', 'initialization')
        module = meta.get_module_from_string(
            module_path,
            debug_on_fail=False,
        )

        Customizer = meta.get_class_from_string('Customizer',
                                                module,
                                                skip_error=True)
        if Customizer is None:
            log.debug("No user properties customizer available")
        else:
            try:
                Customizer().custom_post_handle_user_input(
                    self, user_node, input_data)
            except BaseException as e:
                log.error("Unable to customize user properties: %s", e)
示例#7
0
    def __init__(self, testing=False, production=False, init=False):

        # Input
        self._testing = testing
        self._production = production
        self._initiliazing = init

        # Some initialization
        self._endpoints = []
        self._definitions = {}
        self._configurations = {}
        self._query_params = {}
        self._schemas_map = {}
        self._meta = Meta()

        # Do things
        self.read_configuration()

        if not self._initiliazing:
            self.do_schema()
            self.find_endpoints()
            self.do_swagger()
示例#8
0
    def custom_user_properties(self, userdata):
        meta = Meta()
        module_path = "%s.%s.%s" % \
            (CUSTOM_PACKAGE, 'initialization', 'initialization')
        module = meta.get_module_from_string(
            module_path,
            debug_on_fail=False,
        )

        Customizer = meta.get_class_from_string('Customizer',
                                                module,
                                                skip_error=True)
        if Customizer is None:
            log.debug("No user properties customizer available")
        else:
            try:
                userdata = Customizer().custom_user_properties(userdata)
            except BaseException as e:
                log.error("Unable to customize user properties: %s", e)

        if "email" in userdata:
            userdata["email"] = userdata["email"].lower()

        return userdata
示例#9
0
def test_failures():
    meta = Meta()

    try:
        meta.import_submodules_from_package("utilities_bla")
    except AttributeError:
        pass
    else:
        pytest.fail("This call should fail and raise and AttributeError")

    try:
        meta.import_submodules_from_package("utilities_bla",
                                            exit_if_not_found=True)
    except AttributeError:
        pass
    else:
        pytest.fail("This call should fail and raise and AttributeError")

    try:
        meta.import_submodules_from_package("utilities_bla",
                                            exit_if_not_found=True,
                                            exit_on_fail=True)
    except AttributeError:
        pass
    else:
        pytest.fail("This call should fail and raise and AttributeError")

    try:
        meta.import_submodules_from_package("utilities_bla", exit_on_fail=True)
    except AttributeError:
        pass
    else:
        pytest.fail("This call should fail and raise and AttributeError")

    module = meta.get_module_from_string("utilities.metabla")
    assert module is None

    try:
        module = meta.get_module_from_string("utilities.metabla",
                                             exit_if_not_found=True)
    except SystemExit:
        pass
    else:
        pytest.fail("This call should fail and exit")

    try:
        module = meta.get_module_from_string("utilities.metabla",
                                             exit_if_not_found=True,
                                             exit_on_fail=True)
    except SystemExit:
        pass
    else:
        pytest.fail("This call should fail and exit")

    try:
        module = meta.get_module_from_string("utilities.metabla",
                                             exit_if_not_found=True,
                                             exit_on_fail=True,
                                             debug_on_fail=True)
    except SystemExit:
        pass
    else:
        pytest.fail("This call should fail and exit")

    # FIXME: unable to test exit_on_fail... we need a moule with import errors?
    module = meta.get_module_from_string("utilities.metabla",
                                         exit_on_fail=True)
    assert module is None

    module = meta.get_module_from_string("utilities.metabla",
                                         debug_on_fail=True)
    assert module is None
示例#10
0
from utilities.logs import get_logger

log = get_logger(__name__)

################################################
# Reload Flask app code also for the worker
# This is necessary to have the app context available
app = create_app(worker_mode=True)

celery_app = app.extensions.get('celery').celery_app
celery_app.app = app


def get_service(service):
    return celery_app.app.extensions.get(service).get_instance()


celery_app.get_service = get_service

################################################
# Import tasks modules to make sure all tasks are available

meta = Meta()
# main_package = "commons.tasks."
# # Base tasks
# submodules = meta.import_submodules_from_package(main_package + "base")
# # Custom tasks
submodules = meta.import_submodules_from_package("%s.tasks" % CUSTOM_PACKAGE)

log.debug("Celery worker is ready %s", celery_app)
示例#11
0
class BaseExtension(metaclass=abc.ABCMeta):

    models = {}  # I get models on a cls level, instead of instances
    meta = Meta()

    def __init__(self, app=None, **kwargs):

        self.objs = {}
        self.set_name()
        self.args = kwargs

        self.app = app
        if app is not None:
            self.init_app(app)

    def set_name(self):
        """ a different name for each extended object """
        self.name = self.__class__.__name__.lower()
        log.very_verbose("Opening service instance of %s" % self.name)

    @classmethod
    def set_models(cls, base_models, custom_models):

        # Join models as described by issue #16
        cls.models = base_models
        for key, model in custom_models.items():

            # Verify if overriding
            if key in base_models.keys():
                original_model = base_models[key]
                # Override
                if issubclass(model, original_model):
                    log.very_verbose("Overriding model %s" % key)
                    cls.models[key] = model
                    continue

            # Otherwise just append
            cls.models[key] = model

        if len(cls.models) > 0:
            log.verbose("Loaded models")

    @classmethod
    def set_variables(cls, envvars):
        cls.variables = envvars

    def init_app(self, app):
        app.teardown_appcontext(self.teardown)

    def pre_object(self, ref, key):
        """ Make sure reference and key are strings """

        if ref is None:
            ref = self.__class__.__name__
        elif isinstance(ref, object):
            ref = ref.__class__.__name__
        elif not isinstance(ref, str):
            ref = str(ref)

        if not isinstance(key, str):
            key = str(key)

        return ref + key

    def set_object(self, obj, key='[]', ref=None):
        """ set object into internal array """

        h = self.pre_object(ref, key)
        self.objs[h] = obj
        return obj

    def get_object(self, key='[]', ref=None):
        """ recover object if any """

        h = self.pre_object(ref, key)
        obj = self.objs.get(h, None)
        return obj

    def connect(self, **kwargs):

        obj = None

        # BEFORE
        ok = self.pre_connection(**kwargs)

        if not ok:
            log.critical("Unable to make preconnection for %s", self.name)
            return obj

        # Try until it's connected
        if len(kwargs) > 0:
            obj = self.custom_connection(**kwargs)
        else:
            obj = self.retry()
            log.info("Connected! %s", self.name)

        # AFTER
        self.post_connection(obj, **kwargs)

        obj.connection_time = datetime.now()
        return obj

    def set_models_to_service(self, obj):

        if len(self.models) < 1 and self.__class__.__name__ == 'NeoModel':
            raise Exception()

        for name, model in self.models.items():
            # Save attribute inside class with the same name
            log.very_verbose("Injecting model '%s'" % name)
            setattr(obj, name, model)
            obj.models = self.models

        return obj

    def set_connection_exception(self):
        return None

    def retry(self, retry_interval=3, max_retries=-1):
        retry_count = 0

        # Get the exception which will signal a missing connection
        exceptions = self.set_connection_exception()
        if exceptions is None:
            exceptions = (BaseException, )

        while max_retries != 0 or retry_count < max_retries:

            retry_count += 1
            if retry_count > 1:
                log.verbose("testing again in %s secs", retry_interval)

            try:
                obj = self.custom_connection()
            except exceptions as e:
                log.error("Catched: %s(%s)", e.__class__.__name__, e)
                # NOTE: if you critical_exit uwsgi will not show this line
                log.critical("Service '%s' not available", self.name)
                log.exit()
                # raise e
            else:
                break

            # Increment sleeps time if doing a lot of retries
            if retry_count % 3 == 0:
                log.debug("Incrementing interval")
                retry_interval += retry_interval

        return obj

    def teardown(self, exception):
        ctx = stack.top
        if self.get_object(ref=ctx) is not None:
            self.close_connection(ctx)

    def get_instance(self, **kwargs):

        # Parameters
        global_instance = kwargs.pop('global_instance', False)
        isauth = kwargs.pop('authenticator', False)
        cache_expiration = kwargs.pop('cache_expiration', None)
        # pinit = kwargs('project_initialization', False)

        # Variables
        obj = None
        ctx = stack.top
        ref = self
        unique_hash = str(sorted(kwargs.items()))
        log.very_verbose("instance hash: %s" % unique_hash)

        # When not using the context, this is the first connection
        if ctx is None:
            # First connection, before any request
            obj = self.connect()
            if obj is None:
                return None
            # self.initialization(obj=obj)
            self.set_object(obj=obj, ref=ref)

            log.verbose("First connection for %s" % self.name)

        else:
            # isauth = 'Authenticator' == self.__class__.__name__

            if not isauth:
                if not global_instance:
                    ref = ctx

                obj = self.get_object(ref=ref, key=unique_hash)

            if obj is not None and cache_expiration is not None:
                now = datetime.now()
                exp = timedelta(seconds=cache_expiration)

                if now < obj.connection_time + exp:
                    log.very_verbose("Cache still fresh for %s" % (self))
                else:
                    log.warning("Cache expired for %s", (self))
                    obj = None

            if obj is None:
                obj = self.connect(**kwargs)
                if obj is None:
                    return None
                self.set_object(obj=obj, ref=ref, key=unique_hash)
            else:
                pass

            log.very_verbose("Instance %s(%s)" % (ref.__class__.__name__, obj))

        obj = self.set_models_to_service(obj)

        return obj

    ############################
    # OPTIONALLY
    # to be executed only at init time?

    def pre_connection(self, **kwargs):
        return True

    def post_connection(self, obj=None, **kwargs):
        return True

    def close_connection(self, ctx):
        """ override this method if you must close
        your connection after each request"""

        # obj = self.get_object(ref=ctx)
        # obj.close()
        self.set_object(obj=None, ref=ctx)  # it could be overidden

    ############################
    # To be overridden
    @abc.abstractmethod
    def custom_connection(self, **kwargs):
        return

    ############################
    # Already has default
    def custom_init(self, **kwargs):
        """
        The real signature:
        def custom_init(self, pinit=False, pdestroy=False, abackend=None):

            - A backend is needed for non-standalone services
                e.g. authentication module
            - Project initialization/removal could be used here
                or carried on to low levels;
                they get activated by specific flask cli commands

        """
        return self.get_instance()