tinybird 0.0.1.dev99__tar.gz → 0.0.1.dev100__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.

Potentially problematic release.


This version of tinybird might be problematic. Click here for more details.

Files changed (109) hide show
  1. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/__cli__.py +2 -2
  3. tinybird-0.0.1.dev100/tinybird/tb/modules/infra.py +564 -0
  4. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird.egg-info/PKG-INFO +1 -1
  5. tinybird-0.0.1.dev99/tinybird/tb/modules/infra.py +0 -693
  6. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/setup.cfg +0 -0
  7. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/__cli__.py +0 -0
  8. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/ch_utils/constants.py +0 -0
  9. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/ch_utils/engine.py +0 -0
  10. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/check_pypi.py +0 -0
  11. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/client.py +0 -0
  12. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/config.py +0 -0
  13. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/connectors.py +0 -0
  14. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/context.py +0 -0
  15. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/datafile.py +0 -0
  16. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/datatypes.py +0 -0
  17. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/feedback_manager.py +0 -0
  18. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/git_settings.py +0 -0
  19. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/prompts.py +0 -0
  20. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/sql.py +0 -0
  21. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/sql_template.py +0 -0
  22. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/sql_template_fmt.py +0 -0
  23. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/sql_toolset.py +0 -0
  24. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/syncasync.py +0 -0
  25. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/cli.py +0 -0
  26. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/auth.py +0 -0
  27. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/build.py +0 -0
  28. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/cicd.py +0 -0
  29. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/cli.py +0 -0
  30. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/common.py +0 -0
  31. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/config.py +0 -0
  32. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/connection.py +0 -0
  33. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/copy.py +0 -0
  34. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/create.py +0 -0
  35. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/build.py +0 -0
  36. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/build_common.py +0 -0
  37. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  38. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  39. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/common.py +0 -0
  40. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/diff.py +0 -0
  41. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  42. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/fixture.py +0 -0
  43. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/format_common.py +0 -0
  44. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  45. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  46. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
  47. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
  48. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  49. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/playground.py +0 -0
  50. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datafile/pull.py +0 -0
  51. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/datasource.py +0 -0
  52. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/deployment.py +0 -0
  53. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/endpoint.py +0 -0
  54. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/exceptions.py +0 -0
  55. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/feedback_manager.py +0 -0
  56. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/fmt.py +0 -0
  57. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/job.py +0 -0
  58. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/llm.py +0 -0
  59. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/llm_utils.py +0 -0
  60. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/local.py +0 -0
  61. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/local_common.py +0 -0
  62. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/login.py +0 -0
  63. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/logout.py +0 -0
  64. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/materialization.py +0 -0
  65. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/mock.py +0 -0
  66. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/open.py +0 -0
  67. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/pipe.py +0 -0
  68. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/playground.py +0 -0
  69. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/project.py +0 -0
  70. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/regions.py +0 -0
  71. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/secret.py +0 -0
  72. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/shell.py +0 -0
  73. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/table.py +0 -0
  74. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/tag.py +0 -0
  75. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/telemetry.py +0 -0
  76. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/test.py +0 -0
  77. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  78. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  79. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/token.py +0 -0
  80. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/watch.py +0 -0
  81. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/workspace.py +0 -0
  82. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb/modules/workspace_members.py +0 -0
  83. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli.py +0 -0
  84. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/auth.py +0 -0
  85. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/branch.py +0 -0
  86. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/cicd.py +0 -0
  87. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/cli.py +0 -0
  88. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/common.py +0 -0
  89. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/config.py +0 -0
  90. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/connection.py +0 -0
  91. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/datasource.py +0 -0
  92. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/exceptions.py +0 -0
  93. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/fmt.py +0 -0
  94. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/job.py +0 -0
  95. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/pipe.py +0 -0
  96. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/regions.py +0 -0
  97. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/tag.py +0 -0
  98. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/telemetry.py +0 -0
  99. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/test.py +0 -0
  100. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  101. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  102. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/workspace.py +0 -0
  103. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  104. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird/tornado_template.py +0 -0
  105. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird.egg-info/SOURCES.txt +0 -0
  106. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird.egg-info/dependency_links.txt +0 -0
  107. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird.egg-info/entry_points.txt +0 -0
  108. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird.egg-info/requires.txt +0 -0
  109. {tinybird-0.0.1.dev99 → tinybird-0.0.1.dev100}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev99
