fivetran-connector-sdk 1.4.5__tar.gz → 1.4.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/PKG-INFO +1 -1
- fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/__init__.py +450 -0
- fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/connector_helper.py +928 -0
- fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/constants.py +70 -0
- fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/helpers.py +318 -0
- fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/logger.py +91 -0
- fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/operations.py +278 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/PKG-INFO +1 -1
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/SOURCES.txt +5 -0
- fivetran_connector_sdk-1.4.5/src/fivetran_connector_sdk/__init__.py +0 -2024
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/README.md +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/pyproject.toml +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/setup.cfg +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/__init__.py +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/common_pb2.py +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/common_pb2.pyi +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/common_pb2_grpc.py +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/connector_sdk_pb2.py +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/connector_sdk_pb2.pyi +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/connector_sdk_pb2_grpc.py +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/dependency_links.txt +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/entry_points.txt +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/requires.txt +0 -0
- {fivetran_connector_sdk-1.4.5 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fivetran_connector_sdk
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.6
|
4
4
|
Summary: Build custom connectors on Fivetran platform
|
5
5
|
Author-email: Fivetran <developers@fivetran.com>
|
6
6
|
Project-URL: Homepage, https://fivetran.com/docs/connectors/connector-sdk
|
@@ -0,0 +1,450 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import grpc
|
4
|
+
import json
|
5
|
+
import shutil
|
6
|
+
import argparse
|
7
|
+
import traceback
|
8
|
+
import requests as rq
|
9
|
+
from http import HTTPStatus
|
10
|
+
from zipfile import ZipFile
|
11
|
+
from concurrent import futures
|
12
|
+
|
13
|
+
from fivetran_connector_sdk.protos import common_pb2
|
14
|
+
from fivetran_connector_sdk.protos import connector_sdk_pb2
|
15
|
+
from fivetran_connector_sdk.protos import connector_sdk_pb2_grpc
|
16
|
+
|
17
|
+
from fivetran_connector_sdk.logger import Logging
|
18
|
+
from fivetran_connector_sdk.operations import Operations
|
19
|
+
from fivetran_connector_sdk import constants
|
20
|
+
from fivetran_connector_sdk.constants import (
|
21
|
+
TESTER_VER, VERSION_FILENAME, UTF_8,
|
22
|
+
VALID_COMMANDS, DEFAULT_PYTHON_VERSION, SUPPORTED_PYTHON_VERSIONS, FIVETRAN_HD_AGENT_ID, TABLES
|
23
|
+
)
|
24
|
+
from fivetran_connector_sdk.helpers import (
|
25
|
+
print_library_log, reset_local_file_directory, find_connector_object, validate_and_load_configuration,
|
26
|
+
validate_and_load_state, get_input_from_cli, suggest_correct_command,
|
27
|
+
)
|
28
|
+
from fivetran_connector_sdk.connector_helper import (
|
29
|
+
validate_requirements_file, upload_project,
|
30
|
+
update_connection, are_setup_tests_failing,
|
31
|
+
validate_deploy_parameters, get_connection_id,
|
32
|
+
handle_failing_tests_message_and_exit, delete_file_if_exists,
|
33
|
+
create_connection, get_os_arch_suffix, get_group_info,
|
34
|
+
java_exe_helper, run_tester, process_tables,
|
35
|
+
update_base_url_if_required, exit_check,
|
36
|
+
get_available_port, tester_root_dir_helper,
|
37
|
+
check_dict, check_newer_version, cleanup_uploaded_project,
|
38
|
+
)
|
39
|
+
|
40
|
+
# Version format: <major_version>.<minor_version>.<patch_version>
|
41
|
+
# (where Major Version = 1 for GA, Minor Version is incremental MM from Jan 25 onwards, Patch Version is incremental within a month)
|
42
|
+
__version__ = "1.4.6"
|
43
|
+
TESTER_VERSION = TESTER_VER
|
44
|
+
|
45
|
+
__all__ = [cls.__name__ for cls in [Logging, Operations]]
|
46
|
+
|
47
|
+
class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
48
|
+
def __init__(self, update, schema=None):
|
49
|
+
"""Initializes the Connector instance.
|
50
|
+
Args:
|
51
|
+
update: The update method.
|
52
|
+
schema: The schema method.
|
53
|
+
"""
|
54
|
+
|
55
|
+
self.schema_method = schema
|
56
|
+
self.update_method = update
|
57
|
+
|
58
|
+
self.configuration = None
|
59
|
+
self.state = None
|
60
|
+
|
61
|
+
update_base_url_if_required()
|
62
|
+
|
63
|
+
# Call this method to deploy the connector to Fivetran platform
|
64
|
+
def deploy(self, args: dict, deploy_key: str, group: str, connection: str, hd_agent_id: str, configuration: dict = None):
|
65
|
+
"""Deploys the connector to the Fivetran platform.
|
66
|
+
|
67
|
+
Args:
|
68
|
+
args (dict): The command arguments.
|
69
|
+
deploy_key (str): The deployment key.
|
70
|
+
group (str): The group name.
|
71
|
+
connection (str): The connection name.
|
72
|
+
hd_agent_id (str): The hybrid deployment agent ID within the Fivetran system.
|
73
|
+
configuration (dict): The configuration dictionary.
|
74
|
+
"""
|
75
|
+
constants.EXECUTED_VIA_CLI = True
|
76
|
+
|
77
|
+
print_library_log("We support only `.py` files and a `requirements.txt` file as part of the code upload. *No other code files* are supported or uploaded during the deployment process. Ensure that your code is structured accordingly and all dependencies are listed in `requirements.txt`")
|
78
|
+
|
79
|
+
validate_deploy_parameters(connection, deploy_key)
|
80
|
+
|
81
|
+
check_dict(configuration, True)
|
82
|
+
|
83
|
+
secrets_list = []
|
84
|
+
if configuration:
|
85
|
+
for k, v in configuration.items():
|
86
|
+
secrets_list.append({"key": k, "value": v})
|
87
|
+
|
88
|
+
connection_config = {
|
89
|
+
"schema": connection,
|
90
|
+
"secrets_list": secrets_list,
|
91
|
+
"sync_method": "DIRECT"
|
92
|
+
}
|
93
|
+
|
94
|
+
if args.python_version:
|
95
|
+
connection_config["python_version"] = args.python_version
|
96
|
+
|
97
|
+
validate_requirements_file(args.project_path, True, __version__, args.force)
|
98
|
+
|
99
|
+
group_id, group_name = get_group_info(group, deploy_key)
|
100
|
+
connection_id, service = get_connection_id(connection, group, group_id, deploy_key) or (None, None)
|
101
|
+
|
102
|
+
if connection_id:
|
103
|
+
if service != 'connector_sdk':
|
104
|
+
print_library_log(
|
105
|
+
f"The connection '{connection}' already exists and does not use the 'Connector SDK' service. You cannot update this connection.", Logging.Level.SEVERE)
|
106
|
+
os._exit(1)
|
107
|
+
else:
|
108
|
+
if args.force:
|
109
|
+
confirm = "y"
|
110
|
+
if args.configuration:
|
111
|
+
confirm_config = "y"
|
112
|
+
else:
|
113
|
+
confirm = input(
|
114
|
+
f"The connection '{connection}' already exists in the destination '{group}'. Updating it will overwrite the existing code. Do you want to proceed with the update? (Y/N): ")
|
115
|
+
if confirm.lower() == "y" and args.configuration:
|
116
|
+
confirm_config = input(f"Your deploy will overwrite the configuration using the values provided in '{args.configuration}': key-value pairs not present in the new configuration will be removed; existing keys' values set in the cofiguration file or in the dashboard will be overwritten with new (empty or non-empty) values; new key-value pairs will be added. Do you want to proceed with the update? (Y/N): ")
|
117
|
+
if confirm.lower() == "y" and (not connection_config["secrets_list"] or (confirm_config.lower() == "y")):
|
118
|
+
print_library_log("Updating the connection...\n")
|
119
|
+
upload_project(
|
120
|
+
args.project_path, deploy_key, group_id, group_name, connection)
|
121
|
+
response = update_connection(
|
122
|
+
args, connection_id, connection, group_name, connection_config, deploy_key, hd_agent_id)
|
123
|
+
print("✓")
|
124
|
+
print_library_log(f"Python version {response.json()['data']['config']['python_version']} to be used at runtime.",
|
125
|
+
Logging.Level.INFO)
|
126
|
+
print_library_log(f"Connection ID: {connection_id}")
|
127
|
+
print_library_log(
|
128
|
+
f"Visit the Fivetran dashboard to manage the connection: https://fivetran.com/dashboard/connectors/{connection_id}/status")
|
129
|
+
else:
|
130
|
+
print_library_log("Update canceled. The process is now terminating.")
|
131
|
+
os._exit(1)
|
132
|
+
else:
|
133
|
+
upload_project(args.project_path, deploy_key,
|
134
|
+
group_id, group_name, connection)
|
135
|
+
response = create_connection(
|
136
|
+
deploy_key, group_id, connection_config, hd_agent_id)
|
137
|
+
if response.ok and response.status_code == HTTPStatus.CREATED:
|
138
|
+
if are_setup_tests_failing(response):
|
139
|
+
handle_failing_tests_message_and_exit(response, "The connection was created, but setup tests failed!")
|
140
|
+
else:
|
141
|
+
print_library_log(
|
142
|
+
f"The connection '{connection}' has been created successfully.\n")
|
143
|
+
connection_id = response.json()['data']['id']
|
144
|
+
print_library_log(f"Python version {response.json()['data']['config']['python_version']} to be used at runtime.",
|
145
|
+
Logging.Level.INFO)
|
146
|
+
print_library_log(f"Connection ID: {connection_id}")
|
147
|
+
print_library_log(
|
148
|
+
f"Visit the Fivetran dashboard to start the initial sync: https://fivetran.com/dashboard/connectors/{connection_id}/status")
|
149
|
+
else:
|
150
|
+
print_library_log(
|
151
|
+
f"Unable to create a new connection, failed with error: {response.json()['message']}", Logging.Level.SEVERE)
|
152
|
+
cleanup_uploaded_project(deploy_key,group_id, connection)
|
153
|
+
print_library_log("Please try again with the deploy command after resolving the issue!")
|
154
|
+
os._exit(1)
|
155
|
+
|
156
|
+
# Call this method to run the connector in production
|
157
|
+
def run(self,
|
158
|
+
port: int = 50051,
|
159
|
+
configuration: dict = None,
|
160
|
+
state: dict = None,
|
161
|
+
log_level: Logging.Level = Logging.Level.INFO) -> grpc.Server:
|
162
|
+
"""Runs the connector server.
|
163
|
+
|
164
|
+
Args:
|
165
|
+
port (int): The port number to listen for incoming requests.
|
166
|
+
configuration (dict): The configuration dictionary.
|
167
|
+
state (dict): The state dictionary.
|
168
|
+
log_level (Logging.Level): The logging level.
|
169
|
+
|
170
|
+
Returns:
|
171
|
+
grpc.Server: The gRPC server instance.
|
172
|
+
"""
|
173
|
+
self.configuration = check_dict(configuration, True)
|
174
|
+
self.state = check_dict(state)
|
175
|
+
Logging.LOG_LEVEL = log_level
|
176
|
+
|
177
|
+
if not constants.DEBUGGING:
|
178
|
+
print_library_log(f"Running on fivetran_connector_sdk: {__version__}")
|
179
|
+
|
180
|
+
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
|
181
|
+
connector_sdk_pb2_grpc.add_ConnectorServicer_to_server(self, server)
|
182
|
+
server.add_insecure_port("[::]:" + str(port))
|
183
|
+
server.start()
|
184
|
+
if constants.DEBUGGING:
|
185
|
+
return server
|
186
|
+
server.wait_for_termination()
|
187
|
+
|
188
|
+
# This method starts both the server and the local testing environment
|
189
|
+
def debug(self,
|
190
|
+
project_path: str = None,
|
191
|
+
configuration: dict = None,
|
192
|
+
state: dict = None,
|
193
|
+
log_level: Logging.Level = Logging.Level.FINE):
|
194
|
+
"""Tests the connector code by running it with the connector tester.\n
|
195
|
+
state.json docs: https://fivetran.com/docs/connectors/connector-sdk/detailed-guide#workingwithstatejsonfile\n
|
196
|
+
configuration.json docs: https://fivetran.com/docs/connectors/connector-sdk/detailed-guide#workingwithconfigurationjsonfile
|
197
|
+
|
198
|
+
Args:
|
199
|
+
project_path (str): The path to the project.
|
200
|
+
configuration (dict): The configuration dictionary, same as configuration.json if present.
|
201
|
+
state (dict): The state dictionary, same as state.json if present.
|
202
|
+
log_level (Logging.Level): The logging level.
|
203
|
+
"""
|
204
|
+
constants.DEBUGGING = True
|
205
|
+
|
206
|
+
check_newer_version(__version__)
|
207
|
+
|
208
|
+
Logging.LOG_LEVEL = log_level
|
209
|
+
os_arch_suffix = get_os_arch_suffix()
|
210
|
+
tester_root_dir = tester_root_dir_helper()
|
211
|
+
java_exe = java_exe_helper(tester_root_dir, os_arch_suffix)
|
212
|
+
install_tester = False
|
213
|
+
version_file = os.path.join(tester_root_dir, VERSION_FILENAME)
|
214
|
+
if os.path.isfile(version_file):
|
215
|
+
# Check version number & update if different
|
216
|
+
with open(version_file, 'r', encoding=UTF_8) as fi:
|
217
|
+
current_version = fi.readline()
|
218
|
+
|
219
|
+
if current_version != TESTER_VERSION:
|
220
|
+
shutil.rmtree(tester_root_dir)
|
221
|
+
install_tester = True
|
222
|
+
else:
|
223
|
+
install_tester = True
|
224
|
+
|
225
|
+
if install_tester:
|
226
|
+
os.makedirs(tester_root_dir, exist_ok=True)
|
227
|
+
download_filename = f"sdk-connector-tester-{os_arch_suffix}-{TESTER_VERSION}.zip"
|
228
|
+
download_filepath = os.path.join(tester_root_dir, download_filename)
|
229
|
+
try:
|
230
|
+
print_library_log(f"Downloading connector tester version: {TESTER_VERSION} ")
|
231
|
+
download_url = f"https://github.com/fivetran/fivetran_sdk_tools/releases/download/{TESTER_VERSION}/{download_filename}"
|
232
|
+
r = rq.get(download_url)
|
233
|
+
if r.ok:
|
234
|
+
with open(download_filepath, 'wb') as fo:
|
235
|
+
fo.write(r.content)
|
236
|
+
else:
|
237
|
+
raise RuntimeError(
|
238
|
+
f"\nSEVERE: Failed to download the connector tester. Please check your access permissions or "
|
239
|
+
f"try again later ( status code: {r.status_code}), url: {download_url}")
|
240
|
+
except RuntimeError:
|
241
|
+
raise RuntimeError(
|
242
|
+
f"SEVERE: Failed to download the connector tester. Error details: {traceback.format_exc()}")
|
243
|
+
|
244
|
+
try:
|
245
|
+
# unzip it
|
246
|
+
with ZipFile(download_filepath, 'r') as z_object:
|
247
|
+
z_object.extractall(path=tester_root_dir)
|
248
|
+
# delete zip file
|
249
|
+
delete_file_if_exists(download_filepath)
|
250
|
+
# make java binary executable
|
251
|
+
import stat
|
252
|
+
st = os.stat(java_exe)
|
253
|
+
os.chmod(java_exe, st.st_mode | stat.S_IEXEC)
|
254
|
+
print("✓")
|
255
|
+
except:
|
256
|
+
shutil.rmtree(tester_root_dir)
|
257
|
+
raise RuntimeError(f"\nSEVERE: Failed to install the connector tester. Error details: {traceback.format_exc()}")
|
258
|
+
|
259
|
+
project_path = os.getcwd() if project_path is None else project_path
|
260
|
+
validate_requirements_file(project_path, False, __version__)
|
261
|
+
print_library_log(f"Debugging connector at: {project_path}")
|
262
|
+
available_port = get_available_port()
|
263
|
+
exit_check(project_path)
|
264
|
+
|
265
|
+
if available_port is None:
|
266
|
+
raise RuntimeError("SEVERE: Unable to allocate a port in the range 50051-50061. "
|
267
|
+
"Please ensure a port is available and try again")
|
268
|
+
|
269
|
+
server = self.run(available_port, configuration, state, log_level=log_level)
|
270
|
+
|
271
|
+
# Uncomment this to run the tester manually
|
272
|
+
# server.wait_for_termination()
|
273
|
+
|
274
|
+
try:
|
275
|
+
print_library_log("Running connector tester...")
|
276
|
+
for log_msg in run_tester(java_exe, tester_root_dir, project_path, available_port, json.dumps(self.state), json.dumps(self.configuration)):
|
277
|
+
print(log_msg, end="")
|
278
|
+
except:
|
279
|
+
print(traceback.format_exc())
|
280
|
+
finally:
|
281
|
+
server.stop(grace=2.0)
|
282
|
+
|
283
|
+
# -- Methods below override ConnectorServicer methods
|
284
|
+
def ConfigurationForm(self, request, context):
|
285
|
+
"""Overrides the ConfigurationForm method from ConnectorServicer.
|
286
|
+
|
287
|
+
Args:
|
288
|
+
request: The gRPC request.
|
289
|
+
context: The gRPC context.
|
290
|
+
|
291
|
+
Returns:
|
292
|
+
common_pb2.ConfigurationFormResponse: An empty configuration form response.
|
293
|
+
"""
|
294
|
+
if not self.configuration:
|
295
|
+
self.configuration = {}
|
296
|
+
|
297
|
+
# Not going to use the tester's configuration file
|
298
|
+
return common_pb2.ConfigurationFormResponse()
|
299
|
+
|
300
|
+
def Test(self, request, context):
|
301
|
+
"""Overrides the Test method from ConnectorServicer.
|
302
|
+
|
303
|
+
Args:
|
304
|
+
request: The gRPC request.
|
305
|
+
context: The gRPC context.
|
306
|
+
|
307
|
+
Returns:
|
308
|
+
None: As this method is not implemented.
|
309
|
+
"""
|
310
|
+
return None
|
311
|
+
|
312
|
+
def Schema(self, request, context):
|
313
|
+
"""Overrides the Schema method from ConnectorServicer.
|
314
|
+
|
315
|
+
Args:
|
316
|
+
request: The gRPC request.
|
317
|
+
context: The gRPC context.
|
318
|
+
|
319
|
+
Returns:
|
320
|
+
connector_sdk_pb2.SchemaResponse: The schema response.
|
321
|
+
"""
|
322
|
+
|
323
|
+
table_list = {}
|
324
|
+
|
325
|
+
if not self.schema_method:
|
326
|
+
return connector_sdk_pb2.SchemaResponse(schema_response_not_supported=True)
|
327
|
+
else:
|
328
|
+
try:
|
329
|
+
configuration = self.configuration if self.configuration else request.configuration
|
330
|
+
print_library_log("Initiating the 'schema' method call...", Logging.Level.INFO)
|
331
|
+
response = self.schema_method(configuration)
|
332
|
+
process_tables(response, table_list)
|
333
|
+
return connector_sdk_pb2.SchemaResponse(without_schema=common_pb2.TableList(tables=TABLES.values()))
|
334
|
+
|
335
|
+
except Exception as e:
|
336
|
+
tb = traceback.format_exc()
|
337
|
+
error_message = f"Error: {str(e)}\n{tb}"
|
338
|
+
print_library_log(error_message, Logging.Level.SEVERE)
|
339
|
+
raise RuntimeError(error_message) from e
|
340
|
+
|
341
|
+
def Update(self, request, context):
|
342
|
+
"""Overrides the Update method from ConnectorServicer.
|
343
|
+
|
344
|
+
Args:
|
345
|
+
request: The gRPC request.
|
346
|
+
context: The gRPC context.
|
347
|
+
|
348
|
+
Yields:
|
349
|
+
connector_sdk_pb2.UpdateResponse: The update response.
|
350
|
+
"""
|
351
|
+
configuration = self.configuration if self.configuration else request.configuration
|
352
|
+
state = self.state if self.state else json.loads(request.state_json)
|
353
|
+
|
354
|
+
try:
|
355
|
+
print_library_log("Initiating the 'update' method call...", Logging.Level.INFO)
|
356
|
+
for resp in self.update_method(configuration=configuration, state=state):
|
357
|
+
if isinstance(resp, list):
|
358
|
+
for r in resp:
|
359
|
+
yield r
|
360
|
+
else:
|
361
|
+
yield resp
|
362
|
+
|
363
|
+
except TypeError as e:
|
364
|
+
if str(e) != "'NoneType' object is not iterable":
|
365
|
+
raise e
|
366
|
+
|
367
|
+
except Exception as e:
|
368
|
+
tb = traceback.format_exc()
|
369
|
+
error_message = f"Error: {str(e)}\n{tb}"
|
370
|
+
print_library_log(error_message, Logging.Level.SEVERE)
|
371
|
+
raise RuntimeError(error_message) from e
|
372
|
+
|
373
|
+
|
374
|
+
def main():
|
375
|
+
"""The main entry point for the script.
|
376
|
+
Parses command line arguments and passes them to connector object methods
|
377
|
+
"""
|
378
|
+
|
379
|
+
constants.EXECUTED_VIA_CLI = True
|
380
|
+
|
381
|
+
parser = argparse.ArgumentParser(allow_abbrev=False, add_help=True)
|
382
|
+
parser._option_string_actions["-h"].help = "Show this help message and exit"
|
383
|
+
|
384
|
+
# Positional
|
385
|
+
parser.add_argument("command", help="|".join(VALID_COMMANDS))
|
386
|
+
parser.add_argument("project_path", nargs='?', default=os.getcwd(), help="Path to connector project directory")
|
387
|
+
|
388
|
+
# Optional (Not all of these are valid with every mutually exclusive option below)
|
389
|
+
parser.add_argument("--state", type=str, default=None, help="Provide state as JSON string or file")
|
390
|
+
parser.add_argument("--configuration", type=str, default=None, help="Provide secrets as JSON file")
|
391
|
+
parser.add_argument("--api-key", type=str, default=None, help="Provide your base64-encoded API key for deployment")
|
392
|
+
parser.add_argument("--destination", type=str, default=None, help="Destination name (aka 'group name')")
|
393
|
+
parser.add_argument("--connection", type=str, default=None, help="Connection name (aka 'destination schema')")
|
394
|
+
parser.add_argument("-f", "--force", action="store_true", help="Force update an existing connection")
|
395
|
+
parser.add_argument("--python-version", "--python", type=str, help=f"Supported Python versions you can use: {SUPPORTED_PYTHON_VERSIONS}. Defaults to {DEFAULT_PYTHON_VERSION}")
|
396
|
+
parser.add_argument("--hybrid-deployment-agent-id", type=str, help="The Hybrid Deployment agent within the Fivetran system. If nothing is passed, the default agent of the destination is used.")
|
397
|
+
|
398
|
+
args = parser.parse_args()
|
399
|
+
|
400
|
+
if args.command.lower() == "version":
|
401
|
+
print_library_log("fivetran_connector_sdk " + __version__)
|
402
|
+
return
|
403
|
+
elif args.command.lower() == "reset":
|
404
|
+
reset_local_file_directory(args)
|
405
|
+
return
|
406
|
+
|
407
|
+
connector_object = find_connector_object(args.project_path)
|
408
|
+
|
409
|
+
if not connector_object:
|
410
|
+
sys.exit(1)
|
411
|
+
|
412
|
+
# Process optional args
|
413
|
+
ft_group = args.destination if args.destination else None
|
414
|
+
ft_connection = args.connection if args.connection else None
|
415
|
+
ft_deploy_key = args.api_key if args.api_key else None
|
416
|
+
hd_agent_id = args.hybrid_deployment_agent_id if args.hybrid_deployment_agent_id else os.getenv(FIVETRAN_HD_AGENT_ID, None)
|
417
|
+
configuration = args.configuration if args.configuration else None
|
418
|
+
state = args.state if args.state else os.getenv('FIVETRAN_STATE', None)
|
419
|
+
|
420
|
+
configuration = validate_and_load_configuration(args, configuration)
|
421
|
+
state = validate_and_load_state(args, state)
|
422
|
+
|
423
|
+
FIVETRAN_API_KEY = os.getenv('FIVETRAN_API_KEY', None)
|
424
|
+
FIVETRAN_DESTINATION_NAME = os.getenv('FIVETRAN_DESTINATION_NAME', None)
|
425
|
+
FIVETRAN_CONNECTION_NAME = os.getenv('FIVETRAN_CONNECTION_NAME', None)
|
426
|
+
|
427
|
+
if args.command.lower() == "deploy":
|
428
|
+
if args.state:
|
429
|
+
print_library_log("'state' parameter is not used for 'deploy' command", Logging.Level.WARNING)
|
430
|
+
|
431
|
+
if not ft_deploy_key:
|
432
|
+
ft_deploy_key = get_input_from_cli("Please provide the API Key", FIVETRAN_API_KEY)
|
433
|
+
|
434
|
+
if not ft_group:
|
435
|
+
ft_group = get_input_from_cli("Please provide the destination", FIVETRAN_DESTINATION_NAME)
|
436
|
+
|
437
|
+
if not ft_connection:
|
438
|
+
ft_connection = get_input_from_cli("Please provide the connection name",FIVETRAN_CONNECTION_NAME)
|
439
|
+
|
440
|
+
connector_object.deploy(args, ft_deploy_key, ft_group, ft_connection, hd_agent_id, configuration)
|
441
|
+
|
442
|
+
elif args.command.lower() == "debug":
|
443
|
+
connector_object.debug(args.project_path, configuration, state)
|
444
|
+
else:
|
445
|
+
if not suggest_correct_command(args.command):
|
446
|
+
raise NotImplementedError(f"Invalid command: {args.command}, see `fivetran --help`")
|
447
|
+
|
448
|
+
|
449
|
+
if __name__ == "__main__":
|
450
|
+
main()
|