tinybird 0.0.1.dev98__py3-none-any.whl → 0.0.1.dev100__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.
Potentially problematic release.
This version of tinybird might be problematic. Click here for more details.
- tinybird/client.py +2 -2
- tinybird/tb/__cli__.py +2 -2
- tinybird/tb/modules/infra.py +213 -342
- tinybird/tb/modules/login.py +1 -0
- tinybird/tb/modules/workspace.py +1 -1
- {tinybird-0.0.1.dev98.dist-info → tinybird-0.0.1.dev100.dist-info}/METADATA +1 -1
- {tinybird-0.0.1.dev98.dist-info → tinybird-0.0.1.dev100.dist-info}/RECORD +10 -10
- {tinybird-0.0.1.dev98.dist-info → tinybird-0.0.1.dev100.dist-info}/WHEEL +0 -0
- {tinybird-0.0.1.dev98.dist-info → tinybird-0.0.1.dev100.dist-info}/entry_points.txt +0 -0
- {tinybird-0.0.1.dev98.dist-info → tinybird-0.0.1.dev100.dist-info}/top_level.txt +0 -0
tinybird/client.py
CHANGED
|
@@ -852,9 +852,9 @@ class TinyB:
|
|
|
852
852
|
url = f"/v0/environments/{branch_id}/regression"
|
|
853
853
|
return await self._req(url, method="POST", data=data, headers={"Content-Type": "application/json"})
|
|
854
854
|
|
|
855
|
-
async def delete_workspace(self, id: str, hard_delete_confirmation: Optional[str]):
|
|
855
|
+
async def delete_workspace(self, id: str, hard_delete_confirmation: Optional[str], version: str = "v0"):
|
|
856
856
|
data = {"confirmation": hard_delete_confirmation}
|
|
857
|
-
return await self._req(f"/
|
|
857
|
+
return await self._req(f"/{version}/workspaces/{id}", data, method="DELETE")
|
|
858
858
|
|
|
859
859
|
async def delete_branch(self, id: str):
|
|
860
860
|
return await self._req(f"/v0/environments/{id}", method="DELETE")
|
tinybird/tb/__cli__.py
CHANGED
|
@@ -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.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '0.0.1.dev100'
|
|
8
|
+
__revision__ = 'ccb1518'
|
tinybird/tb/modules/infra.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import time
|
|
2
4
|
import uuid
|
|
3
5
|
from pathlib import Path
|
|
4
6
|
from typing import Optional
|
|
5
7
|
|
|
6
8
|
import click
|
|
9
|
+
import requests
|
|
7
10
|
from click import Context
|
|
8
11
|
|
|
9
12
|
from tinybird.client import TinyB
|
|
@@ -40,28 +43,50 @@ metadata:
|
|
|
40
43
|
namespace: %(namespace)s
|
|
41
44
|
labels:
|
|
42
45
|
name: tinybird
|
|
43
|
-
annotations:
|
|
44
|
-
service.beta.kubernetes.io/aws-load-balancer-type: 'external'
|
|
45
|
-
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: 'ip'
|
|
46
|
-
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: 'tcp'
|
|
47
|
-
service.beta.kubernetes.io/aws-load-balancer-scheme: 'internet-facing'
|
|
48
|
-
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: 'ELBSecurityPolicy-TLS13-1-2-2021-06'
|
|
49
|
-
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: '%(cert_arn)s'
|
|
50
46
|
spec:
|
|
51
|
-
type:
|
|
47
|
+
type: ClusterIP
|
|
52
48
|
ports:
|
|
53
|
-
- port:
|
|
49
|
+
- port: 80
|
|
54
50
|
targetPort: http
|
|
55
51
|
protocol: TCP
|
|
56
|
-
name:
|
|
52
|
+
name: http
|
|
57
53
|
selector:
|
|
58
54
|
name: tinybird
|
|
59
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
|
+
---
|
|
60
85
|
apiVersion: apps/v1
|
|
61
86
|
kind: StatefulSet
|
|
62
87
|
metadata:
|
|
63
88
|
name: tinybird
|
|
64
|
-
namespace:
|
|
89
|
+
namespace: %(namespace)s
|
|
65
90
|
spec:
|
|
66
91
|
serviceName: "tinybird"
|
|
67
92
|
replicas: 1
|
|
@@ -85,6 +110,12 @@ spec:
|
|
|
85
110
|
env:
|
|
86
111
|
- name: TB_INFRA_TOKEN
|
|
87
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"
|
|
88
119
|
volumeMounts:
|
|
89
120
|
- name: clickhouse-data
|
|
90
121
|
mountPath: /var/lib/clickhouse
|
|
@@ -115,12 +146,12 @@ provider "aws" {
|
|
|
115
146
|
|
|
116
147
|
# Get the hosted zone data
|
|
117
148
|
data "aws_route53_zone" "selected" {
|
|
118
|
-
name = "%(
|
|
149
|
+
name = "%(dns_zone_name)s"
|
|
119
150
|
}
|
|
120
151
|
|
|
121
152
|
# Create ACM certificate
|
|
122
153
|
resource "aws_acm_certificate" "cert" {
|
|
123
|
-
domain_name = "
|
|
154
|
+
domain_name = "%(dns_record)s.${data.aws_route53_zone.selected.name}"
|
|
124
155
|
validation_method = "DNS"
|
|
125
156
|
subject_alternative_names = [data.aws_route53_zone.selected.name]
|
|
126
157
|
|
|
@@ -152,21 +183,23 @@ resource "aws_acm_certificate_validation" "cert" {
|
|
|
152
183
|
certificate_arn = aws_acm_certificate.cert.arn
|
|
153
184
|
validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
|
|
154
185
|
}
|
|
155
|
-
|
|
156
|
-
output "certificate_arn" {
|
|
157
|
-
description = "The ARN of the ACM certificate"
|
|
158
|
-
value = aws_acm_certificate.cert.arn
|
|
159
|
-
}
|
|
160
186
|
"""
|
|
161
187
|
|
|
162
188
|
TERRAFORM_SECOND_TEMPLATE = """
|
|
163
189
|
# Create Route 53 record for the load balancer
|
|
190
|
+
data "aws_alb" "tinybird" {
|
|
191
|
+
name = "%(namespace)s"
|
|
192
|
+
}
|
|
193
|
+
|
|
164
194
|
resource "aws_route53_record" "tinybird" {
|
|
165
195
|
zone_id = data.aws_route53_zone.selected.zone_id
|
|
166
196
|
name = "%(full_dns_name)s"
|
|
167
|
-
type = "
|
|
168
|
-
|
|
169
|
-
|
|
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
|
+
}
|
|
170
203
|
}
|
|
171
204
|
|
|
172
205
|
output "tinybird_dns" {
|
|
@@ -184,46 +217,42 @@ def infra(ctx: Context) -> None:
|
|
|
184
217
|
|
|
185
218
|
@infra.command(name="init")
|
|
186
219
|
@click.option("--name", type=str, help="Name for identifying the self-managed infrastructure in Tinybird")
|
|
187
|
-
@click.option("--provider",
|
|
220
|
+
@click.option("--provider", type=str, help="Infrastructure provider (aws, gcp, azure)")
|
|
188
221
|
@click.option("--region", type=str, help="AWS region (for AWS provider)")
|
|
189
|
-
@click.option("--
|
|
222
|
+
@click.option("--dns-zone-name", type=str, help="DNS zone name")
|
|
190
223
|
@click.option("--namespace", type=str, help="Kubernetes namespace for deployment")
|
|
191
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")
|
|
192
226
|
@click.option(
|
|
193
|
-
"--auto-apply
|
|
194
|
-
)
|
|
195
|
-
@click.option("--auto-apply-dns", is_flag=True, help="Automatically apply DNS configuration without prompting")
|
|
196
|
-
@click.option(
|
|
197
|
-
"--auto-apply-kubectl", is_flag=True, help="Automatically apply Kubernetes configuration without prompting"
|
|
227
|
+
"--auto-apply", is_flag=True, help="Automatically apply Terraform and kubectl configuration without prompting"
|
|
198
228
|
)
|
|
199
|
-
@click.option("--skip-
|
|
200
|
-
@click.option("--skip-kubectl", is_flag=True, help="Skip Kubernetes configuration and application")
|
|
201
|
-
@click.option("--skip-dns", is_flag=True, help="Skip DNS configuration and application")
|
|
229
|
+
@click.option("--skip-apply", is_flag=True, help="Skip Terraform and kubectl configuration and application")
|
|
202
230
|
@click.pass_context
|
|
203
231
|
def infra_init(
|
|
204
232
|
ctx: Context,
|
|
205
233
|
name: str,
|
|
206
234
|
provider: str,
|
|
207
235
|
region: Optional[str] = None,
|
|
208
|
-
|
|
236
|
+
dns_zone_name: Optional[str] = None,
|
|
209
237
|
namespace: Optional[str] = None,
|
|
210
238
|
dns_record: Optional[str] = None,
|
|
211
239
|
storage_class: Optional[str] = None,
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
auto_apply_kubectl: bool = False,
|
|
215
|
-
skip_terraform: bool = False,
|
|
216
|
-
skip_kubectl: bool = False,
|
|
217
|
-
skip_dns: bool = False,
|
|
240
|
+
auto_apply: bool = False,
|
|
241
|
+
skip_apply: bool = False,
|
|
218
242
|
) -> None:
|
|
219
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
|
+
|
|
220
249
|
# AWS-specific Terraform template creation
|
|
221
250
|
if provider.lower() != "aws":
|
|
222
251
|
click.echo("Provider not supported yet.")
|
|
223
252
|
return
|
|
224
253
|
|
|
225
254
|
# Create infra directory if it doesn't exist
|
|
226
|
-
infra_dir = Path("infra")
|
|
255
|
+
infra_dir = Path(f"infra/{provider}")
|
|
227
256
|
infra_dir.mkdir(exist_ok=True)
|
|
228
257
|
yaml_path = infra_dir / "k8s.yaml"
|
|
229
258
|
tf_path = infra_dir / "main.tf"
|
|
@@ -245,7 +274,7 @@ def infra_init(
|
|
|
245
274
|
# Get or prompt for configuration values
|
|
246
275
|
name = name or click.prompt("Enter name", type=str)
|
|
247
276
|
region = region or config.get("region") or click.prompt("Enter aws region", default="us-east-1", type=str)
|
|
248
|
-
|
|
277
|
+
dns_zone_name = dns_zone_name or config.get("dns_zone_name") or click.prompt("Enter DNS zone name", type=str)
|
|
249
278
|
namespace = (
|
|
250
279
|
namespace
|
|
251
280
|
or config.get("namespace")
|
|
@@ -264,7 +293,7 @@ def infra_init(
|
|
|
264
293
|
config = {
|
|
265
294
|
"provider": provider,
|
|
266
295
|
"region": region,
|
|
267
|
-
"
|
|
296
|
+
"dns_zone_name": dns_zone_name,
|
|
268
297
|
"namespace": namespace,
|
|
269
298
|
"dns_record": dns_record,
|
|
270
299
|
"storage_class": storage_class,
|
|
@@ -280,30 +309,48 @@ def infra_init(
|
|
|
280
309
|
user_client = cli_config.get_client(token=cli_config.get_user_token() or "")
|
|
281
310
|
user_workspaces = async_to_sync(user_client.user_workspaces_with_organization)()
|
|
282
311
|
admin_org_id = user_workspaces.get("organization_id")
|
|
312
|
+
admin_org_name = user_workspaces.get("organization_name", "")
|
|
283
313
|
infras = async_to_sync(client.infra_list)(organization_id=admin_org_id)
|
|
284
314
|
infra = next((infra for infra in infras if infra["name"] == name), None)
|
|
285
315
|
if not infra:
|
|
286
316
|
click.echo(FeedbackManager.highlight(message=f"\n» Creating infrastructure '{name}' in Tinybird..."))
|
|
287
|
-
host = f"https://{dns_record}.{
|
|
317
|
+
host = f"https://{dns_record}.{dns_zone_name}"
|
|
288
318
|
infra = async_to_sync(client.infra_create)(organization_id=admin_org_id, name=name, host=host)
|
|
289
319
|
|
|
290
320
|
infra_token = infra["token"]
|
|
291
321
|
|
|
292
322
|
# Write the Terraform template
|
|
293
|
-
terraform_content = TERRAFORM_FIRST_TEMPLATE % {
|
|
323
|
+
terraform_content = TERRAFORM_FIRST_TEMPLATE % {
|
|
324
|
+
"aws_region": region,
|
|
325
|
+
"dns_zone_name": dns_zone_name,
|
|
326
|
+
"dns_record": dns_record,
|
|
327
|
+
}
|
|
294
328
|
|
|
295
329
|
with open(tf_path, "w") as f:
|
|
296
330
|
f.write(terraform_content.lstrip())
|
|
297
331
|
|
|
298
|
-
click.echo(f"
|
|
332
|
+
click.echo(f"Created Terraform configuration in {tf_path}")
|
|
299
333
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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}")
|
|
303
348
|
|
|
349
|
+
# Apply Terraform configuration if user confirms
|
|
350
|
+
if not skip_apply:
|
|
304
351
|
# Initialize Terraform
|
|
305
352
|
click.echo("Initializing Terraform...")
|
|
306
|
-
init_result = subprocess.run(["terraform", "-chdir=
|
|
353
|
+
init_result = subprocess.run(["terraform", f"-chdir={infra_dir}", "init"], capture_output=True, text=True)
|
|
307
354
|
|
|
308
355
|
if init_result.returncode != 0:
|
|
309
356
|
click.echo("Terraform initialization failed:")
|
|
@@ -312,7 +359,7 @@ def infra_init(
|
|
|
312
359
|
|
|
313
360
|
# Run terraform plan first
|
|
314
361
|
click.echo("\nRunning Terraform plan...\n")
|
|
315
|
-
plan_result = subprocess.run(["terraform", "-chdir=
|
|
362
|
+
plan_result = subprocess.run(["terraform", f"-chdir={infra_dir}", "plan"], capture_output=True, text=True)
|
|
316
363
|
|
|
317
364
|
if plan_result.returncode != 0:
|
|
318
365
|
click.echo("Terraform plan failed:")
|
|
@@ -322,10 +369,10 @@ def infra_init(
|
|
|
322
369
|
click.echo(plan_result.stdout)
|
|
323
370
|
|
|
324
371
|
# Apply Terraform configuration if user confirms
|
|
325
|
-
if
|
|
372
|
+
if auto_apply or click.confirm("Would you like to apply the Terraform configuration now?"):
|
|
326
373
|
click.echo("\nApplying Terraform configuration...\n")
|
|
327
374
|
apply_result = subprocess.run(
|
|
328
|
-
["terraform", "-chdir=
|
|
375
|
+
["terraform", f"-chdir={infra_dir}", "apply", "-auto-approve"], capture_output=True, text=True
|
|
329
376
|
)
|
|
330
377
|
|
|
331
378
|
if apply_result.returncode != 0:
|
|
@@ -335,309 +382,133 @@ def infra_init(
|
|
|
335
382
|
|
|
336
383
|
click.echo(apply_result.stdout)
|
|
337
384
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
|
341
392
|
)
|
|
342
393
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
"infra_token": infra_token,
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
with open(yaml_path, "w") as f:
|
|
354
|
-
f.write(new_content.lstrip())
|
|
355
|
-
|
|
356
|
-
click.echo(f"Created Kubernetes configuration with certificate ARN in {yaml_path}")
|
|
357
|
-
|
|
358
|
-
# Prompt to apply the k8s configuration
|
|
359
|
-
if not skip_kubectl and (
|
|
360
|
-
auto_apply_kubectl or click.confirm("Would you like to apply the Kubernetes configuration now?")
|
|
361
|
-
):
|
|
362
|
-
import subprocess
|
|
363
|
-
|
|
364
|
-
# Get current kubectl context
|
|
365
|
-
current_context_result = subprocess.run(
|
|
366
|
-
["kubectl", "config", "current-context"], capture_output=True, text=True
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
current_context = (
|
|
370
|
-
current_context_result.stdout.strip() if current_context_result.returncode == 0 else "unknown"
|
|
371
|
-
)
|
|
372
|
-
|
|
373
|
-
# Get available contexts
|
|
374
|
-
contexts_result = subprocess.run(
|
|
375
|
-
["kubectl", "config", "get-contexts", "-o", "name"], capture_output=True, text=True
|
|
376
|
-
)
|
|
377
|
-
|
|
378
|
-
if contexts_result.returncode != 0:
|
|
379
|
-
click.echo("Failed to get kubectl contexts:")
|
|
380
|
-
click.echo(contexts_result.stderr)
|
|
381
|
-
return
|
|
382
|
-
|
|
383
|
-
available_contexts = [
|
|
384
|
-
context.strip() for context in contexts_result.stdout.splitlines() if context.strip()
|
|
385
|
-
]
|
|
386
|
-
|
|
387
|
-
if not available_contexts:
|
|
388
|
-
click.echo("No kubectl contexts found. Please configure kubectl first.")
|
|
389
|
-
return
|
|
390
|
-
|
|
391
|
-
# Prompt user to select a context
|
|
392
|
-
if len(available_contexts) == 1:
|
|
393
|
-
selected_context = available_contexts[0]
|
|
394
|
-
click.echo(f"Using the only available kubectl context: {selected_context}")
|
|
395
|
-
else:
|
|
396
|
-
click.echo("\nAvailable kubectl contexts:")
|
|
397
|
-
for i, context in enumerate(available_contexts):
|
|
398
|
-
marker = " (current)" if context == current_context else ""
|
|
399
|
-
click.echo(f" {i + 1}. {context}{marker}")
|
|
400
|
-
|
|
401
|
-
click.echo("")
|
|
402
|
-
default_index = (
|
|
403
|
-
available_contexts.index(current_context) + 1
|
|
404
|
-
if current_context in available_contexts
|
|
405
|
-
else 1
|
|
406
|
-
)
|
|
407
|
-
|
|
408
|
-
selected_index = click.prompt(
|
|
409
|
-
"Select kubectl context number to apply configuration",
|
|
410
|
-
type=click.IntRange(1, len(available_contexts)),
|
|
411
|
-
default=default_index,
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
selected_context = available_contexts[selected_index - 1]
|
|
415
|
-
click.echo(f"Selected context: {selected_context}")
|
|
416
|
-
|
|
417
|
-
# Apply the configuration to the selected context
|
|
418
|
-
click.echo(f"Applying Kubernetes configuration to context '{selected_context}'...")
|
|
419
|
-
apply_result = subprocess.run(
|
|
420
|
-
["kubectl", "--context", selected_context, "apply", "-f", str(yaml_path)],
|
|
421
|
-
capture_output=True,
|
|
422
|
-
text=True,
|
|
423
|
-
)
|
|
424
|
-
|
|
425
|
-
if apply_result.returncode != 0:
|
|
426
|
-
click.echo("Failed to apply Kubernetes configuration:")
|
|
427
|
-
click.echo(apply_result.stderr)
|
|
428
|
-
else:
|
|
429
|
-
click.echo("Kubernetes configuration applied successfully:")
|
|
430
|
-
click.echo(apply_result.stdout)
|
|
431
|
-
|
|
432
|
-
# Get the namespace from the applied configuration
|
|
433
|
-
namespace = None
|
|
434
|
-
with open(yaml_path, "r") as f:
|
|
435
|
-
for line in f:
|
|
436
|
-
if "namespace:" in line and not namespace:
|
|
437
|
-
namespace = line.split("namespace:")[1].strip()
|
|
438
|
-
break
|
|
439
|
-
|
|
440
|
-
if not namespace:
|
|
441
|
-
namespace = "tinybird" # Default namespace
|
|
442
|
-
|
|
443
|
-
click.echo(f"\nWaiting for load balancer to be provisioned in namespace '{namespace}'...")
|
|
444
|
-
|
|
445
|
-
# Wait for the load balancer to get an external IP
|
|
446
|
-
max_attempts = 30
|
|
447
|
-
attempt = 0
|
|
448
|
-
external_ip = None
|
|
449
|
-
|
|
450
|
-
while attempt < max_attempts and not external_ip:
|
|
451
|
-
attempt += 1
|
|
452
|
-
|
|
453
|
-
# Get the service details
|
|
454
|
-
get_service_result = subprocess.run(
|
|
455
|
-
[
|
|
456
|
-
"kubectl",
|
|
457
|
-
"--context",
|
|
458
|
-
selected_context,
|
|
459
|
-
"-n",
|
|
460
|
-
namespace,
|
|
461
|
-
"get",
|
|
462
|
-
"service",
|
|
463
|
-
"tinybird",
|
|
464
|
-
"-o",
|
|
465
|
-
"jsonpath='{.status.loadBalancer.ingress[0].hostname}'",
|
|
466
|
-
],
|
|
467
|
-
capture_output=True,
|
|
468
|
-
text=True,
|
|
469
|
-
)
|
|
470
|
-
|
|
471
|
-
if get_service_result.returncode == 0:
|
|
472
|
-
potential_ip = get_service_result.stdout.strip().replace("'", "")
|
|
473
|
-
if potential_ip and potential_ip != "":
|
|
474
|
-
external_ip = potential_ip
|
|
475
|
-
break
|
|
476
|
-
|
|
477
|
-
click.echo(
|
|
478
|
-
f"Attempt {attempt}/{max_attempts}: Load balancer not ready yet, waiting 10 seconds..."
|
|
479
|
-
)
|
|
480
|
-
import time
|
|
481
|
-
|
|
482
|
-
time.sleep(10)
|
|
483
|
-
|
|
484
|
-
if external_ip:
|
|
485
|
-
click.echo("\nLoad balancer provisioned successfully.")
|
|
486
|
-
|
|
487
|
-
# Update the Terraform configuration with the load balancer DNS
|
|
488
|
-
if not skip_dns and domain and tf_path.exists():
|
|
489
|
-
click.echo("\nUpdating Terraform configuration with load balancer DNS...")
|
|
490
|
-
|
|
491
|
-
with open(tf_path, "r") as f:
|
|
492
|
-
tf_content = f.read()
|
|
493
|
-
|
|
494
|
-
# Check if the Route 53 record already exists in the file
|
|
495
|
-
if 'resource "aws_route53_record" "tinybird"' not in tf_content:
|
|
496
|
-
# Create the full DNS name
|
|
497
|
-
full_dns_name = f"{dns_record}.{domain}"
|
|
498
|
-
|
|
499
|
-
# Use in the Terraform template
|
|
500
|
-
route53_record = TERRAFORM_SECOND_TEMPLATE % {
|
|
501
|
-
"external_ip": external_ip,
|
|
502
|
-
"full_dns_name": full_dns_name,
|
|
503
|
-
}
|
|
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
|
+
)
|
|
504
401
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
402
|
+
if contexts_result.returncode != 0:
|
|
403
|
+
click.echo("Failed to get kubectl contexts:")
|
|
404
|
+
click.echo(contexts_result.stderr)
|
|
405
|
+
return
|
|
508
406
|
|
|
509
|
-
|
|
510
|
-
else:
|
|
511
|
-
# Update the existing Route 53 record
|
|
512
|
-
updated_tf = tf_content.replace(
|
|
513
|
-
'records = ["LOAD_BALANCER_DNS_PLACEHOLDER"]', f'records = ["{external_ip}"]'
|
|
514
|
-
)
|
|
407
|
+
available_contexts = [context.strip() for context in contexts_result.stdout.splitlines() if context.strip()]
|
|
515
408
|
|
|
516
|
-
|
|
517
|
-
|
|
409
|
+
if not available_contexts:
|
|
410
|
+
click.echo("No kubectl contexts found. Please configure kubectl first.")
|
|
411
|
+
return
|
|
518
412
|
|
|
519
|
-
|
|
520
|
-
|
|
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
|
+
)
|
|
521
444
|
|
|
522
|
-
|
|
523
|
-
|
|
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)
|
|
524
498
|
|
|
525
|
-
|
|
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")
|
|
526
505
|
|
|
527
|
-
|
|
528
|
-
click.echo("\nRunning Terraform plan for DNS changes...\n")
|
|
529
|
-
plan_result = subprocess.run(
|
|
530
|
-
["terraform", "-chdir=infra", "plan"], capture_output=True, text=True
|
|
531
|
-
)
|
|
506
|
+
click.echo(f"\n🔗 Tinybird is available at: https://{dns_record}.{dns_zone_name}")
|
|
532
507
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
click.echo(plan_result.stderr)
|
|
536
|
-
else:
|
|
537
|
-
click.echo(plan_result.stdout)
|
|
538
|
-
|
|
539
|
-
# Apply the updated Terraform configuration
|
|
540
|
-
if not skip_dns and (
|
|
541
|
-
auto_apply_dns
|
|
542
|
-
or click.confirm("Would you like to create the DNS record in Route 53 now?")
|
|
543
|
-
):
|
|
544
|
-
click.echo("Applying updated Terraform configuration...")
|
|
545
|
-
apply_result = subprocess.run(
|
|
546
|
-
["terraform", "-chdir=infra", "apply", "-auto-approve"],
|
|
547
|
-
capture_output=True,
|
|
548
|
-
text=True,
|
|
549
|
-
)
|
|
550
|
-
|
|
551
|
-
if apply_result.returncode != 0:
|
|
552
|
-
click.echo("Failed to create DNS record:")
|
|
553
|
-
click.echo(apply_result.stderr)
|
|
554
|
-
else:
|
|
555
|
-
click.echo(apply_result.stdout)
|
|
556
|
-
click.echo("DNS record created successfully!")
|
|
557
|
-
|
|
558
|
-
# Get the DNS name from Terraform output
|
|
559
|
-
dns_output = subprocess.run(
|
|
560
|
-
["terraform", "-chdir=infra", "output", "tinybird_dns"],
|
|
561
|
-
capture_output=True,
|
|
562
|
-
text=True,
|
|
563
|
-
)
|
|
564
|
-
|
|
565
|
-
if dns_output.returncode == 0:
|
|
566
|
-
dns_name = dns_output.stdout.strip().replace('"', "")
|
|
567
|
-
click.echo("\nDNS record created successfully!")
|
|
568
|
-
click.echo(
|
|
569
|
-
"\nWaiting up to 5 minutes for HTTPS endpoint to become available..."
|
|
570
|
-
)
|
|
571
|
-
|
|
572
|
-
import time
|
|
573
|
-
|
|
574
|
-
import requests
|
|
575
|
-
|
|
576
|
-
max_attempts = 30 # 30 attempts * 10 seconds = 5 minutes
|
|
577
|
-
attempt = 0
|
|
578
|
-
while attempt < max_attempts:
|
|
579
|
-
attempt += 1
|
|
580
|
-
try:
|
|
581
|
-
response = requests.get(
|
|
582
|
-
f"https://{dns_name}", allow_redirects=False, timeout=5
|
|
583
|
-
)
|
|
584
|
-
response.raise_for_status()
|
|
585
|
-
click.echo("\n✅ HTTPS endpoint is now accessible!")
|
|
586
|
-
break
|
|
587
|
-
except requests.RequestException:
|
|
588
|
-
if attempt == max_attempts:
|
|
589
|
-
click.echo(
|
|
590
|
-
"\n⚠️ HTTPS endpoint not accessible after 5 minutes"
|
|
591
|
-
)
|
|
592
|
-
click.echo(
|
|
593
|
-
" This might be due to DNS propagation or the Load Balancer provisioning delays"
|
|
594
|
-
)
|
|
595
|
-
click.echo(
|
|
596
|
-
" Please try accessing the URL manually in a few minutes"
|
|
597
|
-
)
|
|
598
|
-
else:
|
|
599
|
-
click.echo(
|
|
600
|
-
f"Attempt {attempt}/{max_attempts}: Not ready yet, waiting 10 seconds..."
|
|
601
|
-
)
|
|
602
|
-
time.sleep(10)
|
|
603
|
-
else:
|
|
604
|
-
click.echo(
|
|
605
|
-
f"\nYour Tinybird instance should be available at: https://tinybird.{domain}"
|
|
606
|
-
)
|
|
607
|
-
|
|
608
|
-
# Print a summary with the endpoint URL
|
|
609
|
-
click.echo("\n" + "=" * 60)
|
|
610
|
-
click.echo("DEPLOYMENT SUMMARY".center(60))
|
|
611
|
-
click.echo("=" * 60)
|
|
612
|
-
|
|
613
|
-
if not skip_kubectl and external_ip:
|
|
614
|
-
click.echo(f"✅ Load balancer provisioned: {external_ip}")
|
|
615
|
-
|
|
616
|
-
if not skip_dns and not skip_terraform and domain:
|
|
617
|
-
# Try to get the DNS name from Terraform output
|
|
618
|
-
dns_output = subprocess.run(
|
|
619
|
-
["terraform", "-chdir=infra", "output", "tinybird_dns"], capture_output=True, text=True
|
|
508
|
+
click.echo(
|
|
509
|
+
"\n📌 Note: It may take a few minutes for DNS to propagate and the HTTPS certificate to be fully provisioned."
|
|
620
510
|
)
|
|
621
511
|
|
|
622
|
-
if dns_output.returncode == 0:
|
|
623
|
-
dns_name = dns_output.stdout.strip().replace('"', "")
|
|
624
|
-
click.echo(f"✅ DNS record created: {dns_name}")
|
|
625
|
-
click.echo(f"\n🔗 Tinybird is available at: https://{dns_name}")
|
|
626
|
-
else:
|
|
627
|
-
# Fallback to constructed DNS name
|
|
628
|
-
full_dns_name = f"{dns_record}.{domain}"
|
|
629
|
-
click.echo(f"✅ DNS record created: {full_dns_name}")
|
|
630
|
-
click.echo(f"\n🔗 Tinybird is available at: https://{full_dns_name}")
|
|
631
|
-
elif not skip_kubectl and external_ip:
|
|
632
|
-
click.echo(f"\n🔗 Tinybird is available at: https://{external_ip}")
|
|
633
|
-
if domain:
|
|
634
|
-
click.echo(f"\n📝 Consider creating a DNS record: {dns_record}.{domain} → {external_ip}")
|
|
635
|
-
|
|
636
|
-
click.echo(
|
|
637
|
-
"\n📌 Note: It may take a few minutes for DNS to propagate and the HTTPS certificate to be fully provisioned."
|
|
638
|
-
)
|
|
639
|
-
click.echo("=" * 60)
|
|
640
|
-
|
|
641
512
|
|
|
642
513
|
@infra.command(name="rm")
|
|
643
514
|
@click.argument("name")
|
tinybird/tb/modules/login.py
CHANGED
|
@@ -147,6 +147,7 @@ async def login(host: str, auth_host: str, workspace: str):
|
|
|
147
147
|
response = requests.get( # noqa: ASYNC210
|
|
148
148
|
f"{auth_host}/api/cli-login?{urlencode(params)}",
|
|
149
149
|
)
|
|
150
|
+
|
|
150
151
|
data = response.json()
|
|
151
152
|
cli_config = CLIConfig.get_project_config()
|
|
152
153
|
cli_config.set_token(data.get("workspace_token", ""))
|
tinybird/tb/modules/workspace.py
CHANGED
|
@@ -203,7 +203,7 @@ async def delete_workspace(
|
|
|
203
203
|
client.token = user_token
|
|
204
204
|
|
|
205
205
|
try:
|
|
206
|
-
await client.delete_workspace(workspace_to_delete["id"], confirm_hard_delete)
|
|
206
|
+
await client.delete_workspace(workspace_to_delete["id"], confirm_hard_delete, version="v1")
|
|
207
207
|
click.echo(FeedbackManager.success_workspace_deleted(workspace_name=workspace_to_delete["name"]))
|
|
208
208
|
except Exception as e:
|
|
209
209
|
raise CLIWorkspaceException(FeedbackManager.error_exception(error=str(e)))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
tinybird/__cli__.py,sha256=esPl5QDTzuQgHe5FuxWLm-fURFigGGwjnYLh9GuWUw4,232
|
|
2
|
-
tinybird/client.py,sha256=
|
|
2
|
+
tinybird/client.py,sha256=aDDifEWkVxJcm4WYaw6uUgXhav-e7JUW1N-mgtEjV4A,55087
|
|
3
3
|
tinybird/config.py,sha256=5UP_UZ2Qtlm5aOH5W7SbtN8r7X-8u3-r853joKqU5zs,6072
|
|
4
4
|
tinybird/connectors.py,sha256=7Gjms7b5MAaBFGi3xytsJurCylprONpFcYrzp4Fw2Rc,15241
|
|
5
5
|
tinybird/context.py,sha256=FfqYfrGX_I7PKGTQo93utaKPDNVYWelg4Hsp3evX5wM,1291
|
|
@@ -15,7 +15,7 @@ tinybird/syncasync.py,sha256=IPnOx6lMbf9SNddN1eBtssg8vCLHMt76SuZ6YNYm-Yk,27761
|
|
|
15
15
|
tinybird/tornado_template.py,sha256=jjNVDMnkYFWXflmT8KU_Ssbo5vR8KQq3EJMk5vYgXRw,41959
|
|
16
16
|
tinybird/ch_utils/constants.py,sha256=aYvg2C_WxYWsnqPdZB1ZFoIr8ZY-XjUXYyHKE9Ansj0,3890
|
|
17
17
|
tinybird/ch_utils/engine.py,sha256=BZuPM7MFS7vaEKK5tOMR2bwSAgJudPrJt27uVEwZmTY,40512
|
|
18
|
-
tinybird/tb/__cli__.py,sha256=
|
|
18
|
+
tinybird/tb/__cli__.py,sha256=5rOoJNw0w56lLAZpNCTlWF_nWVfCJL-SxcTE0FJGiG4,252
|
|
19
19
|
tinybird/tb/cli.py,sha256=H_HaZhkimKgkryYXpBjHfY9Qtg-ZORiONU3psDNpzDk,1135
|
|
20
20
|
tinybird/tb/modules/auth.py,sha256=L1IatO2arRSzys3t8px8xVt8uPWUL5EVD0sFzAV_uVU,9022
|
|
21
21
|
tinybird/tb/modules/build.py,sha256=h5drdmDFX8NHts9dA2Zepao7KSgMAl3DZGyFufVZP78,11085
|
|
@@ -32,13 +32,13 @@ tinybird/tb/modules/endpoint.py,sha256=EhVoGAXsFz-83Fiwj1gI-I73iRRvL49d0W81un7hv
|
|
|
32
32
|
tinybird/tb/modules/exceptions.py,sha256=4A2sSjCEqKUMqpP3WI00zouCWW4uLaghXXLZBSw04mY,3363
|
|
33
33
|
tinybird/tb/modules/feedback_manager.py,sha256=7nNiOx7OMebiheLED1r0d75SbuXCNxyBmF4e20rCBNc,69511
|
|
34
34
|
tinybird/tb/modules/fmt.py,sha256=qpf9APqKTKL2uphNgdbj4OMVyLkAxZn6dn4eHF99L5g,3553
|
|
35
|
-
tinybird/tb/modules/infra.py,sha256=
|
|
35
|
+
tinybird/tb/modules/infra.py,sha256=l64FN62AB6N_ICisEonVsI_uQ_hzwZRBvupBjBJKac8,19707
|
|
36
36
|
tinybird/tb/modules/job.py,sha256=956Pj8BEEsiD2GZsV9RKKVM3I_CveOLgS82lykO5ukk,2963
|
|
37
37
|
tinybird/tb/modules/llm.py,sha256=AC0VSphTOM2t-v1_3NLvNN_FIbgMo4dTyMqIv5nniPo,835
|
|
38
38
|
tinybird/tb/modules/llm_utils.py,sha256=nS9r4FAElJw8yXtmdYrx-rtI2zXR8qXfi1QqUDCfxvg,3469
|
|
39
39
|
tinybird/tb/modules/local.py,sha256=revEEYP-Oq5nqURgmZmc0kt1_tEjM31dyUtcH5YbOuc,5842
|
|
40
40
|
tinybird/tb/modules/local_common.py,sha256=RN5OEncHdq7ua4AZ--WgKtaFuEsLvIhq_ROHJadRXXA,3188
|
|
41
|
-
tinybird/tb/modules/login.py,sha256=
|
|
41
|
+
tinybird/tb/modules/login.py,sha256=dAaBBn_ZIQRm9BFl6Uw_HgZa2qoLuAO6mBOxob_17ms,6253
|
|
42
42
|
tinybird/tb/modules/logout.py,sha256=ULooy1cDBD02-r7voZmhV7udA0ML5tVuflJyShrh56Y,1022
|
|
43
43
|
tinybird/tb/modules/materialization.py,sha256=r8Q9HXcYEmfrEzP4WpiasCKDJdSkTPaAKJtZMoJKhi8,5749
|
|
44
44
|
tinybird/tb/modules/mock.py,sha256=9VKlp2bO2NsRgqF03SrFv_8OvAoHeRcOU89TiBRFfqY,3891
|
|
@@ -55,7 +55,7 @@ tinybird/tb/modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09
|
|
|
55
55
|
tinybird/tb/modules/test.py,sha256=FUU-drY8mdjNoKsw16O5ZqvYvZqzycrZBEpSwbhGDUE,11456
|
|
56
56
|
tinybird/tb/modules/token.py,sha256=OhqLFpCHVfYeBCxJ0n7n2qoho9E9eGcUfHgL7R1MUVQ,13485
|
|
57
57
|
tinybird/tb/modules/watch.py,sha256=poNJOUNDESDNn80H2dHvE6X6pIu-t9MZFi59_TxVN2U,8822
|
|
58
|
-
tinybird/tb/modules/workspace.py,sha256=
|
|
58
|
+
tinybird/tb/modules/workspace.py,sha256=GUXSROaPn2LpR2ZTYLIlj-wZnAbiFkib9m3Cag-Kbeg,7791
|
|
59
59
|
tinybird/tb/modules/workspace_members.py,sha256=Vb5XEaKmkfONyfg2MS5EcpwolMvv7GLwFS5m2EuobT8,8726
|
|
60
60
|
tinybird/tb/modules/datafile/build.py,sha256=jhfIJ2xt0N13XsLPe3iMQIyCPApHS13_Df2LfISYtT8,50952
|
|
61
61
|
tinybird/tb/modules/datafile/build_common.py,sha256=rT7VJ5mnQ68R_8US91DAtkusfvjWuG_NObOzNgtN_ko,4562
|
|
@@ -81,8 +81,8 @@ tinybird/tb_cli_modules/config.py,sha256=IsgdtFRnUrkY8-Zo32lmk6O7u3bHie1QCxLwgp4
|
|
|
81
81
|
tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
|
|
82
82
|
tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
|
|
83
83
|
tinybird/tb_cli_modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09K1A,10449
|
|
84
|
-
tinybird-0.0.1.
|
|
85
|
-
tinybird-0.0.1.
|
|
86
|
-
tinybird-0.0.1.
|
|
87
|
-
tinybird-0.0.1.
|
|
88
|
-
tinybird-0.0.1.
|
|
84
|
+
tinybird-0.0.1.dev100.dist-info/METADATA,sha256=QaYp1xwcpo3MDoYY8ZGLSXI9ZHFKCV6I6bk2d9u6hRg,2586
|
|
85
|
+
tinybird-0.0.1.dev100.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
86
|
+
tinybird-0.0.1.dev100.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
|
|
87
|
+
tinybird-0.0.1.dev100.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
|
|
88
|
+
tinybird-0.0.1.dev100.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|