예제 #1
0
    def build_sqlalchemy_uri(
        self, data: Dict[str, Any], **kwargs: Any
    ) -> Dict[str, Any]:
        """
        Build SQLAlchemy URI from separate parameters.

        This is used for databases that support being configured by individual
        parameters (eg, username, password, host, etc.), instead of requiring
        the constructed SQLAlchemy URI to be passed.
        """
        parameters = data.pop("parameters", {})

        # TODO (betodealmeida): remove second expression after making sure
        # frontend is not passing engine inside parameters
        engine = data.pop("engine", None) or parameters.pop("engine", None)

        configuration_method = data.get("configuration_method")
        if configuration_method == ConfigurationMethod.DYNAMIC_FORM:
            if not engine:
                raise ValidationError(
                    [
                        _(
                            "An engine must be specified when passing "
                            "individual parameters to a database."
                        )
                    ]
                )
            engine_specs = get_engine_specs()
            if engine not in engine_specs:
                raise ValidationError(
                    [_('Engine "%(engine)s" is not a valid engine.', engine=engine,)]
                )
            engine_spec = engine_specs[engine]

            if not hasattr(engine_spec, "build_sqlalchemy_uri") or not hasattr(
                engine_spec, "parameters_schema"
            ):
                raise ValidationError(
                    [
                        _(
                            'Engine spec "InvalidEngine" does not support '
                            "being configured via individual parameters."
                        )
                    ]
                )

            # validate parameters
            parameters = engine_spec.parameters_schema.load(parameters)  # type: ignore

            serialized_encrypted_extra = data.get("encrypted_extra", "{}")
            try:
                encrypted_extra = json.loads(serialized_encrypted_extra)
            except json.decoder.JSONDecodeError:
                encrypted_extra = {}

            data["sqlalchemy_uri"] = engine_spec.build_sqlalchemy_uri(  # type: ignore
                parameters, encrypted_extra
            )

        return data
예제 #2
0
    def build_sqlalchemy_uri(self, data: Dict[str, Any],
                             **kwargs: Any) -> Dict[str, Any]:
        """
        Build SQLAlchemy URI from separate parameters.

        This is used for databases that support being configured by individual
        parameters (eg, username, password, host, etc.), instead of requiring
        the constructed SQLAlchemy URI to be passed.
        """
        parameters = data.pop("parameters", None)
        if parameters:
            if "engine" not in parameters:
                raise ValidationError([
                    _("An engine must be specified when passing "
                      "individual parameters to a database.")
                ])
            engine = parameters["engine"]

            engine_specs = get_engine_specs()
            if engine not in engine_specs:
                raise ValidationError([
                    _(
                        'Engine "%(engine)s" is not a valid engine.',
                        engine=engine,
                    )
                ])
            engine_spec = engine_specs[engine]
            if hasattr(engine_spec, "build_sqlalchemy_uri"):
                data[
                    "sqlalchemy_uri"] = engine_spec.build_sqlalchemy_uri(  # type: ignore
                        parameters)
        return data
예제 #3
0
def get_engine_spec(engine: Optional[str]) -> Type[BaseEngineSpec]:
    if not engine:
        raise ValidationError([
            _("An engine must be specified when passing "
              "individual parameters to a database.")
        ])
    engine_specs = get_engine_specs()
    if engine not in engine_specs:
        raise ValidationError(
            [_(
                'Engine "%(engine)s" is not a valid engine.',
                engine=engine,
            )])
    return engine_specs[engine]
예제 #4
0
 def test_engine_time_grain_validity(self):
     time_grains = set(builtin_time_grains.keys())
     # loop over all subclasses of BaseEngineSpec
     for engine in get_engine_specs().values():
         if engine is not BaseEngineSpec:
             # make sure time grain functions have been defined
             self.assertGreater(len(engine.get_time_grain_expressions()), 0)
             # make sure all defined time grains are supported
             defined_grains = {
                 grain.duration
                 for grain in engine.get_time_grains()
             }
             intersection = time_grains.intersection(defined_grains)
             self.assertSetEqual(defined_grains, intersection, engine)
