Fix #4032 - Bigquery properties & GCS Credentials (#4202)

Fix #4032 - Bigquery properties & GCS Credentials (#4202)
This commit is contained in:
Pere Miquel Brull 2022-04-19 12:31:34 +02:00 committed by GitHub
parent c7bd445676
commit 256b16d877
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 312 additions and 128 deletions

View File

@ -39,10 +39,14 @@
"description": "username to connect to the Athena. This user should have privileges to read all the metadata in Athena.", "description": "username to connect to the Athena. This user should have privileges to read all the metadata in Athena.",
"type": "string" "type": "string"
}, },
"projectID": { "projectId": {
"description": "Google BigQuery project id.", "description": "BigQuery project ID. Inform it here if passing the credentials path.",
"type": "string" "type": "string"
}, },
"credentials": {
"description": "GCS Credentials",
"$ref": "../../../../security/credentials/gcsCredentials.json"
},
"enablePolicyTagImport": { "enablePolicyTagImport": {
"description": "Enable importing policy tags of BigQuery into OpenMetadata", "description": "Enable importing policy tags of BigQuery into OpenMetadata",
"type": "boolean", "type": "boolean",
@ -87,6 +91,6 @@
}, },
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": [
"projectID" "credentials"
] ]
} }

View File

@ -0,0 +1,82 @@
{
"$id": "https://open-metadata.org/security/credentials/gcsCredentials.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GCSCredentials",
"description": "GCS credentials configs.",
"type": "object",
"javaType": "org.openmetadata.catalog.security.credentials.GCSCredentials",
"definitions": {
"GCSValues": {
"description": "GCS Credentials.",
"type": "object",
"properties": {
"type": {
"description": "Google Cloud service account type.",
"type": "string"
},
"projectId": {
"description": "Google Cloud project id.",
"type": "string"
},
"privateKeyId": {
"description": "Google Cloud private key id.",
"type": "string"
},
"privateKey": {
"description": "Google Cloud private key.",
"type": "string"
},
"clientEmail": {
"description": "Google Cloud email.",
"type": "string"
},
"clientId": {
"description": "Google Cloud Client ID.",
"type": "string"
},
"authUri": {
"description": "Google Cloud auth uri.",
"type": "string",
"format": "uri"
},
"tokenUri": {
"description": "Google Cloud token uri.",
"type": "string",
"format": "uri"
},
"authProviderX509CertUrl": {
"description": "Google Cloud auth provider certificate.",
"type": "string",
"format": "uri"
},
"clientX509CertUrl": {
"description": "Google Cloud client certificate uri.",
"type": "string",
"format": "uri"
}
},
"additionalProperties": false
},
"GCSCredentialsPath": {
"description": "GCS Credentials Path.",
"type": "string"
}
},
"properties": {
"gcsConfig": {
"description": "GCS configs.",
"oneOf": [
{
"$ref": "#/definitions/GCSValues"
},
{
"$ref": "#/definitions/GCSCredentialsPath"
}
]
}
},
"additionalProperties": false,
"required": [
"gcsConfig"
]
}

View File

