fal 0.11.1__py3-none-any.whl → 0.11.3__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 fal might be problematic. Click here for more details.
- fal/api.py +51 -19
- fal/auth/__init__.py +1 -2
- fal/auth/auth0.py +2 -5
- fal/cli.py +92 -108
- fal/rest_client.py +1 -0
- fal/sdk.py +49 -129
- fal/sync.py +3 -2
- fal/toolkit/file/file.py +6 -5
- fal/toolkit/file/providers/gcp.py +4 -1
- fal/toolkit/file/providers/r2.py +83 -0
- fal/toolkit/file/types.py +1 -1
- fal/toolkit/image/image.py +2 -2
- fal/toolkit/utils/download_utils.py +1 -1
- {fal-0.11.1.dist-info → fal-0.11.3.dist-info}/METADATA +40 -3
- {fal-0.11.1.dist-info → fal-0.11.3.dist-info}/RECORD +58 -44
- openapi_fal_rest/api/admin/get_usage_per_user.py +199 -0
- openapi_fal_rest/api/admin/handle_user_lock.py +6 -2
- openapi_fal_rest/api/applications/get_status_applications_app_user_id_app_alias_or_id_status_get.py +6 -2
- openapi_fal_rest/api/billing/delete_payment_method.py +9 -3
- openapi_fal_rest/api/billing/get_setup_intent_key.py +6 -2
- openapi_fal_rest/api/billing/get_user_price.py +6 -2
- openapi_fal_rest/api/billing/get_user_spending.py +6 -2
- openapi_fal_rest/api/billing/handle_stripe_webhook.py +21 -7
- openapi_fal_rest/api/billing/upcoming_invoice.py +6 -2
- openapi_fal_rest/api/billing/update_customer_budget.py +6 -2
- openapi_fal_rest/api/files/check_dir_hash.py +9 -3
- openapi_fal_rest/api/files/delete.py +6 -2
- openapi_fal_rest/api/files/download.py +6 -2
- openapi_fal_rest/api/files/file_exists.py +6 -2
- openapi_fal_rest/api/files/upload_from_url.py +6 -2
- openapi_fal_rest/api/files/upload_local_file.py +9 -3
- openapi_fal_rest/api/keys/create_key.py +6 -2
- openapi_fal_rest/api/keys/delete_key.py +6 -2
- openapi_fal_rest/api/{usage/get_request_stats_by_time.py → requests/requests.py} +33 -18
- openapi_fal_rest/api/storage/get_file_link.py +200 -0
- openapi_fal_rest/api/storage/initiate_upload.py +172 -0
- openapi_fal_rest/api/tokens/__init__.py +0 -0
- openapi_fal_rest/api/{application/get_status_application_status_user_id_alias_get.py → tokens/create_token.py} +41 -48
- openapi_fal_rest/api/usage/get_gateway_request_stats.py +49 -1
- openapi_fal_rest/api/usage/get_gateway_request_stats_by_time.py +270 -0
- openapi_fal_rest/api/usage/per_machine_usage_details.py +3 -1
- openapi_fal_rest/models/__init__.py +18 -0
- openapi_fal_rest/models/body_create_token.py +68 -0
- openapi_fal_rest/models/body_upload_file.py +4 -1
- openapi_fal_rest/models/body_upload_local_file.py +4 -1
- openapi_fal_rest/models/gateway_stats_by_time.py +27 -27
- openapi_fal_rest/models/gateway_usage_stats.py +58 -31
- openapi_fal_rest/models/get_gateway_request_stats_by_time_response_get_gateway_request_stats_by_time.py +80 -0
- openapi_fal_rest/models/initiate_upload_info.py +64 -0
- openapi_fal_rest/models/presigned_upload_url.py +64 -0
- openapi_fal_rest/models/request_io.py +112 -0
- openapi_fal_rest/models/request_io_json_input.py +43 -0
- openapi_fal_rest/models/request_io_json_output.py +43 -0
- openapi_fal_rest/models/stats_timeframe.py +1 -0
- openapi_fal_rest/models/usage_per_user.py +71 -0
- {fal-0.11.1.dist-info → fal-0.11.3.dist-info}/WHEEL +0 -0
- {fal-0.11.1.dist-info → fal-0.11.3.dist-info}/entry_points.txt +0 -0
- /openapi_fal_rest/api/{application → requests}/__init__.py +0 -0
fal/api.py
CHANGED
|
@@ -31,6 +31,7 @@ from fal._serialization import add_serialization_listeners_for, patch_dill
|
|
|
31
31
|
from fal.logging.isolate import IsolateLogPrinter
|
|
32
32
|
from fal.sdk import (
|
|
33
33
|
FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
34
|
+
FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
34
35
|
Credentials,
|
|
35
36
|
FalServerlessClient,
|
|
36
37
|
FalServerlessConnection,
|
|
@@ -75,9 +76,7 @@ class Host(Generic[ArgsT, ReturnT]):
|
|
|
75
76
|
is executed."""
|
|
76
77
|
|
|
77
78
|
_SUPPORTED_KEYS: ClassVar[frozenset[str]] = frozenset()
|
|
78
|
-
_GATEWAY_KEYS: ClassVar[frozenset[str]] = frozenset(
|
|
79
|
-
{"serve", "exposed_port", "max_concurrency"}
|
|
80
|
-
)
|
|
79
|
+
_GATEWAY_KEYS: ClassVar[frozenset[str]] = frozenset({"serve", "exposed_port"})
|
|
81
80
|
|
|
82
81
|
def __post_init__(self):
|
|
83
82
|
assert not self._SUPPORTED_KEYS.intersection(
|
|
@@ -117,7 +116,6 @@ class Host(Generic[ArgsT, ReturnT]):
|
|
|
117
116
|
self,
|
|
118
117
|
func: Callable[ArgsT, ReturnT],
|
|
119
118
|
options: Options,
|
|
120
|
-
max_concurrency: int | None = None,
|
|
121
119
|
application_name: str | None = None,
|
|
122
120
|
application_auth_mode: Literal["public", "shared", "private"] | None = None,
|
|
123
121
|
metadata: dict[str, Any] | None = None,
|
|
@@ -310,6 +308,8 @@ class FalServerlessHost(Host):
|
|
|
310
308
|
{
|
|
311
309
|
"machine_type",
|
|
312
310
|
"keep_alive",
|
|
311
|
+
"max_concurrency",
|
|
312
|
+
"max_multiplexing",
|
|
313
313
|
"setup_function",
|
|
314
314
|
"metadata",
|
|
315
315
|
"_base_image",
|
|
@@ -339,7 +339,6 @@ class FalServerlessHost(Host):
|
|
|
339
339
|
self,
|
|
340
340
|
func: Callable[ArgsT, ReturnT],
|
|
341
341
|
options: Options,
|
|
342
|
-
max_concurrency: int | None = None,
|
|
343
342
|
application_name: str | None = None,
|
|
344
343
|
application_auth_mode: Literal["public", "shared", "private"] | None = None,
|
|
345
344
|
metadata: dict[str, Any] | None = None,
|
|
@@ -352,6 +351,8 @@ class FalServerlessHost(Host):
|
|
|
352
351
|
"machine_type", FAL_SERVERLESS_DEFAULT_MACHINE_TYPE
|
|
353
352
|
)
|
|
354
353
|
keep_alive = options.host.get("keep_alive", FAL_SERVERLESS_DEFAULT_KEEP_ALIVE)
|
|
354
|
+
max_concurrency = options.host.get("max_concurrency")
|
|
355
|
+
max_multiplexing = options.host.get("max_multiplexing")
|
|
355
356
|
base_image = options.host.get("_base_image", None)
|
|
356
357
|
scheduler = options.host.get("_scheduler", None)
|
|
357
358
|
scheduler_options = options.host.get("_scheduler_options", None)
|
|
@@ -364,6 +365,8 @@ class FalServerlessHost(Host):
|
|
|
364
365
|
exposed_port=exposed_port,
|
|
365
366
|
scheduler=scheduler,
|
|
366
367
|
scheduler_options=scheduler_options,
|
|
368
|
+
max_multiplexing=max_multiplexing,
|
|
369
|
+
max_concurrency=max_concurrency,
|
|
367
370
|
)
|
|
368
371
|
|
|
369
372
|
partial_func = _prepare_partial_func(func)
|
|
@@ -388,7 +391,6 @@ class FalServerlessHost(Host):
|
|
|
388
391
|
application_name=application_name,
|
|
389
392
|
application_auth_mode=application_auth_mode,
|
|
390
393
|
machine_requirements=machine_requirements,
|
|
391
|
-
max_concurrency=max_concurrency,
|
|
392
394
|
metadata=metadata,
|
|
393
395
|
):
|
|
394
396
|
for log in partial_result.logs:
|
|
@@ -397,18 +399,6 @@ class FalServerlessHost(Host):
|
|
|
397
399
|
if partial_result.result:
|
|
398
400
|
return partial_result.result.application_id
|
|
399
401
|
|
|
400
|
-
@_handle_grpc_error()
|
|
401
|
-
def schedule(
|
|
402
|
-
self,
|
|
403
|
-
func: Callable[ArgsT, ReturnT],
|
|
404
|
-
cron: str,
|
|
405
|
-
options: Options,
|
|
406
|
-
) -> str | None:
|
|
407
|
-
application_id = self.register(func, options)
|
|
408
|
-
if application_id is None:
|
|
409
|
-
return None
|
|
410
|
-
return self._connection.schedule_cronjob(application_id, cron)
|
|
411
|
-
|
|
412
402
|
@_handle_grpc_error()
|
|
413
403
|
def run(
|
|
414
404
|
self,
|
|
@@ -425,6 +415,8 @@ class FalServerlessHost(Host):
|
|
|
425
415
|
"machine_type", FAL_SERVERLESS_DEFAULT_MACHINE_TYPE
|
|
426
416
|
)
|
|
427
417
|
keep_alive = options.host.get("keep_alive", FAL_SERVERLESS_DEFAULT_KEEP_ALIVE)
|
|
418
|
+
max_concurrency = options.host.get("max_concurrency")
|
|
419
|
+
max_multiplexing = options.host.get("max_multiplexing")
|
|
428
420
|
base_image = options.host.get("_base_image", None)
|
|
429
421
|
scheduler = options.host.get("_scheduler", None)
|
|
430
422
|
scheduler_options = options.host.get("_scheduler_options", None)
|
|
@@ -438,6 +430,8 @@ class FalServerlessHost(Host):
|
|
|
438
430
|
exposed_port=exposed_port,
|
|
439
431
|
scheduler=scheduler,
|
|
440
432
|
scheduler_options=scheduler_options,
|
|
433
|
+
max_multiplexing=max_multiplexing,
|
|
434
|
+
max_concurrency=max_concurrency,
|
|
441
435
|
)
|
|
442
436
|
|
|
443
437
|
return_value = _UNSET
|
|
@@ -560,6 +554,7 @@ def function(
|
|
|
560
554
|
# FalServerlessHost options
|
|
561
555
|
machine_type: str = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
|
|
562
556
|
keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
557
|
+
max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
563
558
|
setup_function: Callable[..., None] | None = None,
|
|
564
559
|
_base_image: str | None = None,
|
|
565
560
|
_scheduler: str | None = None,
|
|
@@ -583,6 +578,7 @@ def function(
|
|
|
583
578
|
# FalServerlessHost options
|
|
584
579
|
machine_type: str = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
|
|
585
580
|
keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
581
|
+
max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
586
582
|
setup_function: Callable[..., None] | None = None,
|
|
587
583
|
_base_image: str | None = None,
|
|
588
584
|
_scheduler: str | None = None,
|
|
@@ -658,6 +654,7 @@ def function(
|
|
|
658
654
|
# FalServerlessHost options
|
|
659
655
|
machine_type: str = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
|
|
660
656
|
keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
657
|
+
max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
661
658
|
setup_function: Callable[..., None] | None = None,
|
|
662
659
|
_base_image: str | None = None,
|
|
663
660
|
_scheduler: str | None = None,
|
|
@@ -686,6 +683,7 @@ def function(
|
|
|
686
683
|
# FalServerlessHost options
|
|
687
684
|
machine_type: str = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
|
|
688
685
|
keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
|
|
686
|
+
max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
|
|
689
687
|
setup_function: Callable[..., None] | None = None,
|
|
690
688
|
_base_image: str | None = None,
|
|
691
689
|
_scheduler: str | None = None,
|
|
@@ -758,8 +756,42 @@ class ServeWrapper:
|
|
|
758
756
|
run(app, host="0.0.0.0", port=8080)
|
|
759
757
|
|
|
760
758
|
def openapi(self) -> dict[str, Any]:
|
|
759
|
+
"""
|
|
760
|
+
Build the OpenAPI specification for the served function.
|
|
761
|
+
Attach needed metadata for a better integration to fal.
|
|
762
|
+
"""
|
|
761
763
|
app = self.build_app()
|
|
762
|
-
|
|
764
|
+
spec = app.openapi()
|
|
765
|
+
self._mark_order_openapi(spec)
|
|
766
|
+
return spec
|
|
767
|
+
|
|
768
|
+
def _mark_order_openapi(self, spec: dict[str, Any]):
|
|
769
|
+
"""
|
|
770
|
+
Add x-fal-order-* keys to the OpenAPI specification to help the rendering of UI.
|
|
771
|
+
|
|
772
|
+
NOTE: We rely on the fact that fastapi and Python dicts keep the order of properties.
|
|
773
|
+
"""
|
|
774
|
+
|
|
775
|
+
def mark_order(obj: dict[str, Any], key: str):
|
|
776
|
+
obj[f"x-fal-order-{key}"] = list(obj[key].keys())
|
|
777
|
+
|
|
778
|
+
mark_order(spec, "paths")
|
|
779
|
+
|
|
780
|
+
def order_schema_object(schema: dict[str, Any]):
|
|
781
|
+
"""
|
|
782
|
+
Mark the order of properties in the schema object.
|
|
783
|
+
They can have 'allOf', 'properties' or '$ref' key.
|
|
784
|
+
"""
|
|
785
|
+
if "allOf" in schema:
|
|
786
|
+
for sub_schema in schema["allOf"]:
|
|
787
|
+
order_schema_object(sub_schema)
|
|
788
|
+
if "properties" in schema:
|
|
789
|
+
mark_order(schema, "properties")
|
|
790
|
+
|
|
791
|
+
for key in spec["components"].get("schemas") or {}:
|
|
792
|
+
order_schema_object(spec["components"]["schemas"][key])
|
|
793
|
+
|
|
794
|
+
return spec
|
|
763
795
|
|
|
764
796
|
|
|
765
797
|
@dataclass
|
fal/auth/__init__.py
CHANGED
|
@@ -10,8 +10,7 @@ from fal.exceptions.auth import UnauthenticatedException
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def login():
|
|
13
|
-
|
|
14
|
-
token_data = auth0.login(bool(refresh_token))
|
|
13
|
+
token_data = auth0.login()
|
|
15
14
|
with local.lock_token():
|
|
16
15
|
local.save_token(token_data["refresh_token"])
|
|
17
16
|
|
fal/auth/auth0.py
CHANGED
|
@@ -44,7 +44,7 @@ def _open_browser(url: str, code: str | None) -> None:
|
|
|
44
44
|
)
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
def login(
|
|
47
|
+
def login() -> dict:
|
|
48
48
|
"""
|
|
49
49
|
Runs the device authorization flow and stores the user object in memory
|
|
50
50
|
"""
|
|
@@ -64,10 +64,7 @@ def login(logout_first: bool) -> dict:
|
|
|
64
64
|
device_user_code = device_code_data["user_code"]
|
|
65
65
|
device_confirmation_url = device_code_data["verification_uri_complete"]
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
url = logout_url(device_confirmation_url)
|
|
69
|
-
else:
|
|
70
|
-
url = device_confirmation_url
|
|
67
|
+
url = logout_url(device_confirmation_url)
|
|
71
68
|
|
|
72
69
|
_open_browser(url, device_user_code)
|
|
73
70
|
|
fal/cli.py
CHANGED
|
@@ -10,8 +10,6 @@ from uuid import uuid4
|
|
|
10
10
|
import click
|
|
11
11
|
import fal.auth as auth
|
|
12
12
|
import grpc
|
|
13
|
-
import openapi_fal_rest.api.billing.get_user_details as get_user_details
|
|
14
|
-
import openapi_fal_rest.api.logs.list_since as list_logs
|
|
15
13
|
from fal import api, sdk
|
|
16
14
|
from fal.console import console
|
|
17
15
|
from fal.exceptions import ApplicationExceptionHandler
|
|
@@ -19,10 +17,13 @@ from fal.logging import get_logger, set_debug_logging
|
|
|
19
17
|
from fal.logging.isolate import IsolateLogPrinter
|
|
20
18
|
from fal.logging.trace import get_tracer
|
|
21
19
|
from fal.rest_client import REST_CLIENT
|
|
22
|
-
from fal.sdk import KeyScope
|
|
20
|
+
from fal.sdk import AliasInfo, KeyScope
|
|
23
21
|
from isolate.logs import Log, LogLevel, LogSource
|
|
24
22
|
from rich.table import Table
|
|
25
23
|
|
|
24
|
+
import openapi_fal_rest.api.billing.get_user_details as get_user_details
|
|
25
|
+
import openapi_fal_rest.api.logs.list_since as list_logs
|
|
26
|
+
|
|
26
27
|
DEFAULT_HOST = "api.alpha.fal.ai"
|
|
27
28
|
HOST_ENVVAR = "FAL_HOST"
|
|
28
29
|
|
|
@@ -231,6 +232,10 @@ def key_revoke(client: sdk.FalServerlessClient, key_id: str):
|
|
|
231
232
|
|
|
232
233
|
|
|
233
234
|
##### Function group #####
|
|
235
|
+
ALIAS_AUTH_OPTIONS = ["public", "private", "shared"]
|
|
236
|
+
ALIAS_AUTH_TYPE = Literal["public", "private", "shared"]
|
|
237
|
+
|
|
238
|
+
|
|
234
239
|
@click.group
|
|
235
240
|
@click.option("--host", default=DEFAULT_HOST, envvar=HOST_ENVVAR)
|
|
236
241
|
@click.option("--port", default=DEFAULT_PORT, envvar=PORT_ENVVAR, hidden=True)
|
|
@@ -244,7 +249,7 @@ def function_cli(ctx, host: str, port: str):
|
|
|
244
249
|
@click.option(
|
|
245
250
|
"--auth",
|
|
246
251
|
"auth_mode",
|
|
247
|
-
type=click.Choice(
|
|
252
|
+
type=click.Choice(ALIAS_AUTH_OPTIONS),
|
|
248
253
|
default="private",
|
|
249
254
|
)
|
|
250
255
|
@click.argument("file_path", required=True)
|
|
@@ -255,7 +260,7 @@ def register_application(
|
|
|
255
260
|
file_path: str,
|
|
256
261
|
function_name: str,
|
|
257
262
|
alias: str | None,
|
|
258
|
-
auth_mode:
|
|
263
|
+
auth_mode: ALIAS_AUTH_TYPE,
|
|
259
264
|
):
|
|
260
265
|
import runpy
|
|
261
266
|
|
|
@@ -279,13 +284,11 @@ def register_application(
|
|
|
279
284
|
"Must expose port 8080 for now. This will be configurable in the future."
|
|
280
285
|
)
|
|
281
286
|
|
|
282
|
-
max_concurrency = gateway_options.get("max_concurrency")
|
|
283
287
|
id = host.register(
|
|
284
288
|
func=isolated_function.func,
|
|
285
289
|
options=isolated_function.options,
|
|
286
290
|
application_name=alias,
|
|
287
291
|
application_auth_mode=auth_mode,
|
|
288
|
-
max_concurrency=max_concurrency,
|
|
289
292
|
metadata={},
|
|
290
293
|
)
|
|
291
294
|
|
|
@@ -304,26 +307,6 @@ def register_application(
|
|
|
304
307
|
console.print(f"URL: https://{user_id}-{id}.{gateway_host}")
|
|
305
308
|
|
|
306
309
|
|
|
307
|
-
@function_cli.command("schedule")
|
|
308
|
-
@click.argument("cron_string", required=True)
|
|
309
|
-
@click.argument("file_path", required=True)
|
|
310
|
-
@click.argument("function_name", required=True)
|
|
311
|
-
@click.pass_obj
|
|
312
|
-
def register_schedulded(
|
|
313
|
-
host: api.FalServerlessHost, cron_string: str, file_path: str, function_name: str
|
|
314
|
-
):
|
|
315
|
-
import runpy
|
|
316
|
-
|
|
317
|
-
module = runpy.run_path(file_path)
|
|
318
|
-
isolated_function = module[function_name]
|
|
319
|
-
|
|
320
|
-
cron_id = host.schedule(
|
|
321
|
-
func=isolated_function.func, cron=cron_string, options=isolated_function.options
|
|
322
|
-
)
|
|
323
|
-
if cron_id:
|
|
324
|
-
console.print(cron_id)
|
|
325
|
-
|
|
326
|
-
|
|
327
310
|
@function_cli.command("logs")
|
|
328
311
|
@click.option("--lines", default=100)
|
|
329
312
|
@click.option("--url", default=None)
|
|
@@ -361,115 +344,116 @@ def alias_cli(ctx, host: str, port: str):
|
|
|
361
344
|
ctx.obj = api.FalServerlessClient(f"{host}:{port}")
|
|
362
345
|
|
|
363
346
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
table.add_column("Max Concurrency")
|
|
347
|
+
def _alias_table(aliases: list[AliasInfo]):
|
|
348
|
+
table = Table(title="Function Aliases")
|
|
349
|
+
table.add_column("Alias")
|
|
350
|
+
table.add_column("Revision")
|
|
351
|
+
table.add_column("Auth")
|
|
352
|
+
table.add_column("Max Concurrency")
|
|
353
|
+
table.add_column("Max Multiplexing")
|
|
354
|
+
table.add_column("Keep Alive")
|
|
373
355
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
)
|
|
356
|
+
for app_alias in aliases:
|
|
357
|
+
table.add_row(
|
|
358
|
+
app_alias.alias,
|
|
359
|
+
app_alias.revision,
|
|
360
|
+
app_alias.auth_mode,
|
|
361
|
+
str(app_alias.max_concurrency),
|
|
362
|
+
str(app_alias.max_multiplexing),
|
|
363
|
+
str(app_alias.keep_alive),
|
|
364
|
+
)
|
|
381
365
|
|
|
382
|
-
|
|
366
|
+
return table
|
|
383
367
|
|
|
384
368
|
|
|
385
|
-
@alias_cli.command("
|
|
369
|
+
@alias_cli.command("set")
|
|
386
370
|
@click.argument("alias", required=True)
|
|
387
|
-
@click.argument("
|
|
371
|
+
@click.argument("revision", required=True)
|
|
372
|
+
@click.option(
|
|
373
|
+
"--auth",
|
|
374
|
+
"auth_mode",
|
|
375
|
+
type=click.Choice(ALIAS_AUTH_OPTIONS),
|
|
376
|
+
default="private",
|
|
377
|
+
)
|
|
388
378
|
@click.pass_obj
|
|
389
|
-
def
|
|
379
|
+
def alias_set(
|
|
380
|
+
client: api.FalServerlessClient,
|
|
381
|
+
alias: str,
|
|
382
|
+
revision: str,
|
|
383
|
+
auth_mode: ALIAS_AUTH_TYPE,
|
|
384
|
+
):
|
|
390
385
|
with client.connect() as connection:
|
|
391
|
-
connection.
|
|
386
|
+
connection.create_alias(alias, revision, auth_mode)
|
|
392
387
|
|
|
393
388
|
|
|
394
|
-
@alias_cli.command("
|
|
389
|
+
@alias_cli.command("delete")
|
|
395
390
|
@click.argument("alias", required=True)
|
|
396
|
-
@click.option("--keep-alive", type=int)
|
|
397
391
|
@click.pass_obj
|
|
398
|
-
def
|
|
392
|
+
def alias_delete(client: api.FalServerlessClient, alias: str):
|
|
399
393
|
with client.connect() as connection:
|
|
400
|
-
|
|
401
|
-
console.log("No parameters for update were provided, ignoring.")
|
|
402
|
-
return
|
|
394
|
+
application_id = connection.delete_alias(alias)
|
|
403
395
|
|
|
404
|
-
|
|
396
|
+
console.print(f"Deleted alias '{alias}' for application '{application_id}'.")
|
|
405
397
|
|
|
406
398
|
|
|
407
|
-
|
|
408
|
-
@click.group
|
|
409
|
-
@click.option("--host", default=DEFAULT_HOST, envvar=HOST_ENVVAR)
|
|
410
|
-
@click.option("--port", default=DEFAULT_PORT, envvar=PORT_ENVVAR, hidden=True)
|
|
411
|
-
@click.pass_context
|
|
412
|
-
def crons_cli(ctx, host: str, port: str):
|
|
413
|
-
ctx.obj = api.FalServerlessHost(f"{host}:{port}")
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
@crons_cli.command(name="list")
|
|
399
|
+
@alias_cli.command("list")
|
|
417
400
|
@click.pass_obj
|
|
418
|
-
def
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
table.add_column("ETA next run")
|
|
423
|
-
table.add_column("State")
|
|
424
|
-
for cron in host._connection.list_scheduled_runs():
|
|
425
|
-
state_string = ["Not Active", "Active"][cron.active]
|
|
426
|
-
table.add_row(cron.cron_id, cron.cron_string, str(cron.next_run), state_string)
|
|
401
|
+
def alias_list(client: api.FalServerlessClient):
|
|
402
|
+
with client.connect() as connection:
|
|
403
|
+
aliases = connection.list_aliases()
|
|
404
|
+
table = _alias_table(aliases)
|
|
427
405
|
|
|
428
406
|
console.print(table)
|
|
429
407
|
|
|
430
408
|
|
|
431
|
-
@
|
|
432
|
-
@click.argument("
|
|
433
|
-
@click.
|
|
409
|
+
@alias_cli.command("update")
|
|
410
|
+
@click.argument("alias", required=True)
|
|
411
|
+
@click.option("--keep-alive", "-k", type=int)
|
|
412
|
+
@click.option("--max-multiplexing", "-m", type=int)
|
|
413
|
+
@click.option("--max-concurrency", "-c", type=int)
|
|
414
|
+
# TODO: add auth_mode
|
|
415
|
+
# @click.option(
|
|
416
|
+
# "--auth",
|
|
417
|
+
# "auth_mode",
|
|
418
|
+
# type=click.Choice(ALIAS_AUTH_OPTIONS),
|
|
419
|
+
# )
|
|
434
420
|
@click.pass_obj
|
|
435
|
-
def
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
421
|
+
def alias_update(
|
|
422
|
+
client: api.FalServerlessClient,
|
|
423
|
+
alias: str,
|
|
424
|
+
keep_alive: int | None,
|
|
425
|
+
max_multiplexing: int | None,
|
|
426
|
+
max_concurrency: int | None,
|
|
427
|
+
):
|
|
428
|
+
with client.connect() as connection:
|
|
429
|
+
if keep_alive is None and max_multiplexing is None and max_concurrency is None:
|
|
430
|
+
console.log("No parameters for update were provided, ignoring.")
|
|
431
|
+
return
|
|
440
432
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
433
|
+
alias_info = connection.update_application(
|
|
434
|
+
application_name=alias,
|
|
435
|
+
keep_alive=keep_alive,
|
|
436
|
+
max_multiplexing=max_multiplexing,
|
|
437
|
+
max_concurrency=max_concurrency,
|
|
446
438
|
)
|
|
439
|
+
table = _alias_table([alias_info])
|
|
447
440
|
|
|
448
441
|
console.print(table)
|
|
449
442
|
|
|
450
443
|
|
|
451
|
-
@
|
|
452
|
-
@click.argument("
|
|
453
|
-
@click.argument("
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
for log in logs:
|
|
462
|
-
log_printer.print(log)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
@crons_cli.command("cancel")
|
|
466
|
-
@click.argument("cron_id", required=True)
|
|
467
|
-
@click.pass_obj
|
|
468
|
-
def cancel_scheduled(host: api.FalServerlessHost, cron_id: str):
|
|
469
|
-
host._connection.cancel_scheduled_run(cron_id)
|
|
470
|
-
console.print("Cancelled", repr(cron_id))
|
|
444
|
+
@alias_cli.command("scale")
|
|
445
|
+
@click.argument("alias", required=True)
|
|
446
|
+
@click.argument("max_concurrency", required=True, type=int)
|
|
447
|
+
def alias_scale(alias: str, max_concurrency: int):
|
|
448
|
+
alias_update.callback(
|
|
449
|
+
alias=alias,
|
|
450
|
+
keep_alive=None,
|
|
451
|
+
max_multiplexing=None,
|
|
452
|
+
max_concurrency=max_concurrency,
|
|
453
|
+
) # type: ignore
|
|
471
454
|
|
|
472
455
|
|
|
456
|
+
##### Secrets group #####
|
|
473
457
|
@click.group
|
|
474
458
|
@click.option("--host", default=DEFAULT_HOST, envvar=HOST_ENVVAR)
|
|
475
459
|
@click.option("--port", default=DEFAULT_PORT, envvar=PORT_ENVVAR, hidden=True)
|
|
@@ -511,11 +495,11 @@ def delete_secret(client: api.FalServerlessClient, secret_name: str):
|
|
|
511
495
|
console.print(f"Secret '{secret_name}' has deleted")
|
|
512
496
|
|
|
513
497
|
|
|
498
|
+
# Setup of groups
|
|
514
499
|
cli.add_command(auth_cli, name="auth")
|
|
515
500
|
cli.add_command(key_cli, name="key", aliases=["keys"])
|
|
516
501
|
cli.add_command(function_cli, name="function", aliases=["fn"])
|
|
517
502
|
cli.add_command(alias_cli, name="alias", aliases=["aliases"])
|
|
518
|
-
cli.add_command(crons_cli, name="cron", aliases=["crons"])
|
|
519
503
|
cli.add_command(secrets_cli, name="secret", aliases=["secrets"])
|
|
520
504
|
|
|
521
505
|
|