fivetran-connector-sdk 1.4.4__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.
Files changed (24) hide show
  1. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/PKG-INFO +6 -5
  2. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/README.md +5 -4
  3. fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/__init__.py +450 -0
  4. fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/connector_helper.py +928 -0
  5. fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/constants.py +70 -0
  6. fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/helpers.py +318 -0
  7. fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/logger.py +91 -0
  8. fivetran_connector_sdk-1.4.6/src/fivetran_connector_sdk/operations.py +278 -0
  9. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/PKG-INFO +6 -5
  10. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/SOURCES.txt +5 -0
  11. fivetran_connector_sdk-1.4.4/src/fivetran_connector_sdk/__init__.py +0 -2009
  12. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/pyproject.toml +0 -0
  13. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/setup.cfg +0 -0
  14. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/__init__.py +0 -0
  15. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/common_pb2.py +0 -0
  16. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/common_pb2.pyi +0 -0
  17. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/common_pb2_grpc.py +0 -0
  18. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/connector_sdk_pb2.py +0 -0
  19. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/connector_sdk_pb2.pyi +0 -0
  20. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk/protos/connector_sdk_pb2_grpc.py +0 -0
  21. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/dependency_links.txt +0 -0
  22. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/entry_points.txt +0 -0
  23. {fivetran_connector_sdk-1.4.4 → fivetran_connector_sdk-1.4.6}/src/fivetran_connector_sdk.egg-info/requires.txt +0 -0
  24. {fivetran_connector_sdk-1.4.4 → 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.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
@@ -35,10 +35,11 @@ To learn more, see our [Connector SDK documentation](https://fivetran.com/docs/c
35
35
  pip install fivetran-connector-sdk
36
36
 
37
37
  ## **Requirements**
38
- - Python ≥3.9 and ≤3.12
39
- - Operating System:
40
- - Windows 10 or later
41
- - MacOS 13 (Ventura) or later
38
+ - Python version ≥3.9 and ≤3.12
39
+ - Operating system:
40
+ - Windows: 10 or later (64-bit only)
41
+ - macOS: 13 (Ventura) or later (Apple Silicon [arm64] or Intel [x86_64])
42
+ - Linux: Distributions such as Ubuntu 20.04 or later, Debian 10 or later, or Amazon Linux 2 or later (arm64 or x86_64)
42
43
 
43
44
  ## **Getting started**
44
45
  See [Quickstart guide](https://fivetran.com/docs/connectors/connector-sdk/quickstart-guide) to get started.
@@ -16,10 +16,11 @@ To learn more, see our [Connector SDK documentation](https://fivetran.com/docs/c
16
16
  pip install fivetran-connector-sdk
17
17
 
18
18
  ## **Requirements**
19
- - Python ≥3.9 and ≤3.12
20
- - Operating System:
21
- - Windows 10 or later
22
- - MacOS 13 (Ventura) or later
19
+ - Python version ≥3.9 and ≤3.12
20
+ - Operating system:
21
+ - Windows: 10 or later (64-bit only)
22
+ - macOS: 13 (Ventura) or later (Apple Silicon [arm64] or Intel [x86_64])
23
+ - Linux: Distributions such as Ubuntu 20.04 or later, Debian 10 or later, or Amazon Linux 2 or later (arm64 or x86_64)
23
24
 
24
25
  ## **Getting started**
25
26
  See [Quickstart guide](https://fivetran.com/docs/connectors/connector-sdk/quickstart-guide) to get started.
@@ -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()