tinybird 0.0.1.dev306__py3-none-any.whl → 1.0.5__py3-none-any.whl
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.
- tinybird/datafile/common.py +4 -1
- tinybird/feedback_manager.py +3 -0
- tinybird/service_datasources.py +57 -8
- tinybird/sql_template.py +1 -1
- tinybird/sql_template_fmt.py +14 -4
- tinybird/tb/__cli__.py +2 -2
- tinybird/tb/cli.py +1 -0
- tinybird/tb/client.py +104 -22
- tinybird/tb/modules/agent/tools/execute_query.py +1 -1
- tinybird/tb/modules/agent/tools/request_endpoint.py +1 -1
- tinybird/tb/modules/branch.py +150 -0
- tinybird/tb/modules/build.py +51 -10
- tinybird/tb/modules/build_common.py +4 -2
- tinybird/tb/modules/cli.py +32 -10
- tinybird/tb/modules/common.py +161 -134
- tinybird/tb/modules/connection.py +125 -194
- tinybird/tb/modules/connection_kafka.py +382 -0
- tinybird/tb/modules/copy.py +3 -1
- tinybird/tb/modules/create.py +11 -0
- tinybird/tb/modules/datafile/build.py +1 -1
- tinybird/tb/modules/datafile/format_pipe.py +44 -5
- tinybird/tb/modules/datafile/playground.py +1 -1
- tinybird/tb/modules/datasource.py +475 -324
- tinybird/tb/modules/deployment.py +2 -0
- tinybird/tb/modules/deployment_common.py +81 -43
- tinybird/tb/modules/deprecations.py +4 -4
- tinybird/tb/modules/dev_server.py +33 -12
- tinybird/tb/modules/info.py +50 -7
- tinybird/tb/modules/job_common.py +15 -0
- tinybird/tb/modules/local.py +91 -21
- tinybird/tb/modules/local_common.py +320 -13
- tinybird/tb/modules/local_logs.py +209 -0
- tinybird/tb/modules/login.py +3 -2
- tinybird/tb/modules/login_common.py +252 -9
- tinybird/tb/modules/open.py +10 -5
- tinybird/tb/modules/project.py +14 -5
- tinybird/tb/modules/shell.py +14 -6
- tinybird/tb/modules/sink.py +3 -1
- tinybird/tb/modules/telemetry.py +7 -3
- tinybird/tb_cli_modules/telemetry.py +1 -1
- {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/METADATA +29 -4
- {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/RECORD +45 -41
- {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/WHEEL +1 -1
- {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/entry_points.txt +0 -0
- {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/top_level.txt +0 -0
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
# - But please, **do not** interleave utility functions and command definitions.
|
|
5
5
|
|
|
6
6
|
import uuid
|
|
7
|
-
from typing import Any, Dict, List, Optional
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
8
|
|
|
9
9
|
import click
|
|
10
10
|
from click import Context
|
|
11
|
-
from confluent_kafka.admin import AdminClient
|
|
12
11
|
|
|
13
12
|
from tinybird.tb.client import TinyB
|
|
13
|
+
from tinybird.tb.modules.build_common import process as build_project
|
|
14
14
|
from tinybird.tb.modules.cli import cli
|
|
15
15
|
from tinybird.tb.modules.common import (
|
|
16
16
|
DataConnectorType,
|
|
@@ -18,21 +18,21 @@ from tinybird.tb.modules.common import (
|
|
|
18
18
|
echo_safe_humanfriendly_tables_format_smart_table,
|
|
19
19
|
get_gcs_connection_name,
|
|
20
20
|
get_gcs_svc_account_creds,
|
|
21
|
-
get_kafka_connection_name,
|
|
22
21
|
get_s3_connection_name,
|
|
23
22
|
production_aws_iamrole_only,
|
|
24
23
|
run_aws_iamrole_connection_flow,
|
|
25
24
|
run_gcp_svc_account_connection_flow,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
)
|
|
26
|
+
from tinybird.tb.modules.connection_kafka import (
|
|
27
|
+
connection_create_kafka,
|
|
28
|
+
echo_kafka_data,
|
|
29
|
+
select_connection,
|
|
30
|
+
select_group_id,
|
|
31
|
+
select_topic,
|
|
31
32
|
)
|
|
32
33
|
from tinybird.tb.modules.create import (
|
|
33
34
|
generate_aws_iamrole_connection_file_with_secret,
|
|
34
35
|
generate_gcs_connection_file_with_secrets,
|
|
35
|
-
generate_kafka_connection_with_secrets,
|
|
36
36
|
)
|
|
37
37
|
from tinybird.tb.modules.exceptions import CLIConnectionException
|
|
38
38
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
@@ -121,7 +121,8 @@ def connection_ls(ctx: Context, service: Optional[DataConnectorType] = None) ->
|
|
|
121
121
|
obj: Dict[str, Any] = ctx.ensure_object(dict)
|
|
122
122
|
client: TinyB = obj["client"]
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
datasources = client.datasources()
|
|
125
|
+
connections = client.connections(connector=service, datasources=datasources)
|
|
125
126
|
columns = []
|
|
126
127
|
table = []
|
|
127
128
|
|
|
@@ -314,198 +315,128 @@ def connection_create_gcs(ctx: Context) -> None:
|
|
|
314
315
|
)
|
|
315
316
|
|
|
316
317
|
|
|
317
|
-
@connection_create.command(name="kafka",
|
|
318
|
+
@connection_create.command(name="kafka", help="Create a Kafka connection.")
|
|
319
|
+
@click.option("--connection-name", default=None, help="The name of the connection to identify it in Tinybird")
|
|
320
|
+
@click.option("--bootstrap-servers", default=None, help="Kafka Bootstrap Server in form mykafka.mycloud.com:9092")
|
|
321
|
+
@click.option("--key", default=None, help="Key/User")
|
|
322
|
+
@click.option("--secret", default=None, help="Secret/Password")
|
|
323
|
+
@click.option(
|
|
324
|
+
"--auto-offset-reset", default=None, help="Offset reset, can be 'latest' or 'earliest'. Defaults to 'latest'."
|
|
325
|
+
)
|
|
326
|
+
@click.option("--schema-registry-url", default=None, help="Avro Confluent Schema Registry URL")
|
|
327
|
+
@click.option(
|
|
328
|
+
"--sasl-mechanism",
|
|
329
|
+
default="PLAIN",
|
|
330
|
+
help="Authentication method for connection-based protocols. Defaults to 'PLAIN'",
|
|
331
|
+
)
|
|
332
|
+
@click.option(
|
|
333
|
+
"--security-protocol",
|
|
334
|
+
default="SASL_SSL",
|
|
335
|
+
help="Security protocol for connection-based protocols. Defaults to 'SASL_SSL'",
|
|
336
|
+
)
|
|
337
|
+
@click.option("--ssl-ca-pem", default=None, help="Path or content of the CA Certificate file in PEM format")
|
|
318
338
|
@click.pass_context
|
|
319
|
-
def connection_create_kafka_cmd(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
339
|
+
def connection_create_kafka_cmd(
|
|
340
|
+
ctx: Context,
|
|
341
|
+
connection_name: Optional[str],
|
|
342
|
+
bootstrap_servers: Optional[str],
|
|
343
|
+
key: Optional[str],
|
|
344
|
+
secret: Optional[str],
|
|
345
|
+
auto_offset_reset: Optional[str],
|
|
346
|
+
schema_registry_url: Optional[str],
|
|
347
|
+
sasl_mechanism: Optional[str],
|
|
348
|
+
security_protocol: Optional[str],
|
|
349
|
+
ssl_ca_pem: Optional[str],
|
|
350
|
+
) -> None:
|
|
351
|
+
env: str = ctx.ensure_object(dict)["env"]
|
|
332
352
|
project: Project = ctx.ensure_object(dict)["project"]
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
message=
|
|
338
|
-
),
|
|
339
|
-
default=default_bootstrap_servers,
|
|
340
|
-
show_default=False,
|
|
341
|
-
)
|
|
342
|
-
if not bootstrap_servers:
|
|
343
|
-
bootstrap_servers = click.prompt("Bootstrap Server")
|
|
344
|
-
|
|
345
|
-
validate_kafka_bootstrap_servers(bootstrap_servers)
|
|
346
|
-
secret_required = click.confirm(
|
|
347
|
-
FeedbackManager.highlight(message=" ? Do you want to store the bootstrap server in a .env.local file? [Y/n]"),
|
|
348
|
-
default=True,
|
|
349
|
-
show_default=False,
|
|
350
|
-
)
|
|
351
|
-
tb_secret_bootstrap_servers: Optional[str] = None
|
|
352
|
-
tb_secret_key: Optional[str] = None
|
|
353
|
-
tb_secret_secret: Optional[str] = None
|
|
354
|
-
|
|
355
|
-
if secret_required:
|
|
356
|
-
tb_secret_bootstrap_servers = str(click.prompt(FeedbackManager.highlight(message=" ? Secret name")))
|
|
357
|
-
try:
|
|
358
|
-
save_secret_to_env_file(project=project, name=tb_secret_bootstrap_servers, value=bootstrap_servers)
|
|
359
|
-
except Exception as e:
|
|
360
|
-
raise CLIConnectionException(FeedbackManager.error(message=str(e)))
|
|
361
|
-
|
|
362
|
-
key = click.prompt(FeedbackManager.highlight(message="? Kafka key"))
|
|
363
|
-
|
|
364
|
-
validate_kafka_key(key)
|
|
365
|
-
|
|
366
|
-
secret_required = click.confirm(
|
|
367
|
-
FeedbackManager.highlight(message=" ? Do you want to store the Kafka key in a .env.local file? [Y/n]"),
|
|
368
|
-
default=True,
|
|
369
|
-
show_default=False,
|
|
370
|
-
)
|
|
371
|
-
|
|
372
|
-
if secret_required:
|
|
373
|
-
tb_secret_key = str(click.prompt(FeedbackManager.highlight(message=" ? Secret name")))
|
|
374
|
-
try:
|
|
375
|
-
save_secret_to_env_file(project=project, name=tb_secret_key, value=key)
|
|
376
|
-
except Exception as e:
|
|
377
|
-
raise CLIConnectionException(FeedbackManager.error(message=str(e)))
|
|
378
|
-
|
|
379
|
-
secret = click.prompt(FeedbackManager.highlight(message="? Kafka secret"), hide_input=True)
|
|
380
|
-
|
|
381
|
-
validate_kafka_secret(secret)
|
|
382
|
-
|
|
383
|
-
secret_required = click.confirm(
|
|
384
|
-
FeedbackManager.highlight(message=" ? Do you want to store the Kafka secret in a .env.local file? [Y/n]"),
|
|
385
|
-
default=True,
|
|
386
|
-
show_default=False,
|
|
387
|
-
)
|
|
388
|
-
|
|
389
|
-
if secret_required:
|
|
390
|
-
tb_secret_secret = str(click.prompt(FeedbackManager.highlight(message=" ? Secret name")))
|
|
391
|
-
try:
|
|
392
|
-
save_secret_to_env_file(project=project, name=tb_secret_secret, value=secret)
|
|
393
|
-
except Exception as e:
|
|
394
|
-
raise CLIConnectionException(FeedbackManager.error(message=str(e)))
|
|
395
|
-
|
|
396
|
-
security_protocol_options = ["SASL_SSL", "PLAINTEXT"]
|
|
397
|
-
security_protocol = click.prompt(
|
|
398
|
-
FeedbackManager.highlight(message="? Security Protocol (SASL_SSL, PLAINTEXT) [SASL_SSL]"),
|
|
399
|
-
type=click.Choice(security_protocol_options),
|
|
400
|
-
show_default=False,
|
|
401
|
-
show_choices=False,
|
|
402
|
-
default="SASL_SSL",
|
|
403
|
-
)
|
|
404
|
-
|
|
405
|
-
sasl_mechanism_options = ["PLAIN", "SCRAM-SHA-256", "SCRAM-SHA-512"]
|
|
406
|
-
sasl_mechanism = click.prompt(
|
|
407
|
-
FeedbackManager.highlight(message="? SASL Mechanism (PLAIN, SCRAM-SHA-256, SCRAM-SHA-512) [PLAIN]"),
|
|
408
|
-
type=click.Choice(sasl_mechanism_options),
|
|
409
|
-
show_default=False,
|
|
410
|
-
show_choices=False,
|
|
411
|
-
default="PLAIN",
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
create_in_cloud = (
|
|
415
|
-
click.confirm(
|
|
416
|
-
FeedbackManager.highlight(
|
|
417
|
-
message="? Would you like to create this connection in the cloud environment as well? [Y/n]"
|
|
418
|
-
),
|
|
419
|
-
default=True,
|
|
353
|
+
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
354
|
+
config: Dict[str, Any] = ctx.ensure_object(dict)["config"]
|
|
355
|
+
if env == "local":
|
|
356
|
+
should_build = click.confirm(
|
|
357
|
+
FeedbackManager.highlight(message="? Do you want to build the project before continue? [Y/n]"),
|
|
420
358
|
show_default=False,
|
|
359
|
+
default=True,
|
|
421
360
|
)
|
|
422
|
-
if
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
token=token,
|
|
433
|
-
host=host,
|
|
434
|
-
staging=False,
|
|
435
|
-
)
|
|
436
|
-
if tb_secret_bootstrap_servers:
|
|
437
|
-
prod_client.create_secret(name=tb_secret_bootstrap_servers, value=bootstrap_servers)
|
|
438
|
-
if tb_secret_key:
|
|
439
|
-
prod_client.create_secret(name=tb_secret_key, value=key)
|
|
440
|
-
if tb_secret_secret:
|
|
441
|
-
prod_client.create_secret(name=tb_secret_secret, value=secret)
|
|
442
|
-
click.echo(FeedbackManager.success(message="✓ Secrets created!"))
|
|
443
|
-
|
|
444
|
-
schema_registry_url = click.prompt(
|
|
445
|
-
FeedbackManager.highlight(message="? Schema Registry URL (optional)"),
|
|
446
|
-
default="",
|
|
447
|
-
show_default=False,
|
|
448
|
-
)
|
|
449
|
-
if schema_registry_url:
|
|
450
|
-
validate_kafka_schema_registry_url(schema_registry_url)
|
|
451
|
-
|
|
452
|
-
auto_offset_reset_options = ["latest", "earliest"]
|
|
453
|
-
auto_offset_reset = click.prompt(
|
|
454
|
-
FeedbackManager.highlight(message="? Auto offset reset (latest, earliest) [latest]"),
|
|
455
|
-
type=click.Choice(auto_offset_reset_options),
|
|
456
|
-
default="latest",
|
|
457
|
-
show_default=False,
|
|
458
|
-
show_choices=False,
|
|
459
|
-
)
|
|
460
|
-
validate_kafka_auto_offset_reset(auto_offset_reset)
|
|
461
|
-
click.echo(FeedbackManager.gray(message="» Validating connection..."))
|
|
462
|
-
|
|
463
|
-
topics = list_kafka_topics(bootstrap_servers, key, secret, security_protocol, sasl_mechanism)
|
|
464
|
-
|
|
465
|
-
if topics is None:
|
|
466
|
-
raise CLIConnectionException(FeedbackManager.error(message="Invalid Kafka connection"))
|
|
467
|
-
|
|
468
|
-
click.echo(FeedbackManager.success(message="✓ Connection is valid"))
|
|
469
|
-
generate_kafka_connection_with_secrets(
|
|
470
|
-
name=name,
|
|
361
|
+
if should_build:
|
|
362
|
+
click.echo(FeedbackManager.gray(message="» Building project..."))
|
|
363
|
+
build_project(project=project, tb_client=client, watch=False, config=config, silent=True)
|
|
364
|
+
click.echo(FeedbackManager.success(message="✓ Build completed"))
|
|
365
|
+
else:
|
|
366
|
+
click.echo(FeedbackManager.gray(message="Skipping build..."))
|
|
367
|
+
|
|
368
|
+
result = connection_create_kafka(
|
|
369
|
+
ctx,
|
|
370
|
+
connection_name=connection_name,
|
|
471
371
|
bootstrap_servers=bootstrap_servers,
|
|
472
|
-
tb_secret_bootstrap_servers=tb_secret_bootstrap_servers,
|
|
473
372
|
key=key,
|
|
474
|
-
tb_secret_key=tb_secret_key,
|
|
475
373
|
secret=secret,
|
|
476
|
-
|
|
477
|
-
|
|
374
|
+
auto_offset_reset=auto_offset_reset,
|
|
375
|
+
schema_registry_url=schema_registry_url,
|
|
478
376
|
sasl_mechanism=sasl_mechanism,
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
click.echo(FeedbackManager.info_file_created(file=f"connections/{name}.connection"))
|
|
482
|
-
click.echo(FeedbackManager.success(message="✓ Connection created!"))
|
|
483
|
-
return (
|
|
484
|
-
name,
|
|
485
|
-
bootstrap_servers,
|
|
486
|
-
key,
|
|
487
|
-
secret,
|
|
488
|
-
schema_registry_url,
|
|
489
|
-
auto_offset_reset,
|
|
490
|
-
sasl_mechanism,
|
|
491
|
-
security_protocol,
|
|
492
|
-
topics,
|
|
377
|
+
security_protocol=security_protocol,
|
|
378
|
+
ssl_ca_pem=ssl_ca_pem,
|
|
493
379
|
)
|
|
494
380
|
|
|
381
|
+
if not result["error"]:
|
|
382
|
+
yes = click.confirm(
|
|
383
|
+
FeedbackManager.highlight(message="? Would you like to preview data from the connection?"),
|
|
384
|
+
default=True,
|
|
385
|
+
show_default=False,
|
|
386
|
+
)
|
|
387
|
+
if yes:
|
|
388
|
+
connection_data(connection_name=result["name"], client=client)
|
|
389
|
+
else:
|
|
390
|
+
click.echo(FeedbackManager.gray(message="Skipping data preview."))
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
@connection.command(name="data", help="Preview data from an existing connection.")
|
|
394
|
+
@click.argument("connection_name", type=str, required=False)
|
|
395
|
+
@click.option("--kafka-topic", type=str, help="The Kafka topic to preview")
|
|
396
|
+
@click.option("--kafka-group-id", type=str, help="The Kafka group ID to use for preview")
|
|
397
|
+
@click.pass_context
|
|
398
|
+
def connection_data_cmd(
|
|
399
|
+
ctx: Context,
|
|
400
|
+
connection_name: Optional[str] = None,
|
|
401
|
+
kafka_topic: Optional[str] = None,
|
|
402
|
+
kafka_group_id: Optional[str] = None,
|
|
403
|
+
) -> None:
|
|
404
|
+
project: Project = ctx.ensure_object(dict)["project"]
|
|
405
|
+
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
406
|
+
env: str = ctx.ensure_object(dict)["env"]
|
|
407
|
+
config: Dict[str, Any] = ctx.ensure_object(dict)["config"]
|
|
408
|
+
|
|
409
|
+
if env == "local":
|
|
410
|
+
click.echo(FeedbackManager.gray(message="» Building project to access the latest connections..."))
|
|
411
|
+
build_project(project=project, tb_client=client, watch=False, config=config, silent=True)
|
|
412
|
+
click.echo(FeedbackManager.success(message="✓ Build completed"))
|
|
413
|
+
|
|
414
|
+
if connection_name is None:
|
|
415
|
+
connections = client.connections("kafka")
|
|
416
|
+
connection = select_connection(None, "kafka", connections, client)
|
|
417
|
+
connection_name = connection["name"]
|
|
418
|
+
|
|
419
|
+
connection_data(connection_name, client, kafka_topic, kafka_group_id)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def connection_data(
|
|
423
|
+
connection_name: str,
|
|
424
|
+
client: TinyB,
|
|
425
|
+
kafka_topic: Optional[str] = None,
|
|
426
|
+
kafka_group_id: Optional[str] = None,
|
|
427
|
+
) -> None:
|
|
428
|
+
connection = next((c for c in client.connections() if c["name"] == connection_name), None)
|
|
429
|
+
if not connection:
|
|
430
|
+
raise CLIConnectionException(FeedbackManager.error(message=f"Connection {connection_name} not found."))
|
|
431
|
+
|
|
432
|
+
if connection["service"] != DataConnectorType.KAFKA:
|
|
433
|
+
raise CLIConnectionException(
|
|
434
|
+
FeedbackManager.error(
|
|
435
|
+
message=f"{connection['service']} connections are not supported yet for previewing data. Supported connections: kafka"
|
|
436
|
+
)
|
|
437
|
+
)
|
|
495
438
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
"sasl.mechanism": sasl_mechanism,
|
|
501
|
-
"sasl.username": sasl_username,
|
|
502
|
-
"sasl.password": sasl_password,
|
|
503
|
-
"log_level": 0,
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
try:
|
|
507
|
-
client = AdminClient(conf)
|
|
508
|
-
metadata = client.list_topics(timeout=5)
|
|
509
|
-
return list(metadata.topics.keys())
|
|
510
|
-
except Exception:
|
|
511
|
-
return None
|
|
439
|
+
connection_id = connection["id"]
|
|
440
|
+
topic = select_topic(kafka_topic, connection_id, client)
|
|
441
|
+
group_id = select_group_id(kafka_group_id, topic, connection_id, client)
|
|
442
|
+
echo_kafka_data(connection_id, connection_name, topic, group_id, client)
|