@ -364,7 +364,7 @@ public class DatabaseServiceResourceTest extends EntityResourceTest<DatabaseServ
public static void validateBigQueryConnection( public static void validateBigQueryConnection(
BigQueryConnection expectedBigQueryConnection, BigQueryConnection actualBigQueryConnection) { BigQueryConnection expectedBigQueryConnection, BigQueryConnection actualBigQueryConnection) {
assertEquals(expectedBigQueryConnection.getHostPort(), actualBigQueryConnection.getHostPort()); assertEquals(expectedBigQueryConnection.getHostPort(), actualBigQueryConnection.getHostPort());
assertEquals(expectedBigQueryConnection.getProjectID(), actualBigQueryConnection.getProjectID()); assertEquals(expectedBigQueryConnection.getCredentials(), actualBigQueryConnection.getCredentials());
assertEquals(expectedBigQueryConnection.getUsername(), actualBigQueryConnection.getUsername()); assertEquals(expectedBigQueryConnection.getUsername(), actualBigQueryConnection.getUsername());
assertEquals(expectedBigQueryConnection.getScheme(), actualBigQueryConnection.getScheme()); assertEquals(expectedBigQueryConnection.getScheme(), actualBigQueryConnection.getScheme());
assertEquals(expectedBigQueryConnection.getDatabase(), actualBigQueryConnection.getDatabase()); assertEquals(expectedBigQueryConnection.getDatabase(), actualBigQueryConnection.getDatabase());

View File

@ -5,7 +5,20 @@
"config": { "config": {
"type": "BigQuery", "type": "BigQuery",
"hostPort": "localhost:1234", "hostPort": "localhost:1234",
"projectID": "project_id" "credentials": {
"gcsConfig": {
"type": "service_account",
"projectId": "projectID",
"privateKeyId": "privateKeyId",
"privateKey": "privateKey",
"clientEmail": "clientEmail",
"clientId": "clientId",
"authUri": "https://accounts.google.com/o/oauth2/auth",
"tokenUri": "https://oauth2.googleapis.com/token",
"authProviderX509CertUrl": "https://www.googleapis.com/oauth2/v1/certs",
"clientX509CertUrl": "https://cert.url"
}
}
} }
}, },
"sourceConfig": { "sourceConfig": {

View File

@ -5,22 +5,17 @@
"serviceConnection": { "serviceConnection": {
"config": { "config": {
"type": "BigQuery", "type": "BigQuery",
"projectID": "project_id",
"enablePolicyTagImport": true, "enablePolicyTagImport": true,
"connectionOptions": { "credentialsType": "service_account",
"credentials": { "projectID": "projectID",
"type": "service_account", "privateKeyId": "privateKeyId",
"project_id": "project_id", "privateKey": "privateKey",
"private_key_id": "private_key_id", "clientEmail": "clientEmail",
"private_key": "private_key", "clientId": "clientId",
"client_email": "gcpuser@project_id.iam.gserviceaccount.com", "authURI": "https://accounts.google.com/o/oauth2/auth",
"client_id": "client_id", "tokenURI": "https://oauth2.googleapis.com/token",
"auth_uri": "https://accounts.google.com/o/oauth2/auth", "authProviderX509CertUrl": "https://www.googleapis.com/oauth2/v1/certs",
"token_uri": "https://oauth2.googleapis.com/token", "clientX509CertUrl": "clientX509CertUrl"
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": ""
}
}
} }
}, },
"sourceConfig": {"config": {"enableDataProfiler": false}} "sourceConfig": {"config": {"enableDataProfiler": false}}

View File

@ -8,10 +8,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import json
import logging import logging
import os import os
import tempfile
from typing import Optional, Tuple from typing import Optional, Tuple
from google.cloud.datacatalog_v1 import PolicyTagManagerClient from google.cloud.datacatalog_v1 import PolicyTagManagerClient
@ -40,6 +38,7 @@ from metadata.generated.schema.type.entityReference import EntityReference
from metadata.ingestion.api.source import InvalidSourceException from metadata.ingestion.api.source import InvalidSourceException
from metadata.ingestion.source.sql_source import SQLSource from metadata.ingestion.source.sql_source import SQLSource
from metadata.utils.column_type_parser import create_sqlalchemy_type from metadata.utils.column_type_parser import create_sqlalchemy_type
from metadata.utils.credentials import set_google_credentials
from metadata.utils.helpers import get_start_and_end from metadata.utils.helpers import get_start_and_end
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -84,7 +83,9 @@ _types.get_columns = get_columns
class BigquerySource(SQLSource): class BigquerySource(SQLSource):
def __init__(self, config, metadata_config): def __init__(self, config, metadata_config):
super().__init__(config, metadata_config) super().__init__(config, metadata_config)
self.connection_config = self.config.serviceConnection.__root__.config self.connection_config: BigQueryConnection = (
self.config.serviceConnection.__root__.config
)
self.temp_credentials = None self.temp_credentials = None
# and "policy_tags" in column and column["policy_tags"] # and "policy_tags" in column and column["policy_tags"]
@ -109,35 +110,12 @@ class BigquerySource(SQLSource):
raise InvalidSourceException( raise InvalidSourceException(
f"Expected BigQueryConnection, but got {connection}" f"Expected BigQueryConnection, but got {connection}"
) )
if (
not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")
and connection.connectionOptions
):
options = connection.connectionOptions.dict()
if options.get("credentials_path"):
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = options[
"credentials_path"
]
del connection.connectionOptions.credentials_path
elif options.get("credentials"):
cls.temp_credentials = cls.create_credential_temp_file(
credentials=options["credentials"]
)
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = cls.temp_credentials
del connection.connectionOptions.credentials
else:
logger.warning(
"Please refer to the BigQuery connector documentation, especially the credentials part "
"https://docs.open-metadata.org/connectors/bigquery"
)
return cls(config, metadata_config)
@staticmethod set_google_credentials(
def create_credential_temp_file(credentials: dict) -> str: gcs_credentials=config.serviceConnection.__root__.config.credentials
with tempfile.NamedTemporaryFile(delete=False) as fp: )
cred_json = json.dumps(credentials, indent=4, separators=(",", ": "))
fp.write(cred_json.encode()) return cls(config, metadata_config)
return fp.name
def standardize_schema_table_names( def standardize_schema_table_names(
self, schema: str, table: str self, schema: str, table: str
@ -184,7 +162,10 @@ class BigquerySource(SQLSource):
def _get_database(self, database: Optional[str]) -> Database: def _get_database(self, database: Optional[str]) -> Database:
if not database: if not database:
database = self.service_connection.projectID database = (
self.connection_config.projectId
or self.connection_config.credentials.gcsConfig.projectId
)
return Database( return Database(
name=database, name=database,
service=EntityReference( service=EntityReference(

View File

@ -33,8 +33,8 @@ from metadata.generated.schema.metadataIngestion.workflow import (
) )
from metadata.ingestion.api.source import InvalidSourceException, Source, SourceStatus from metadata.ingestion.api.source import InvalidSourceException, Source, SourceStatus
from metadata.ingestion.models.table_queries import TableQuery from metadata.ingestion.models.table_queries import TableQuery
from metadata.ingestion.source.bigquery import BigquerySource
from metadata.ingestion.source.sql_alchemy_helper import SQLSourceStatus from metadata.ingestion.source.sql_alchemy_helper import SQLSourceStatus
from metadata.utils.credentials import set_google_credentials
from metadata.utils.helpers import get_start_and_end from metadata.utils.helpers import get_start_and_end
logger = log.getLogger(__name__) logger = log.getLogger(__name__)
@ -50,7 +50,13 @@ class BigqueryUsageSource(Source[TableQuery]):
self.metadata_config = metadata_config self.metadata_config = metadata_config
self.config = config self.config = config
self.service_connection = config.serviceConnection.__root__.config self.service_connection = config.serviceConnection.__root__.config
self.project_id = self.service_connection.projectID
# Used as db
self.project_id = (
self.service_connection.projectId
or self.service_connection.credentials.gcsConfig.projectId
)
self.logger_name = "cloudaudit.googleapis.com%2Fdata_access" self.logger_name = "cloudaudit.googleapis.com%2Fdata_access"
self.status = SQLSourceStatus() self.status = SQLSourceStatus()
@ -58,28 +64,15 @@ class BigqueryUsageSource(Source[TableQuery]):
def create(cls, config_dict, metadata_config: OpenMetadataConnection): def create(cls, config_dict, metadata_config: OpenMetadataConnection):
config: WorkflowSource = WorkflowSource.parse_obj(config_dict) config: WorkflowSource = WorkflowSource.parse_obj(config_dict)
connection: BigQueryConnection = config.serviceConnection.__root__.config connection: BigQueryConnection = config.serviceConnection.__root__.config
options = connection.connectionOptions.dict()
if not isinstance(connection, BigQueryConnection): if not isinstance(connection, BigQueryConnection):
raise InvalidSourceException( raise InvalidSourceException(
f"Expected BigQueryConnection, but got {connection}" f"Expected BigQueryConnection, but got {connection}"
) )
if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS"):
if options.get("credentials_path"): set_google_credentials(
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = options[ gcs_credentials=config.serviceConnection.__root__.config.credentials
"credentials_path"
]
del connection.connectionOptions.credentials_path
elif options.get("credentials"):
cls.temp_credentials = BigquerySource.create_credential_temp_file(
credentials=options["credentials"]
)
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = cls.temp_credentials
del connection.connectionOptions.credentials
else:
logger.warning(
"Please refer to the BigQuery connector documentation, especially the credentials part "
"https://docs.open-metadata.org/connectors/bigquery"
) )
return cls(config, metadata_config) return cls(config, metadata_config)
def prepare(self): def prepare(self):

View File

@ -18,9 +18,6 @@ from typing import Any, Dict, Iterable
from metadata.generated.schema.entity.services.connections.database.clickhouseConnection import ( from metadata.generated.schema.entity.services.connections.database.clickhouseConnection import (
ClickhouseConnection, ClickhouseConnection,
) )
from metadata.generated.schema.entity.services.databaseService import (
DatabaseServiceType,
)
from metadata.generated.schema.metadataIngestion.workflow import ( from metadata.generated.schema.metadataIngestion.workflow import (
Source as WorkflowSource, Source as WorkflowSource,
) )
@ -31,7 +28,7 @@ from metadata.ingestion.api.source import InvalidSourceException, Source, Source
from metadata.ingestion.models.table_queries import TableQuery from metadata.ingestion.models.table_queries import TableQuery
from metadata.ingestion.source.sql_alchemy_helper import SQLSourceStatus from metadata.ingestion.source.sql_alchemy_helper import SQLSourceStatus
from metadata.utils.engines import get_engine, test_connection from metadata.utils.engines import get_engine, test_connection
from metadata.utils.helpers import get_raw_extract_iter, get_start_and_end from metadata.utils.helpers import get_start_and_end
from metadata.utils.sql_queries import CLICKHOUSE_SQL_USAGE_STATEMENT from metadata.utils.sql_queries import CLICKHOUSE_SQL_USAGE_STATEMENT

View File

@ -17,9 +17,6 @@ from typing import Any, Dict, Iterable
from metadata.generated.schema.entity.services.connections.database.mssqlConnection import ( from metadata.generated.schema.entity.services.connections.database.mssqlConnection import (
MssqlConnection, MssqlConnection,
) )
from metadata.generated.schema.entity.services.databaseService import (
DatabaseServiceType,
)
from metadata.generated.schema.metadataIngestion.workflow import ( from metadata.generated.schema.metadataIngestion.workflow import (
Source as WorkflowSource, Source as WorkflowSource,
) )
@ -30,7 +27,7 @@ from metadata.ingestion.api.source import InvalidSourceException, Source, Source
from metadata.ingestion.models.table_queries import TableQuery from metadata.ingestion.models.table_queries import TableQuery
from metadata.ingestion.source.sql_alchemy_helper import SQLSourceStatus from metadata.ingestion.source.sql_alchemy_helper import SQLSourceStatus
from metadata.utils.engines import get_engine, test_connection from metadata.utils.engines import get_engine, test_connection
from metadata.utils.helpers import get_raw_extract_iter, get_start_and_end from metadata.utils.helpers import get_start_and_end
from metadata.utils.sql_queries import MSSQL_SQL_USAGE_STATEMENT from metadata.utils.sql_queries import MSSQL_SQL_USAGE_STATEMENT

View File

@ -66,7 +66,9 @@ class PostgresSource(SQLSource):
try: try:
logger.info(f"Ingesting from database: {row[0]}") logger.info(f"Ingesting from database: {row[0]}")
self.service_connection.database = row[0] self.service_connection.database = row[0]
self.engine = get_engine(self.config.serviceConnection) self.engine = get_engine(
self.config.serviceConnection.__root__.config
)
self.engine.connect() self.engine.connect()
yield inspect(self.engine) yield inspect(self.engine)
except Exception as err: except Exception as err:

View File

@ -35,7 +35,6 @@ from metadata.generated.schema.metadataIngestion.workflow import (
from metadata.ingestion.api.source import InvalidSourceException from metadata.ingestion.api.source import InvalidSourceException
from metadata.ingestion.source.sql_source import SQLSource from metadata.ingestion.source.sql_source import SQLSource
from metadata.utils.column_type_parser import create_sqlalchemy_type from metadata.utils.column_type_parser import create_sqlalchemy_type
from metadata.utils.engines import get_engine
GEOGRAPHY = create_sqlalchemy_type("GEOGRAPHY") GEOGRAPHY = create_sqlalchemy_type("GEOGRAPHY")
ischema_names["VARIANT"] = VARIANT ischema_names["VARIANT"] = VARIANT
@ -82,7 +81,6 @@ class SnowflakeSource(SQLSource):
self.connection.execute(use_db_query) self.connection.execute(use_db_query)
logger.info(f"Ingesting from database: {row[1]}") logger.info(f"Ingesting from database: {row[1]}")
self.config.serviceConnection.__root__.config.database = row[1] self.config.serviceConnection.__root__.config.database = row[1]
self.engine = get_engine(self.config.serviceConnection)
yield inspect(self.engine) yield inspect(self.engine)
def fetch_sample_data(self, schema: str, table: str) -> Optional[TableData]: def fetch_sample_data(self, schema: str, table: str) -> Optional[TableData]:

View File

@ -134,7 +134,7 @@ class SQLSource(Source[OMetaDatabaseAndTable]):
entity=DatabaseService, config=config entity=DatabaseService, config=config
) )
self.engine = get_engine(service_connection=self.config.serviceConnection) self.engine = get_engine(self.service_connection)
self.test_connection() self.test_connection()
self._session = None # We will instantiate this just if needed self._session = None # We will instantiate this just if needed

View File

@ -0,0 +1,81 @@
# Copyright 2021 Collate
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Credentials helper module
"""
import json
import os
import tempfile
from metadata.generated.schema.security.credentials.gcsCredentials import (
GCSCredentials,
GCSCredentialsPath,
GCSValues,
)
GOOGLE_CREDENTIALS = "GOOGLE_APPLICATION_CREDENTIALS"
class InvalidGcsConfigException(Exception):
"""
Raised when we have errors trying to set GCS credentials
"""
def create_credential_tmp_file(credentials: dict) -> str:
"""
Given a credentials' dict, store it in a tmp file
:param credentials: dictionary to store
:return: path to find the file
"""
with tempfile.NamedTemporaryFile(delete=False) as fp:
cred_json = json.dumps(credentials, indent=4, separators=(",", ": "))
fp.write(cred_json.encode())
return fp.name
def set_google_credentials(gcs_credentials: GCSCredentials) -> None:
"""
Set GCS credentials environment variable
:param gcs_credentials: GCSCredentials
"""
if os.environ.get(GOOGLE_CREDENTIALS):
return
if isinstance(gcs_credentials.gcsConfig, GCSCredentialsPath):
os.environ[GOOGLE_CREDENTIALS] = str(gcs_credentials.gcsConfig.__root__)
return
if isinstance(gcs_credentials.gcsConfig, GCSValues):
credentials_dict = {
"type": gcs_credentials.gcsConfig.type,
"project_id": gcs_credentials.gcsConfig.projectId,
"private_key_id": gcs_credentials.gcsConfig.privateKeyId,
"private_key": gcs_credentials.gcsConfig.privateKey,
"client_email": gcs_credentials.gcsConfig.clientEmail,
"client_id": gcs_credentials.gcsConfig.clientId,
"auth_uri": str(gcs_credentials.gcsConfig.authUri),
"token_uri": str(gcs_credentials.gcsConfig.tokenUri),
"auth_provider_x509_cert_url": str(
gcs_credentials.gcsConfig.authProviderX509CertUrl
),
"client_x509_cert_url": str(gcs_credentials.gcsConfig.clientX509CertUrl),
}
tmp_credentials_file = create_credential_tmp_file(credentials=credentials_dict)
os.environ[GOOGLE_CREDENTIALS] = tmp_credentials_file
return
raise InvalidGcsConfigException(
f"Error trying to set GCS credentials with {gcs_credentials}."
" Check https://docs.open-metadata.org/connectors/bigquery"
)

View File

@ -23,9 +23,6 @@ from sqlalchemy.orm.session import Session
from metadata.generated.schema.entity.services.connections.connectionBasicType import ( from metadata.generated.schema.entity.services.connections.connectionBasicType import (
ConnectionOptions, ConnectionOptions,
) )
from metadata.generated.schema.entity.services.connections.serviceConnection import (
ServiceConnection,
)
from metadata.utils.source_connections import get_connection_args, get_connection_url from metadata.utils.source_connections import get_connection_args, get_connection_url
from metadata.utils.timeout import timeout from metadata.utils.timeout import timeout
@ -38,20 +35,19 @@ class SourceConnectionException(Exception):
""" """
def get_engine(service_connection: ServiceConnection, verbose: bool = False) -> Engine: def get_engine(connection, verbose: bool = False) -> Engine:
""" """
Given an SQL configuration, build the SQLAlchemy Engine Given an SQL configuration, build the SQLAlchemy Engine
""" """
service_connection_config = service_connection.__root__.config
options = service_connection_config.connectionOptions options = connection.connectionOptions
if not options: if not options:
options = ConnectionOptions() options = ConnectionOptions()
engine = create_engine( engine = create_engine(
get_connection_url(service_connection_config), get_connection_url(connection),
**options.dict(), **options.dict(),
connect_args=get_connection_args(service_connection_config), connect_args=get_connection_args(connection),
echo=verbose, echo=verbose,
) )

View File

@ -73,6 +73,7 @@ from metadata.generated.schema.entity.services.connections.database.trinoConnect
from metadata.generated.schema.entity.services.connections.database.verticaConnection import ( from metadata.generated.schema.entity.services.connections.database.verticaConnection import (
VerticaConnection, VerticaConnection,
) )
from metadata.generated.schema.security.credentials.gcsCredentials import GCSValues
def get_connection_url_common(connection): def get_connection_url_common(connection):
@ -254,8 +255,13 @@ def _(connection: HiveConnection):
@get_connection_url.register @get_connection_url.register
def _(connection: BigQueryConnection): def _(connection: BigQueryConnection):
if connection.projectID: project_id = connection.projectId
return f"{connection.scheme.value}://{connection.projectID}" if not project_id and isinstance(connection.credentials.gcsConfig, GCSValues):
project_id = connection.credentials.gcsConfig.projectId
if project_id:
return (
f"{connection.scheme.value}://{connection.credentials.gcsConfig.projectId}"
)
return f"{connection.scheme.value}://" return f"{connection.scheme.value}://"

View File

@ -126,6 +126,50 @@ class OMetaServiceTest(TestCase):
# Clean # Clean
self.metadata.delete(entity=DatabaseService, entity_id=service.id) self.metadata.delete(entity=DatabaseService, entity_id=service.id)
def test_create_database_service_bigquery(self):
"""
Create a db service from WorkflowSource
"""
data = {
"type": "bigquery",
"serviceName": "local_bigquery",
"serviceConnection": {
"config": {
"type": "BigQuery",
"enablePolicyTagImport": True,
"credentials": {
"gcsConfig": {
"type": "service_account",
"projectId": "projectID",
"privateKeyId": "privateKeyId",
"privateKey": "privateKey",
"clientEmail": "clientEmail",
"clientId": "clientId",
"authUri": "https://accounts.google.com/o/oauth2/auth",
"tokenUri": "https://oauth2.googleapis.com/token",
"authProviderX509CertUrl": "https://www.googleapis.com/oauth2/v1/certs",
"clientX509CertUrl": "https://cert.url",
}
},
}
},
"sourceConfig": {"config": {"enableDataProfiler": False}},
}
workflow_source = WorkflowSource(**data)
# Create service
service: DatabaseService = self.metadata.get_service_or_create(
entity=DatabaseService, config=workflow_source
)
assert service
assert service.serviceType == DatabaseServiceType.BigQuery
# Check get
assert service == self.metadata.get_service_or_create(
entity=DatabaseService, config=workflow_source
)
def test_create_dashboard_service_looker(self): def test_create_dashboard_service_looker(self):
""" """
Create a db service from WorkflowSource Create a db service from WorkflowSource

View File

@ -31,20 +31,19 @@ CONFIG = """
"serviceConnection": { "serviceConnection": {
"config": { "config": {
"type": "BigQuery", "type": "BigQuery",
"projectID": "project_id",
"enablePolicyTagImport": true, "enablePolicyTagImport": true,
"connectionOptions": {
"credentials": { "credentials": {
"gcsConfig": {
"type": "service_account", "type": "service_account",
"project_id": "project_id", "projectId": "projectID",
"private_key_id": "private_key_id", "privateKeyId": "privateKeyId",
"private_key": "private_key", "privateKey": "privateKey",
"client_email": "gcpuser@project_id.iam.gserviceaccount.com", "clientEmail": "clientEmail",
"client_id": "client_id", "clientId": "clientId",
"auth_uri": "https://accounts.google.com/o/oauth2/auth", "authUri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token", "tokenUri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "authProviderX509CertUrl": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "" "clientX509CertUrl": "https://cert.url"
} }
} }
} }

View File

@ -172,20 +172,19 @@ def test_bigquery():
"serviceConnection": { "serviceConnection": {
"config": { "config": {
"type": "BigQuery", "type": "BigQuery",
"projectID": "project_id",
"enablePolicyTagImport": True, "enablePolicyTagImport": True,
"connectionOptions": {
"credentials": { "credentials": {
"gcsConfig": {
"type": "service_account", "type": "service_account",
"project_id": "project_id", "projectId": "projectID",
"private_key_id": "private_key_id", "privateKeyId": "privateKeyId",
"private_key": "private_key", "privateKey": "privateKey",
"client_email": "gcpuser@project_id.iam.gserviceaccount.com", "clientEmail": "clientEmail",
"client_id": "client_id", "clientId": "clientId",
"auth_uri": "https://accounts.google.com/o/oauth2/auth", "authUri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token", "tokenUri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "authProviderX509CertUrl": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "", "clientX509CertUrl": "https://cert.url",
} }
}, },
} }

View File

@ -173,7 +173,9 @@ class REST_API(AppBuilderBaseView):
try: try:
service_connection_model = ServiceConnectionModel(**json_request) service_connection_model = ServiceConnectionModel(**json_request)
response = test_source_connection(service_connection_model) response = test_source_connection(
service_connection_model.serviceConnection.__root__.config
)
return response return response

View File

@ -15,9 +15,6 @@ from a WorkflowSource
from flask import Response from flask import Response
from openmetadata.api.response import ApiResponse from openmetadata.api.response import ApiResponse
from metadata.generated.schema.entity.services.connections.serviceConnection import (
ServiceConnectionModel,
)
from metadata.utils.engines import ( from metadata.utils.engines import (
SourceConnectionException, SourceConnectionException,
get_engine, get_engine,
@ -25,15 +22,13 @@ from metadata.utils.engines import (
) )
def test_source_connection( def test_source_connection(connection) -> Response:
service_connection_model: ServiceConnectionModel,
) -> Response:
""" """
Create the engine and test the connection Create the engine and test the connection
:param workflow_source: Source to test :param workflow_source: Source to test
:return: None or exception :return: None or exception
""" """
engine = get_engine(service_connection_model.serviceConnection) engine = get_engine(connection)
try: try:
test_connection(engine) test_connection(engine)