3
+ Version: 0.0.1.dev100
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '0.0.1.dev99'
8
- __revision__ = '1e30c94'
7
+ __version__ = '0.0.1.dev100'
8
+ __revision__ = 'ccb1518'
@@ -0,0 +1,564 @@
1
+ import json
2
+ import subprocess
3
+ import time
4
+ import uuid
5
+ from pathlib import Path
6
+ from typing import Optional
7
+
8
+ import click
9
+ import requests
10
+ from click import Context
11
+
12
+ from tinybird.client import TinyB
13
+ from tinybird.syncasync import async_to_sync
14
+ from tinybird.tb.modules.cli import CLIException, cli
15
+ from tinybird.tb.modules.common import coro, echo_safe_humanfriendly_tables_format_smart_table
16
+ from tinybird.tb.modules.config import CLIConfig
17
+ from tinybird.tb.modules.feedback_manager import FeedbackManager
18
+
19
+ from .common import CONTEXT_SETTINGS
20
+
21
+ K8S_YML = """
22
+ ---
23
+ apiVersion: v1
24
+ kind: Namespace
25
+ metadata:
26
+ name: %(namespace)s
27
+ labels:
28
+ name: tinybird
29
+ ---
30
+ apiVersion: v1
31
+ kind: ServiceAccount
32
+ metadata:
33
+ name: tinybird
34
+ namespace: %(namespace)s
35
+ labels:
36
+ name: tinybird
37
+ automountServiceAccountToken: true
38
+ ---
39
+ apiVersion: v1
40
+ kind: Service
41
+ metadata:
42
+ name: tinybird
43
+ namespace: %(namespace)s
44
+ labels:
45
+ name: tinybird
46
+ spec:
47
+ type: ClusterIP
48
+ ports:
49
+ - port: 80
50
+ targetPort: http
51
+ protocol: TCP
52
+ name: http
53
+ selector:
54
+ name: tinybird
55
+ ---
56
+ apiVersion: networking.k8s.io/v1
57
+ kind: Ingress
58
+ metadata:
59
+ namespace: %(namespace)s
60
+ name: tinybird
61
+ annotations:
62
+ alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
63
+ alb.ingress.kubernetes.io/scheme: internet-facing
64
+ alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
65
+ alb.ingress.kubernetes.io/ssl-redirect: '443'
66
+ alb.ingress.kubernetes.io/target-type: 'ip'
67
+ alb.ingress.kubernetes.io/load-balancer-name: %(namespace)s
68
+ alb.ingress.kubernetes.io/success-codes: '200,301,302'
69
+ spec:
70
+ ingressClassName: alb
71
+ tls:
72
+ - hosts:
73
+ - %(full_dns_name)s
74
+ rules:
75
+ - http:
76
+ paths:
77
+ - path: /
78
+ pathType: Prefix
79
+ backend:
80
+ service:
81
+ name: tinybird
82
+ port:
83
+ name: http
84
+ ---
85
+ apiVersion: apps/v1
86
+ kind: StatefulSet
87
+ metadata:
88
+ name: tinybird
89
+ namespace: %(namespace)s
90
+ spec:
91
+ serviceName: "tinybird"
92
+ replicas: 1
93
+ selector:
94
+ matchLabels:
95
+ name: tinybird
96
+ template:
97
+ metadata:
98
+ labels:
99
+ name: tinybird
100
+ spec:
101
+ serviceAccountName: tinybird
102
+ containers:
103
+ - name: tinybird
104
+ image: "tinybirdco/tinybird-local:beta"
105
+ imagePullPolicy: Always
106
+ ports:
107
+ - name: http
108
+ containerPort: 7181
109
+ protocol: TCP
110
+ env:
111
+ - name: TB_INFRA_TOKEN
112
+ value: "%(infra_token)s"
113
+ - name: TB_INFRA_WORKSPACE
114
+ value: "%(infra_workspace)s"
115
+ - name: TB_INFRA_ORGANIZATION
116
+ value: "%(infra_organization)s"
117
+ - name: TB_INFRA_USER
118
+ value: "%(infra_user)s"
119
+ volumeMounts:
120
+ - name: clickhouse-data
121
+ mountPath: /var/lib/clickhouse
122
+ volumeClaimTemplates:
123
+ - metadata:
124
+ name: clickhouse-data
125
+ spec:
126
+ accessModes: [ "ReadWriteOnce" ]
127
+ resources:
128
+ requests:
129
+ storage: 100Gi
130
+ storageClassName: %(storage_class)s
131
+ """
132
+
133
+ TERRAFORM_FIRST_TEMPLATE = """
134
+ terraform {
135
+ required_providers {
136
+ aws = {
137
+ source = "hashicorp/aws"
138
+ version = "~> 5.0"
139
+ }
140
+ }
141
+ }
142
+
143
+ provider "aws" {
144
+ region = "%(aws_region)s"
145
+ }
146
+
147
+ # Get the hosted zone data
148
+ data "aws_route53_zone" "selected" {
149
+ name = "%(dns_zone_name)s"
150
+ }
151
+
152
+ # Create ACM certificate
153
+ resource "aws_acm_certificate" "cert" {
154
+ domain_name = "%(dns_record)s.${data.aws_route53_zone.selected.name}"
155
+ validation_method = "DNS"
156
+ subject_alternative_names = [data.aws_route53_zone.selected.name]
157
+
158
+ lifecycle {
159
+ create_before_destroy = true
160
+ }
161
+ }
162
+
163
+ # Create DNS records for certificate validation
164
+ resource "aws_route53_record" "cert_validation" {
165
+ for_each = {
166
+ for dvo in aws_acm_certificate.cert.domain_validation_options : dvo.domain_name => {
167
+ name = dvo.resource_record_name
168
+ record = dvo.resource_record_value
169
+ type = dvo.resource_record_type
170
+ }
171
+ }
172
+
173
+ allow_overwrite = true
174
+ name = each.value.name
175
+ records = [each.value.record]
176
+ ttl = 60
177
+ type = each.value.type
178
+ zone_id = data.aws_route53_zone.selected.zone_id
179
+ }
180
+
181
+ # Certificate validation
182
+ resource "aws_acm_certificate_validation" "cert" {
183
+ certificate_arn = aws_acm_certificate.cert.arn
184
+ validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
185
+ }
186
+ """
187
+
188
+ TERRAFORM_SECOND_TEMPLATE = """
189
+ # Create Route 53 record for the load balancer
190
+ data "aws_alb" "tinybird" {
191
+ name = "%(namespace)s"
192
+ }
193
+
194
+ resource "aws_route53_record" "tinybird" {
195
+ zone_id = data.aws_route53_zone.selected.zone_id
196
+ name = "%(full_dns_name)s"
197
+ type = "A"
198
+ alias {
199
+ name = data.aws_alb.tinybird.dns_name
200
+ zone_id = data.aws_alb.tinybird.zone_id
201
+ evaluate_target_health = true
202
+ }
203
+ }
204
+
205
+ output "tinybird_dns" {
206
+ description = "The DNS name for Tinybird"
207
+ value = aws_route53_record.tinybird.fqdn
208
+ }
209
+ """
210
+
211
+
212
+ @cli.group(context_settings=CONTEXT_SETTINGS, hidden=True)
213
+ @click.pass_context
214
+ def infra(ctx: Context) -> None:
215
+ """Infra commands."""
216
+
217
+
218
+ @infra.command(name="init")
219
+ @click.option("--name", type=str, help="Name for identifying the self-managed infrastructure in Tinybird")
220
+ @click.option("--provider", type=str, help="Infrastructure provider (aws, gcp, azure)")
221
+ @click.option("--region", type=str, help="AWS region (for AWS provider)")
222
+ @click.option("--dns-zone-name", type=str, help="DNS zone name")
223
+ @click.option("--namespace", type=str, help="Kubernetes namespace for deployment")
224
+ @click.option("--dns-record", type=str, help="DNS record name to create (without domain, e.g. 'tinybird')")
225
+ @click.option("--storage-class", type=str, help="Storage class for the k8s StatefulSet")
226
+ @click.option(
227
+ "--auto-apply", is_flag=True, help="Automatically apply Terraform and kubectl configuration without prompting"
228
+ )
229
+ @click.option("--skip-apply", is_flag=True, help="Skip Terraform and kubectl configuration and application")
230
+ @click.pass_context
231
+ def infra_init(
232
+ ctx: Context,
233
+ name: str,
234
+ provider: str,
235
+ region: Optional[str] = None,
236
+ dns_zone_name: Optional[str] = None,
237
+ namespace: Optional[str] = None,
238
+ dns_record: Optional[str] = None,
239
+ storage_class: Optional[str] = None,
240
+ auto_apply: bool = False,
241
+ skip_apply: bool = False,
242
+ ) -> None:
243
+ """Init infra"""
244
+ # Check if provider is specified
245
+ if not provider:
246
+ click.echo("Error: --provider option is required. Please specify a provider (aws, gcp, azure).")
247
+ return
248
+
249
+ # AWS-specific Terraform template creation
250
+ if provider.lower() != "aws":
251
+ click.echo("Provider not supported yet.")
252
+ return
253
+
254
+ # Create infra directory if it doesn't exist
255
+ infra_dir = Path(f"infra/{provider}")
256
+ infra_dir.mkdir(exist_ok=True)
257
+ yaml_path = infra_dir / "k8s.yaml"
258
+ tf_path = infra_dir / "main.tf"
259
+ config_path = infra_dir / "config.json"
260
+
261
+ # Load existing configuration if available
262
+ config = {}
263
+ if config_path.exists():
264
+ try:
265
+ with open(config_path, "r") as f:
266
+ config = json.load(f)
267
+ click.echo("Loaded existing configuration from config.json")
268
+ except json.JSONDecodeError:
269
+ click.echo("Warning: Could not parse existing config.json, will create a new one")
270
+
271
+ # Generate a random ID for default values
272
+ random_id = str(uuid.uuid4())[:8]
273
+
274
+ # Get or prompt for configuration values
275
+ name = name or click.prompt("Enter name", type=str)
276
+ region = region or config.get("region") or click.prompt("Enter aws region", default="us-east-1", type=str)
277
+ dns_zone_name = dns_zone_name or config.get("dns_zone_name") or click.prompt("Enter DNS zone name", type=str)
278
+ namespace = (
279
+ namespace
280
+ or config.get("namespace")
281
+ or click.prompt("Enter namespace name", default=f"tinybird-{random_id}", type=str)
282
+ )
283
+ dns_record = (
284
+ dns_record
285
+ or config.get("dns_record")
286
+ or click.prompt("Enter DNS record name (without domain)", default=f"tinybird-{random_id}", type=str)
287
+ )
288
+ storage_class = config.get("storage_class") or click.prompt(
289
+ "Enter storage class", default="gp3-encrypted", type=str
290
+ )
291
+
292
+ # Save configuration
293
+ config = {
294
+ "provider": provider,
295
+ "region": region,
296
+ "dns_zone_name": dns_zone_name,
297
+ "namespace": namespace,
298
+ "dns_record": dns_record,
299
+ "storage_class": storage_class,
300
+ }
301
+
302
+ with open(config_path, "w") as f:
303
+ json.dump(config, f, indent=2)
304
+
305
+ click.echo(f"Configuration saved to {config_path}")
306
+
307
+ client: TinyB = ctx.obj["client"]
308
+ cli_config = CLIConfig.get_project_config()
309
+ user_client = cli_config.get_client(token=cli_config.get_user_token() or "")
310
+ user_workspaces = async_to_sync(user_client.user_workspaces_with_organization)()
311
+ admin_org_id = user_workspaces.get("organization_id")
312
+ admin_org_name = user_workspaces.get("organization_name", "")
313
+ infras = async_to_sync(client.infra_list)(organization_id=admin_org_id)
314
+ infra = next((infra for infra in infras if infra["name"] == name), None)
315
+ if not infra:
316
+ click.echo(FeedbackManager.highlight(message=f"\n» Creating infrastructure '{name}' in Tinybird..."))
317
+ host = f"https://{dns_record}.{dns_zone_name}"
318
+ infra = async_to_sync(client.infra_create)(organization_id=admin_org_id, name=name, host=host)
319
+
320
+ infra_token = infra["token"]
321
+
322
+ # Write the Terraform template
323
+ terraform_content = TERRAFORM_FIRST_TEMPLATE % {
324
+ "aws_region": region,
325
+ "dns_zone_name": dns_zone_name,
326
+ "dns_record": dns_record,
327
+ }
328
+
329
+ with open(tf_path, "w") as f:
330
+ f.write(terraform_content.lstrip())
331
+
332
+ click.echo(f"Created Terraform configuration in {tf_path}")
333
+
334
+ new_content = K8S_YML % {
335
+ "namespace": namespace,
336
+ "storage_class": storage_class,
337
+ "full_dns_name": f"{dns_record}.{dns_zone_name}",
338
+ "infra_token": infra_token,
339
+ "infra_workspace": cli_config.get("name", ""),
340
+ "infra_organization": admin_org_name,
341
+ "infra_user": cli_config.get_user_email() or "",
342
+ }
343
+
344
+ with open(yaml_path, "w") as f:
345
+ f.write(new_content.lstrip())
346
+
347
+ click.echo(f"Created Kubernetes configuration in {yaml_path}")
348
+
349
+ # Apply Terraform configuration if user confirms
350
+ if not skip_apply:
351
+ # Initialize Terraform
352
+ click.echo("Initializing Terraform...")
353
+ init_result = subprocess.run(["terraform", f"-chdir={infra_dir}", "init"], capture_output=True, text=True)
354
+
355
+ if init_result.returncode != 0:
356
+ click.echo("Terraform initialization failed:")
357
+ click.echo(init_result.stderr)
358
+ return
359
+
360
+ # Run terraform plan first
361
+ click.echo("\nRunning Terraform plan...\n")
362
+ plan_result = subprocess.run(["terraform", f"-chdir={infra_dir}", "plan"], capture_output=True, text=True)
363
+
364
+ if plan_result.returncode != 0:
365
+ click.echo("Terraform plan failed:")
366
+ click.echo(plan_result.stderr)
367
+ return
368
+
369
+ click.echo(plan_result.stdout)
370
+
371
+ # Apply Terraform configuration if user confirms
372
+ if auto_apply or click.confirm("Would you like to apply the Terraform configuration now?"):
373
+ click.echo("\nApplying Terraform configuration...\n")
374
+ apply_result = subprocess.run(
375
+ ["terraform", f"-chdir={infra_dir}", "apply", "-auto-approve"], capture_output=True, text=True
376
+ )
377
+
378
+ if apply_result.returncode != 0:
379
+ click.echo("Terraform apply failed:")
380
+ click.echo(apply_result.stderr)
381
+ return
382
+
383
+ click.echo(apply_result.stdout)
384
+
385
+ # Prompt to apply the k8s configuration
386
+ if not skip_apply and (
387
+ auto_apply or click.confirm("Would you like to apply the Kubernetes configuration now?")
388
+ ):
389
+ # Get current kubectl context
390
+ current_context_result = subprocess.run(
391
+ ["kubectl", "config", "current-context"], capture_output=True, text=True
392
+ )
393
+
394
+ current_context = (
395
+ current_context_result.stdout.strip() if current_context_result.returncode == 0 else "unknown"
396
+ )
397
+ # Get available contexts
398
+ contexts_result = subprocess.run(
399
+ ["kubectl", "config", "get-contexts", "-o", "name"], capture_output=True, text=True
400
+ )
401
+
402
+ if contexts_result.returncode != 0:
403
+ click.echo("Failed to get kubectl contexts:")
404
+ click.echo(contexts_result.stderr)
405
+ return
406
+
407
+ available_contexts = [context.strip() for context in contexts_result.stdout.splitlines() if context.strip()]
408
+
409
+ if not available_contexts:
410
+ click.echo("No kubectl contexts found. Please configure kubectl first.")
411
+ return
412
+
413
+ # Prompt user to select a context
414
+ if len(available_contexts) == 1:
415
+ selected_context = available_contexts[0]
416
+ click.echo(f"Using the only available kubectl context: {selected_context}")
417
+ else:
418
+ click.echo("\nAvailable kubectl contexts:")
419
+ for i, context in enumerate(available_contexts):
420
+ marker = " (current)" if context == current_context else ""
421
+ click.echo(f" {i + 1}. {context}{marker}")
422
+
423
+ click.echo("")
424
+ default_index = (
425
+ available_contexts.index(current_context) + 1 if current_context in available_contexts else 1
426
+ )
427
+
428
+ selected_index = click.prompt(
429
+ "Select kubectl context number to apply configuration",
430
+ type=click.IntRange(1, len(available_contexts)),
431
+ default=default_index,
432
+ )
433
+
434
+ selected_context = available_contexts[selected_index - 1]
435
+ click.echo(f"Selected context: {selected_context}")
436
+
437
+ # Apply the configuration to the selected context
438
+ click.echo(f"Applying Kubernetes configuration to context '{selected_context}'...")
439
+ apply_result = subprocess.run(
440
+ ["kubectl", "--context", selected_context, "apply", "-f", str(yaml_path)],
441
+ capture_output=True,
442
+ text=True,
443
+ )
444
+
445
+ if apply_result.returncode != 0:
446
+ click.echo("Failed to apply Kubernetes configuration:")
447
+ click.echo(apply_result.stderr)
448
+ else:
449
+ click.echo("Kubernetes configuration applied successfully:")
450
+ click.echo(apply_result.stdout)
451
+
452
+ # Get the namespace from the applied configuration
453
+ namespace = None
454
+ with open(yaml_path, "r") as f:
455
+ for line in f:
456
+ if "namespace:" in line and not namespace:
457
+ namespace = line.split("namespace:")[1].strip()
458
+ break
459
+
460
+ if not namespace:
461
+ namespace = "tinybird" # Default namespace
462
+
463
+ click.echo("\nWaiting for load balancer and DNS to be provisioned...")
464
+
465
+ max_attempts = 30 # 30 attempts * 10 seconds = 5 minutes
466
+ endpoint_url = f"https://{dns_record}.{dns_zone_name}"
467
+
468
+ with click.progressbar(
469
+ range(max_attempts),
470
+ label=f"Checking endpoint availability: {endpoint_url}",
471
+ length=max_attempts,
472
+ show_eta=True,
473
+ show_percent=True,
474
+ fill_char="█",
475
+ empty_char="░",
476
+ ) as bar:
477
+ for attempt in bar:
478
+ try:
479
+ response = requests.get(endpoint_url, allow_redirects=False, timeout=5)
480
+ if response.status_code < 400: # Consider any non-error response as success
481
+ click.echo(click.style("\n✅ HTTPS endpoint is now accessible!", fg="green", bold=True))
482
+ break
483
+ except requests.RequestException:
484
+ pass
485
+
486
+ if attempt == max_attempts - 1:
487
+ click.echo(
488
+ click.style(
489
+ "\n⚠️ HTTPS endpoint not accessible after 5 minutes", fg="yellow", bold=True
490
+ )
491
+ )
492
+ click.echo(
493
+ " This might be due to DNS propagation or the Load Balancer provisioning delays"
494
+ )
495
+ click.echo(f" Please try accessing {endpoint_url} manually in a few minutes")
496
+ else:
497
+ time.sleep(10)
498
+
499
+ if not skip_apply:
500
+ # Print a summary with the endpoint URL
501
+ click.echo("\n" + "=" * 60)
502
+ click.echo("DEPLOYMENT SUMMARY".center(60))
503
+ click.echo("=" * 60)
504
+ click.echo("✅ Load balancer provisioned")
505
+
506
+ click.echo(f"\n🔗 Tinybird is available at: https://{dns_record}.{dns_zone_name}")
507
+
508
+ click.echo(
509
+ "\n📌 Note: It may take a few minutes for DNS to propagate and the HTTPS certificate to be fully provisioned."
510
+ )
511
+
512
+
513
+ @infra.command(name="rm")
514
+ @click.argument("name")
515
+ @click.pass_context
516
+ @coro
517
+ async def infra_rm(ctx: click.Context, name: str):
518
+ """Delete an infrastructure from Tinybird"""
519
+ try:
520
+ click.echo(FeedbackManager.highlight(message=f"\n» Deleting infrastructure '{name}' from Tinybird..."))
521
+ client: TinyB = ctx.ensure_object(dict)["client"]
522
+ user_workspaces = await client.user_workspaces_with_organization()
523
+ admin_org_id = user_workspaces.get("organization_id")
524
+ if not admin_org_id:
525
+ raise CLIException("No organization associated to this workspace")
526
+ infras = await client.infra_list(admin_org_id)
527
+ infra_id = next((infra["id"] for infra in infras if infra["name"] == name), None)
528
+ if not infra_id:
529
+ raise CLIException(f"Infrastructure '{name}' not found")
530
+ await client.infra_delete(infra_id, admin_org_id)
531
+ click.echo(FeedbackManager.success(message=f"\n✓ Infrastructure '{name}' deleted"))
532
+ except Exception as e:
533
+ click.echo(FeedbackManager.error(message=f"✗ Error: {e}"))
534
+
535
+
536
+ @infra.command(name="ls")
537
+ @click.pass_context
538
+ @coro
539
+ async def infra_ls(ctx: click.Context):
540
+ """List self-managed infrastructures"""
541
+
542
+ client: TinyB = ctx.ensure_object(dict)["client"]
543
+ config = CLIConfig.get_project_config()
544
+ user_client = config.get_client(token=config.get_user_token() or "")
545
+ user_workspaces = await user_client.user_workspaces_with_organization()
546
+ admin_org_id = user_workspaces.get("organization_id")
547
+ infras = await client.infra_list(organization_id=admin_org_id)
548
+ columns = [
549
+ "name",
550
+ "host",
551
+ ]
552
+ table_human_readable = []
553
+ table_machine_readable = []
554
+
555
+ for infra in infras:
556
+ name = infra["name"]
557
+ host = infra["host"]
558
+
559
+ table_human_readable.append((name, host))
560
+ table_machine_readable.append({"name": name, "host": host})
561
+
562
+ click.echo(FeedbackManager.info(message="\n** Infras:"))
563
+ echo_safe_humanfriendly_tables_format_smart_table(table_human_readable, column_names=columns)
564
+ click.echo("\n")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev99
3
+ Version: 0.0.1.dev100
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird