def _validate_initialization_type(self, settings_object: Config): if settings_object.INIESTA_INITIALIZATION_TYPE is None: raise ImproperlyConfigured( "Please configure INIESTA_INITIALIZATION_TYPE in your config!") if not isinstance(settings_object.INIESTA_INITIALIZATION_TYPE, (list, tuple)): raise ImproperlyConfigured( "INIESTA_INITIALIZATION_TYPE type is invalid. Must be list or tuple!" )
def get_rate(self) -> str: """ Determine the string representation of the allowed request rate. """ if not getattr(self, "scope", None): msg = ( "You must set either `.scope` or `.rate` for '%s' throttle" % self.__class__.__name__) raise ImproperlyConfigured(msg) try: return self.THROTTLE_RATES[self.scope] except KeyError: msg = "No default throttle rate set for '%s' scope" % self.scope raise ImproperlyConfigured(msg)
async def confirm_permission(self) -> None: """ Confirms correct permissions are in place. :raises ImproperlyConfigured: If the permissions were not found. :raises AssertionError: If the permissions are not correctly configured on AWS. """ session = BotoSession.get_session() async with session.create_client( "sqs", region_name=self.region_name or BotoSession.aws_default_region, endpoint_url=self.endpoint_url, aws_access_key_id=BotoSession.aws_access_key_id, aws_secret_access_key=BotoSession.aws_secret_access_key, ) as client: policy_attributes = await client.get_queue_attributes( QueueUrl=self.queue_url, AttributeNames=["Policy"] ) try: policies = json.loads(policy_attributes["Attributes"]["Policy"]) statement = policies["Statement"][0] except KeyError: raise ImproperlyConfigured("Permissions not found.") # need "Effect": "Allow", "Action": "SQS:SendMessage" assert statement["Effect"] == "Allow" assert "SQS:SendMessage" in statement["Action"]
def _init_event_polling(self, app: Insanic) -> None: """ Initializes for event polling. Actions: - Checks if global arn exists - Checks if filters are 0 to avoid receiving all messages - Loads iniesta configs - Attaches listeners - Checks if queue exists (initialize) - Checks subscriptions - Checks permissions """ self.load_config(app.config) if not app.config.INIESTA_DRY_RUN: # check if global arn exists self.check_global_arn(app.config) # check if filters are 0 if len(app.config.INIESTA_SQS_CONSUMER_FILTERS) == 0: raise ImproperlyConfigured( "INIESTA_SQS_CONSUMER_FILTERS is an empty list. " "Please specify events to receive!") listener = IniestaListener() app.register_listener(listener.after_server_start_event_polling, "after_server_start") app.register_listener(listener.before_server_stop_stop_polling, "before_server_stop")
def configure_version(self, version: str) -> None: """ Configures the application version and sets the version on settings. This is especially necessary for microservices. Precedence 1. `version` argument 2. APPLICATION_VERSION in settings 3. defaults to `UNKNOWN` :param version: version of the service or application """ if (settings.ENFORCE_APPLICATION_VERSION and version is None and settings.APPLICATION_VERSION is None): raise ImproperlyConfigured( "`version` must be included. Either set " "`ENFORCE_APPLICATION_VERSION` to False or include " "`version` when initializing Insanic. Or just include " "`APPLICATION_VERSION` in your config.`") settings.APPLICATION_VERSION = (version or settings.APPLICATION_VERSION or "UNKNOWN")
def _order_initialization_type(self, settings_object: Config) -> list: try: init_types = settings_object.INIESTA_INITIALIZATION_TYPE return sorted([InitializationTypes[it] for it in init_types]) except (KeyError, TypeError): raise ImproperlyConfigured( f"{str(init_types)} is " f"an invalid initialization type. " f"Choices are {', '.join(str(i) for i in self.INITIALIZATION_MAPPING.keys())}" )
def verify_plugin_requirements(self) -> None: """ Checks if the required plugins set in `REQUIRED_PLUGINS` have been installed and initialized. """ for plugin in self.config.REQUIRED_PLUGINS: if plugin not in self.initialized_plugins.keys(): raise ImproperlyConfigured( f"{plugin} is defined in `REQUIRED_PLUGINS` in this " f"environment but has not been initialized.")
def __getattr__(self, name): """Return the value of a setting and cache it in self.__dict__.""" if self._wrapped is empty: self._setup(name) # val = self.__dict__.get(name) or getattr(self._wrapped, name) val = getattr(self._wrapped, name) # some special cases if name in {"SERVICE_NAME", "SECRET_KEY"} and not val: raise ImproperlyConfigured( "The SERVICE_NAME setting must not be empty.") self.__dict__[name] = val return val
def caches(self): if self._caches is None: caches = settings.INSANIC_CACHES for k, v in settings.CACHES.items(): if k in caches: raise ImproperlyConfigured( f"Cannot override {k}. This is a " f"protected cache reserved for insanic use." ) caches.update({k: v}) self._caches = caches return self._caches
def __call__(self, func_or_cls: [HTTPMethodView, Callable]): @wraps(func_or_cls) def wrapper(*args, **kwargs): request = None for arg in args: if isinstance(arg, Request): request = arg break view_response = func_or_cls(*args, **kwargs) if request: now = get_utc_timestamp() request_service = ( f"@{request.service.request_service.upper() or 'FE'}") request_type = f"{request.method} {request.uri_template}" key = (request_service, request.method, request.uri_template) if key not in self.last_call: self.last_call[key] = now - self.ttl if self.last_call[key] + self.ttl <= now: logger.warning( f"[DEPRECATION WARNING] For maintainers of {request_service}! " f"{request_type} will be deprecated on {self.dt}. " f"You have {get_utc_datetime() - self.dt} left!") self.last_call[key] = now return view_response if inspect.isclass(func_or_cls): if issubclass(func_or_cls, HTTPMethodView): for m in func_or_cls.http_method_names: handler = getattr(func_or_cls, m.lower(), None) if handler is None: continue setattr(func_or_cls, m.lower(), self.__call__(handler)) return func_or_cls else: raise ImproperlyConfigured( "Must wrap a HTTPMethodView subclass.") else: return wrapper
def _setup(self, name=None): """ Load the settings module pointed to by the environment variable. This is used the first time we need any settings at all, if the user has not previously configured the settings manually. """ settings_module = os.environ.get(ENVIRONMENT_VARIABLE) if not settings_module: desc = ("setting %s" % name) if name else "settings" raise ImproperlyConfigured( "Requested %s, but settings are not configured. " "You must either define the environment variable %s " "or call settings.configure() before accessing settings." % (desc, ENVIRONMENT_VARIABLE)) self._wrapped = self.config_class(settings_module)
def init_app(self, app: Insanic) -> None: """ Initializes the application depending on INIESTA_INITIALIZATION_TYPE set in settings """ if self._initialization_type is not empty: raise ImproperlyConfigured("Iniesta has already been initialized!") self.load_config(app.config) self._validate_initialization_type(app.config) initialization_types = self._order_initialization_type(app.config) for choice in initialization_types: initialization_method = self.INITIALIZATION_MAPPING[choice] initialization_method(app) self.initialization_type = choice
def check_global_arn(self, settings_object: Config) -> None: if settings_object.INIESTA_SNS_PRODUCER_GLOBAL_TOPIC_ARN is None: raise ImproperlyConfigured( "INIESTA_SNS_PRODUCER_GLOBAL_TOPIC_ARN not set in settings!")