def login_user( self, sudo_id: int, transport_options: Optional[transport.TransportOptions] = None, ) -> None: """Authenticate using settings credentials and sudo as sudo_id. Make API calls as if authenticated as sudo_id. The sudo_id token is automatically renewed when it expires. In order to subsequently login_user() as another user you must first logout() """ if self._sudo_id is None: self._sudo_id = sudo_id try: self._login_sudo(transport_options or {}) except error.SDKError: self._sudo_id = None raise else: if self._sudo_id != sudo_id: raise error.SDKError( f"Another user ({self._sudo_id}) " "is already logged in. Log them out first." ) elif not self.is_sudo_authenticated: self._login_sudo(transport_options or {})
def _login(self) -> None: client_id = self.settings.read_config().get("client_id") client_secret = self.settings.read_config().get("client_secret") if not (client_id and client_secret): raise error.SDKError("Required auth credentials not found.") serialized = urllib.parse.urlencode({ "client_id": cast(str, client_id), "client_secret": cast(str, client_secret), }).encode("utf-8") response = self._ok( self.transport.request( transport.HttpMethod.POST, f"{self.settings.base_url}/api/{self.version}/login", body=serialized, headers={"Content-Type": "application/x-www-form-urlencoded"}, )) # ignore type: mypy bug doesn't recognized kwarg `structure` to partial func access_token = self.deserialize( data=response, structure=self.token_model) # type: ignore assert isinstance(access_token, token_model_isinstances) self.token = auth_token.AuthToken(access_token)
def _login_admin(self) -> None: config_data = self.settings.read_ini(self.settings._filename, self.settings._section) client_id = os.getenv(f"{versions.environment_prefix}_CLIENT_ID" ) or config_data.get("client_id") client_secret = os.getenv( f"{versions.environment_prefix}_CLIENT_SECRET") or config_data.get( "client_secret") if not (client_id and client_secret): raise error.SDKError("Required auth credentials not found.") serialized = urllib.parse.urlencode({ "client_id": cast(str, client_id), "client_secret": cast(str, client_secret), }).encode("utf-8") response = self._ok( self.transport.request( transport.HttpMethod.POST, "/login", body=serialized, headers={"Content-Type": "application/x-www-form-urlencoded"}, )) access_token = self.deserialize(response, models.AccessToken) assert isinstance(access_token, models.AccessToken) self.admin_token = auth_token.AuthToken(access_token)
def __init__( self, *, settings: api_settings.PApiSettings, transport: transport.Transport, deserialize: serialize.TDeserialize, serialize: serialize.TSerialize, crypto: CryptoHash, version: str, ): super().__init__(settings, transport, deserialize, version) self.crypto = crypto self.serialize = serialize config_data = self.settings.read_config() for required in ["client_id", "redirect_uri", "looker_url"]: if required not in config_data: raise error.SDKError( f"Missing required configuration value {required}") # would have prefered using setattr(self, required, ...) in loop above # but mypy can't follow it self.client_id = config_data["client_id"] self.redirect_uri = config_data["redirect_uri"] self.looker_url = config_data["looker_url"] self.code_verifier = ""
def test_scrape_dashboard_should_raise_sdk_error_on_failure(self): sdk = self.__scraper.__dict__['_MetadataScraper__sdk'] sdk.dashboard.side_effect = error.SDKError('SDK error') self.assertRaises(error.SDKError, self.__scraper.scrape_dashboard, 'dashboard-id') sdk.dashboard.assert_called_once() sdk.dashboard.assert_called_with(dashboard_id='dashboard-id')
def test_write_connections_new(mocker): conn_list = [models.WriteDBConnection(name="Taco")] mocker.patch.object(sdk, "connection", side_effect=error.SDKError("mocked error")) mocker.patch.object(sdk, "create_connection") deploy_connections.write_connections(conn_list, sdk) sdk.create_connection.assert_called_once_with(conn_list[0])
def test_scrape_model_explore_should_raise_sdk_error_on_failure(self): sdk = self.__scraper.__dict__['_MetadataScraper__sdk'] sdk.lookml_model_explore.side_effect = error.SDKError('SDK error') self.assertRaises(error.SDKError, self.__scraper.scrape_lookml_model_explore, 'test-model', 'test-view') sdk.lookml_model_explore.assert_called_once() sdk.lookml_model_explore.assert_called_with( lookml_model_name='test-model', explore_name='test-view')
def _return(self, response: transport.Response, structure: TStructure) -> TReturn: if not response.ok: raise error.SDKError(response.value) ret: TReturn if structure is None: ret = None elif structure is str: ret = response.value else: ret = self.deserialize(response.value, structure) return ret
def test_write_connections_update_pw_new(mocker): conn_list = [models.WriteDBConnection(name="Taco")] conf = {"Taco": "Cat"} mocker.patch.object(sdk, "connection", side_effect=error.SDKError("mocked error")) mocker.patch.object(sdk, "create_connection") deploy_connections.write_connections(conn_list, sdk, conf) sdk.create_connection.assert_called_once_with( models.WriteDBConnection(name="Taco", password="******"))
def _request_token( self, grant_type: Union[AuthCodeGrantTypeParams, RefreshTokenGrantTypeParams] ) -> Union[models31.AccessToken, models40.AccessToken]: response = self.transport.request( transport.HttpMethod.POST, urllib.parse.urljoin(self.settings.base_url, "/api/token"), body=self.serialize(grant_type), ) if not response.ok: raise error.SDKError(response.value.decode(encoding=response.encoding)) # ignore type: mypy bug doesn't recognized kwarg `structure` to partial func return self.deserialize( data=response.value, structure=self.token_model ) # type: ignore
def __init__( self, settings: api_settings.PApiSettings, transport: transport.Transport, deserialize: serialize.TDeserialize, ): if not settings.is_configured(): raise error.SDKError( "Missing required configuration values like base_url and api_version." ) self.settings = settings self.user_token: auth_token.AuthToken = auth_token.AuthToken() self.admin_token: auth_token.AuthToken = auth_token.AuthToken() self._sudo_id: Optional[int] = None self.transport = transport self.deserialize = deserialize
def _return(self, response: transport.Response, structure: TStructure) -> TReturn: encoding = response.encoding if not response.ok: raise error.SDKError(response.value.decode(encoding=encoding)) ret: TReturn if structure is None: ret = None elif response.response_mode == transport.ResponseMode.BINARY: ret = response.value else: value = response.value.decode(encoding=encoding) if structure is Union[str, bytes] or structure is str: # type: ignore ret = value else: ret = self.deserialize(value, structure) return ret
def _return(self, response: transport.Response, structure: TStructure) -> TReturn: encoding = response.encoding if not response.ok: raise error.SDKError(response.value.decode(encoding=encoding)) ret: TReturn if structure is None: ret = None elif response.response_mode == transport.ResponseMode.BINARY: ret = response.value else: value = response.value.decode(encoding=encoding) if structure is Union[str, bytes] or structure is str: # type: ignore ret = value else: # ignore type: mypy bug doesn't recognized kwarg # `structure` to partial func ret = self.deserialize(data=value, structure=structure) # type: ignore return ret
def configure(cls, filename: str = "looker.ini", section: Optional[str] = None) -> "ApiSettings": """Configure using a config file and/or environment variables. Environment variables will override config file settings. Neither is necessary but some combination must supply the minimum to instantiate ApiSettings. ENV variables map like this: <package-prefix>_API_VERSION -> api_version <package-prefix>_BASE_URL -> base_url <package-prefix>_VERIFY_SSL -> verify_ssl """ config_data = cls.read_ini(filename, section) env_api_version = cast( str, os.getenv(f"{constants.environment_prefix}_API_VERSION")) if env_api_version: config_data["api_version"] = env_api_version env_base_url = cast( str, os.getenv(f"{constants.environment_prefix}_BASE_URL")) if env_base_url: config_data["base_url"] = env_base_url env_verify_ssl = cast( str, os.getenv(f"{constants.environment_prefix}_VERIFY_SSL")) if env_verify_ssl: config_data["verify_ssl"] = env_verify_ssl if not config_data.get("base_url"): raise error.SDKError(f"Required parameter base_url not found.") converter = cattr.Converter() converter.register_structure_hook(bool, _convert_bool) settings: ApiSettings = converter.structure(config_data, cls) return settings
def test_run_recursive_dashboard_should_handle_sdk_error( self, mock_mapper, mock_cleaner, mock_ingestor): # noqa: E125 scraper = self.__synchronizer.__dict__[ '_MetadataSynchronizer__metadata_scraper'] lookml_folder = self.__make_fake_folder() lookml_folder.dashboards = [self.__make_fake_dashboard(lookml_folder)] scraper.scrape_folder.return_value = lookml_folder scraper.scrape_dashboard.side_effect = error.SDKError('SDK error') self.__synchronizer.run() scraper.scrape_dashboard.assert_called_once() mapper = mock_mapper.return_value mapper.fulfill_tag_fields.assert_called_once() cleaner = mock_cleaner.return_value cleaner.delete_obsolete_metadata.assert_called_once() ingestor = mock_ingestor.return_value ingestor.ingest_metadata.assert_called_once()
def __init__( self, settings: api_settings.PApiSettings, transport: transport.Transport, deserialize: serialize.TDeserialize, version: str, ): if not settings.is_configured(): raise error.SDKError( "Missing required configuration values like base_url and api_version." ) self.settings = settings self.sudo_token: auth_token.AuthToken = auth_token.AuthToken() self.token: auth_token.AuthToken = auth_token.AuthToken() self._sudo_id: Optional[int] = None self.transport = transport self.deserialize = deserialize self.version = version self.token_model: Union[Type[models31.AccessToken], Type[models40.AccessToken]] if self.version == "3.1": self.token_model = models31.AccessToken elif self.version == "4.0": self.token_model = models40.AccessToken
def _login_admin(self) -> None: client_id = self.settings.get_client_id() client_secret = self.settings.get_client_secret() if not (client_id and client_secret): raise error.SDKError("Required auth credentials not found.") serialized = urllib.parse.urlencode({ "client_id": cast(str, client_id), "client_secret": cast(str, client_secret), }).encode("utf-8") response = self._ok( self.transport.request( transport.HttpMethod.POST, "/login", body=serialized, headers={"Content-Type": "application/x-www-form-urlencoded"}, )) access_token = self.deserialize(data=response, structure=token_model) assert isinstance(access_token, token_model_isinstances) self.admin_token = auth_token.AuthToken(access_token)
def _ok(self, response: transport.Response) -> transport.TResponseValue: if not response.ok: raise error.SDKError(response.value) return response.value
def _ok(self, response: transport.Response) -> str: if not response.ok: raise error.SDKError(response.value) return response.value.decode(encoding="utf-8")
def is_configured(self) -> bool: if not self.base_url: raise error.SDKError( "Missing required configuration value: base_url")