3
3
import warnings
4
4
from typing import Dict , Optional
5
5
6
- import pydantic
7
6
from pydantic import Field , root_validator
8
7
from typing_extensions import Literal
9
8
19
18
from datahub .ingestion .source .bigquery_v2 .bigquery_config import (
20
19
BigQueryConnectionConfig ,
21
20
)
21
+ from datahub .ingestion .source .fivetran .fivetran_constants import FivetranMode
22
22
from datahub .ingestion .source .snowflake .snowflake_connection import (
23
23
SnowflakeConnectionConfig ,
24
24
)
@@ -85,15 +85,15 @@ class BigQueryDestinationConfig(BigQueryConnectionConfig):
85
85
86
86
87
87
class FivetranLogConfig (ConfigModel ):
88
- destination_platform : Literal ["snowflake" , "bigquery" ] = pydantic . Field (
88
+ destination_platform : Literal ["snowflake" , "bigquery" ] = Field (
89
89
default = "snowflake" ,
90
90
description = "The destination platform where fivetran connector log tables are dumped." ,
91
91
)
92
- snowflake_destination_config : Optional [SnowflakeDestinationConfig ] = pydantic . Field (
92
+ snowflake_destination_config : Optional [SnowflakeDestinationConfig ] = Field (
93
93
default = None ,
94
94
description = "If destination platform is 'snowflake', provide snowflake configuration." ,
95
95
)
96
- bigquery_destination_config : Optional [BigQueryDestinationConfig ] = pydantic . Field (
96
+ bigquery_destination_config : Optional [BigQueryDestinationConfig ] = Field (
97
97
default = None ,
98
98
description = "If destination platform is 'bigquery', provide bigquery configuration." ,
99
99
)
@@ -121,6 +121,19 @@ def validate_destination_platfrom_and_config(cls, values: Dict) -> Dict:
121
121
return values
122
122
123
123
124
+ class FivetranAPIConfig (ConfigModel ):
125
+ """Configuration for the Fivetran API client."""
126
+
127
+ api_key : str = Field (description = "Fivetran API key" )
128
+ api_secret : str = Field (description = "Fivetran API secret" )
129
+ base_url : str = Field (
130
+ default = "https://api.fivetran.com" , description = "Fivetran API base URL"
131
+ )
132
+ request_timeout_sec : int = Field (
133
+ default = 30 , description = "Request timeout in seconds"
134
+ )
135
+
136
+
124
137
@dataclasses .dataclass
125
138
class MetadataExtractionPerfReport (Report ):
126
139
connectors_metadata_extraction_sec : PerfTimer = dataclasses .field (
@@ -150,33 +163,47 @@ def report_connectors_dropped(self, connector: str) -> None:
150
163
151
164
152
165
class PlatformDetail (ConfigModel ):
153
- platform : Optional [str ] = pydantic . Field (
166
+ platform : Optional [str ] = Field (
154
167
default = None ,
155
168
description = "Override the platform type detection." ,
156
169
)
157
- platform_instance : Optional [str ] = pydantic . Field (
170
+ platform_instance : Optional [str ] = Field (
158
171
default = None ,
159
172
description = "The instance of the platform that all assets produced by this recipe belong to" ,
160
173
)
161
- env : str = pydantic . Field (
174
+ env : str = Field (
162
175
default = DEFAULT_ENV ,
163
176
description = "The environment that all assets produced by DataHub platform ingestion source belong to" ,
164
177
)
165
- database : Optional [str ] = pydantic . Field (
178
+ database : Optional [str ] = Field (
166
179
default = None ,
167
180
description = "The database that all assets produced by this connector belong to. "
168
181
"For destinations, this defaults to the fivetran log config's database." ,
169
182
)
170
- include_schema_in_urn : bool = pydantic . Field (
183
+ include_schema_in_urn : bool = Field (
171
184
default = True ,
172
185
description = "Include schema in the dataset URN. In some cases, the schema is not relevant to the dataset URN and Fivetran sets it to the source and destination table names in the connector." ,
173
186
)
174
187
175
188
176
189
class FivetranSourceConfig (StatefulIngestionConfigBase , DatasetSourceConfigMixin ):
177
- fivetran_log_config : FivetranLogConfig = pydantic .Field (
178
- description = "Fivetran log connector destination server configurations." ,
190
+ fivetran_mode : FivetranMode = Field (
191
+ default = FivetranMode .AUTO ,
192
+ description = "Mode of operation: 'enterprise' for log tables access, 'standard' for REST API, or 'auto' to detect." ,
193
+ )
194
+
195
+ # Enterprise version configuration
196
+ fivetran_log_config : Optional [FivetranLogConfig ] = Field (
197
+ default = None ,
198
+ description = "Fivetran log connector destination server configurations for enterprise version." ,
199
+ )
200
+
201
+ # Standard version configuration
202
+ api_config : Optional [FivetranAPIConfig ] = Field (
203
+ default = None ,
204
+ description = "Fivetran REST API configuration for standard version." ,
179
205
)
206
+
180
207
connector_patterns : AllowDenyPattern = Field (
181
208
default = AllowDenyPattern .allow_all (),
182
209
description = "Filtering regex patterns for connector names." ,
@@ -193,22 +220,46 @@ class FivetranSourceConfig(StatefulIngestionConfigBase, DatasetSourceConfigMixin
193
220
)
194
221
195
222
# Configuration for stateful ingestion
196
- stateful_ingestion : Optional [StatefulStaleMetadataRemovalConfig ] = pydantic . Field (
197
- default = None , description = "Airbyte Stateful Ingestion Config."
223
+ stateful_ingestion : Optional [StatefulStaleMetadataRemovalConfig ] = Field (
224
+ default = None , description = "Fivetran Stateful Ingestion Config."
198
225
)
199
226
200
227
# Fivetran connector all sources to platform instance mapping
201
- sources_to_platform_instance : Dict [str , PlatformDetail ] = pydantic . Field (
228
+ sources_to_platform_instance : Dict [str , PlatformDetail ] = Field (
202
229
default = {},
203
230
description = "A mapping from connector id to its platform/instance/env/database details." ,
204
231
)
205
232
# Fivetran destination to platform instance mapping
206
- destination_to_platform_instance : Dict [str , PlatformDetail ] = pydantic . Field (
233
+ destination_to_platform_instance : Dict [str , PlatformDetail ] = Field (
207
234
default = {},
208
235
description = "A mapping of destination id to its platform/instance/env details." ,
209
236
)
210
237
211
- @pydantic .root_validator (pre = True )
238
+ @root_validator
239
+ def validate_config_based_on_mode (cls , values : Dict ) -> Dict :
240
+ """Validate configuration based on the selected mode."""
241
+ mode = values .get ("fivetran_mode" , FivetranMode .AUTO )
242
+ log_config = values .get ("fivetran_log_config" )
243
+ api_config = values .get ("api_config" )
244
+
245
+ if mode == FivetranMode .ENTERPRISE :
246
+ if not log_config :
247
+ raise ValueError (
248
+ "Enterprise mode requires 'fivetran_log_config' to be specified."
249
+ )
250
+ elif mode == FivetranMode .STANDARD :
251
+ if not api_config :
252
+ raise ValueError ("Standard mode requires 'api_config' to be specified." )
253
+ elif mode == FivetranMode .AUTO :
254
+ # Auto-detect based on provided configs
255
+ if not log_config and not api_config :
256
+ raise ValueError (
257
+ "Either 'fivetran_log_config' (for enterprise) or 'api_config' (for standard) must be specified."
258
+ )
259
+
260
+ return values
261
+
262
+ @root_validator (pre = True )
212
263
def compat_sources_to_database (cls , values : Dict ) -> Dict :
213
264
if "sources_to_database" in values :
214
265
warnings .warn (
@@ -227,7 +278,7 @@ def compat_sources_to_database(cls, values: Dict) -> Dict:
227
278
228
279
return values
229
280
230
- history_sync_lookback_period : int = pydantic . Field (
281
+ history_sync_lookback_period : int = Field (
231
282
7 ,
232
283
description = "The number of days to look back when extracting connectors' sync history." ,
233
284
)
0 commit comments