예제 #5
0
 def get_db_engine_spec_for_backend(
     cls, backend: str
 ) -> Type[db_engine_specs.BaseEngineSpec]:
     engines = db_engine_specs.get_engine_specs()
     return engines.get(backend, db_engine_specs.BaseEngineSpec)
예제 #6
0
 def test_engine_alias_name(self):
     """
     DB Eng Specs (postgres): Test "postgres" in engine spec
     """
     self.assertIn("postgres", get_engine_specs())
예제 #7
0
파일: validate.py 프로젝트: swaitw/superset
    def run(self) -> None:
        engine = self._properties["engine"]
        engine_specs = get_engine_specs()

        if engine in BYPASS_VALIDATION_ENGINES:
            # Skip engines that are only validated onCreate
            return

        if engine not in engine_specs:
            raise InvalidEngineError(
                SupersetError(
                    message=__(
                        'Engine "%(engine)s" is not a valid engine.',
                        engine=engine,
                    ),
                    error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR,
                    level=ErrorLevel.ERROR,
                    extra={
                        "allowed": list(engine_specs),
                        "provided": engine
                    },
                ), )
        engine_spec = engine_specs[engine]
        if not issubclass(engine_spec, BasicParametersMixin):
            raise InvalidEngineError(
                SupersetError(
                    message=__(
                        'Engine "%(engine)s" cannot be configured through parameters.',
                        engine=engine,
                    ),
                    error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR,
                    level=ErrorLevel.ERROR,
                    extra={
                        "allowed": [
                            name for name, engine_spec in engine_specs.items()
                            if issubclass(engine_spec, BasicParametersMixin)
                        ],
                        "provided":
                        engine,
                    },
                ), )

        # perform initial validation
        errors = engine_spec.validate_parameters(
            self._properties.get("parameters", {}))
        if errors:
            raise InvalidParametersError(errors)

        serialized_encrypted_extra = self._properties.get(
            "encrypted_extra", "{}")
        try:
            encrypted_extra = json.loads(serialized_encrypted_extra)
        except json.decoder.JSONDecodeError:
            encrypted_extra = {}

        # try to connect
        sqlalchemy_uri = engine_spec.build_sqlalchemy_uri(
            self._properties.get("parameters", None),  # type: ignore
            encrypted_extra,
        )
        if self._model and sqlalchemy_uri == self._model.safe_sqlalchemy_uri():
            sqlalchemy_uri = self._model.sqlalchemy_uri_decrypted
        database = DatabaseDAO.build_db_for_connection_test(
            server_cert=self._properties.get("server_cert", ""),
            extra=self._properties.get("extra", "{}"),
            impersonate_user=self._properties.get("impersonate_user", False),
            encrypted_extra=serialized_encrypted_extra,
        )
        database.set_sqlalchemy_uri(sqlalchemy_uri)
        database.db_engine_spec.mutate_db_for_connection_test(database)
        username = self._actor.username if self._actor is not None else None
        engine = database.get_sqla_engine(user_name=username)
        try:
            with closing(engine.raw_connection()) as conn:
                alive = engine.dialect.do_ping(conn)
        except Exception as ex:  # pylint: disable=broad-except
            url = make_url(sqlalchemy_uri)
            context = {
                "hostname": url.host,
                "password": url.password,
                "port": url.port,
                "username": url.username,
                "database": url.database,
            }
            errors = database.db_engine_spec.extract_errors(ex, context)
            raise DatabaseTestConnectionFailedError(errors)

        if not alive:
            raise DatabaseOfflineError(
                SupersetError(
                    message=__("Database is offline."),
                    error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR,
                    level=ErrorLevel.ERROR,
                ), )
예제 #8
0
파일: core.py 프로젝트: zhiwuya/superset
 def db_engine_spec(self) -> Type[db_engine_specs.BaseEngineSpec]:
     engines = db_engine_specs.get_engine_specs()
     return engines.get(self.backend, db_engine_specs.BaseEngineSpec)