lightning-sdk 2025.8.18__py3-none-any.whl → 2025.8.19.post0__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.
- lightning_sdk/__init__.py +1 -1
- lightning_sdk/api/cloud_account_api.py +5 -0
- lightning_sdk/api/studio_api.py +14 -36
- lightning_sdk/api/utils.py +108 -18
- lightning_sdk/cli/config/get.py +16 -0
- lightning_sdk/cli/config/set.py +27 -0
- lightning_sdk/cli/studio/create.py +16 -1
- lightning_sdk/cli/studio/start.py +20 -2
- lightning_sdk/lightning_cloud/openapi/__init__.py +1 -0
- lightning_sdk/lightning_cloud/openapi/api/k8_s_cluster_service_api.py +113 -0
- lightning_sdk/lightning_cloud/openapi/models/__init__.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/id_codeconfig_body.py +3 -81
- lightning_sdk/lightning_cloud/openapi/models/orgs_id_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/project_id_storage_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/storage_complete_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/uploads_upload_id_body1.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_metrics.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_list_aggregated_pod_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_node_metrics.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_update_cloud_space_instance_config_request.py +3 -81
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +1 -105
- lightning_sdk/studio.py +0 -1
- lightning_sdk/utils/config.py +3 -0
- lightning_sdk/utils/resolve.py +12 -0
- {lightning_sdk-2025.8.18.dist-info → lightning_sdk-2025.8.19.post0.dist-info}/METADATA +1 -1
- {lightning_sdk-2025.8.18.dist-info → lightning_sdk-2025.8.19.post0.dist-info}/RECORD +31 -30
- {lightning_sdk-2025.8.18.dist-info → lightning_sdk-2025.8.19.post0.dist-info}/LICENSE +0 -0
- {lightning_sdk-2025.8.18.dist-info → lightning_sdk-2025.8.19.post0.dist-info}/WHEEL +0 -0
- {lightning_sdk-2025.8.18.dist-info → lightning_sdk-2025.8.19.post0.dist-info}/entry_points.txt +0 -0
- {lightning_sdk-2025.8.18.dist-info → lightning_sdk-2025.8.19.post0.dist-info}/top_level.txt +0 -0
lightning_sdk/__init__.py
CHANGED
|
@@ -181,6 +181,11 @@ class CloudAccountApi:
|
|
|
181
181
|
cloud_provider: Optional[Union["CloudProvider", str]],
|
|
182
182
|
default_cloud_account: Optional[str],
|
|
183
183
|
) -> Optional[str]:
|
|
184
|
+
from lightning_sdk.machine import CloudProvider
|
|
185
|
+
|
|
186
|
+
if cloud_provider and not isinstance(cloud_provider, CloudProvider):
|
|
187
|
+
cloud_provider = CloudProvider(cloud_provider)
|
|
188
|
+
|
|
184
189
|
if cloud_account:
|
|
185
190
|
if cloud_provider:
|
|
186
191
|
cloud_account_resp = self.get_cloud_account_non_org(teamspace_id, cloud_account)
|
lightning_sdk/api/studio_api.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
-
import tempfile
|
|
4
3
|
import time
|
|
5
|
-
import
|
|
4
|
+
from pathlib import Path
|
|
6
5
|
from threading import Event, Thread
|
|
7
6
|
from typing import Any, Dict, Generator, List, Mapping, Optional, Tuple, Union
|
|
8
7
|
|
|
@@ -12,6 +11,7 @@ from tqdm import tqdm
|
|
|
12
11
|
|
|
13
12
|
from lightning_sdk.api.utils import (
|
|
14
13
|
_create_app,
|
|
14
|
+
_download_studio_files,
|
|
15
15
|
_DummyBody,
|
|
16
16
|
_DummyResponse,
|
|
17
17
|
_FileUploader,
|
|
@@ -569,46 +569,24 @@ class StudioApi:
|
|
|
569
569
|
progress_bar: bool = True,
|
|
570
570
|
) -> None:
|
|
571
571
|
"""Downloads a given folder from a Studio to a target location."""
|
|
572
|
-
# TODO:
|
|
572
|
+
# TODO: implement resumable downloads
|
|
573
573
|
auth = Auth()
|
|
574
574
|
auth.authenticate()
|
|
575
|
-
token = self._client.auth_service_login(V1LoginRequest(auth.api_key)).token
|
|
576
575
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
"
|
|
581
|
-
}
|
|
576
|
+
prefix = _sanitize_studio_remote_path(path, studio_id)
|
|
577
|
+
# ensure we only download as a directory and not the entire prefix
|
|
578
|
+
if prefix.endswith("/") is False:
|
|
579
|
+
prefix = prefix + "/"
|
|
582
580
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
581
|
+
_download_studio_files(
|
|
582
|
+
client=self._client,
|
|
583
|
+
teamspace_id=teamspace_id,
|
|
584
|
+
cluster_id=cloud_account,
|
|
585
|
+
prefix=prefix,
|
|
586
|
+
download_dir=Path(target_path),
|
|
587
|
+
progress_bar=progress_bar,
|
|
587
588
|
)
|
|
588
589
|
|
|
589
|
-
if progress_bar:
|
|
590
|
-
pbar = tqdm(
|
|
591
|
-
desc=f"Downloading {os.path.split(path)[1]}",
|
|
592
|
-
unit="B",
|
|
593
|
-
unit_scale=True,
|
|
594
|
-
unit_divisor=1000,
|
|
595
|
-
)
|
|
596
|
-
|
|
597
|
-
pbar_update = pbar.update
|
|
598
|
-
else:
|
|
599
|
-
pbar_update = lambda x: None
|
|
600
|
-
|
|
601
|
-
if target_path:
|
|
602
|
-
os.makedirs(target_path, exist_ok=True)
|
|
603
|
-
|
|
604
|
-
with tempfile.TemporaryFile() as f:
|
|
605
|
-
for chunk in r.iter_content(chunk_size=4096 * 8):
|
|
606
|
-
f.write(chunk)
|
|
607
|
-
pbar_update(len(chunk))
|
|
608
|
-
|
|
609
|
-
with zipfile.ZipFile(f) as z:
|
|
610
|
-
z.extractall(target_path)
|
|
611
|
-
|
|
612
590
|
def install_plugin(self, studio_id: str, teamspace_id: str, plugin_name: str) -> str:
|
|
613
591
|
"""Installs the given plugin."""
|
|
614
592
|
resp: V1Plugin = self._client.cloud_space_service_install_plugin(
|
lightning_sdk/api/utils.py
CHANGED
|
@@ -6,7 +6,7 @@ import re
|
|
|
6
6
|
from concurrent.futures import ThreadPoolExecutor
|
|
7
7
|
from functools import partial
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
9
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, TypedDict, Union
|
|
10
10
|
|
|
11
11
|
import backoff
|
|
12
12
|
import requests
|
|
@@ -19,6 +19,7 @@ from lightning_sdk.lightning_cloud.openapi import (
|
|
|
19
19
|
ModelsStoreApi,
|
|
20
20
|
ProjectIdStorageBody,
|
|
21
21
|
StorageCompleteBody,
|
|
22
|
+
StorageServiceApi,
|
|
22
23
|
UploadIdCompleteBody,
|
|
23
24
|
UploadIdPartsBody,
|
|
24
25
|
V1CompletedPart,
|
|
@@ -367,38 +368,40 @@ _DOWNLOAD_REQUEST_CHUNK_SIZE = 10 * _BYTES_PER_MB
|
|
|
367
368
|
_DOWNLOAD_MIN_CHUNK_SIZE = 100 * _BYTES_PER_KB
|
|
368
369
|
|
|
369
370
|
|
|
371
|
+
class _RefreshResponse(TypedDict):
|
|
372
|
+
url: str
|
|
373
|
+
size: int
|
|
374
|
+
|
|
375
|
+
|
|
370
376
|
class _FileDownloader:
|
|
371
377
|
def __init__(
|
|
372
378
|
self,
|
|
373
|
-
client: LightningClient,
|
|
374
|
-
model_id: str,
|
|
375
|
-
version: str,
|
|
376
379
|
teamspace_id: str,
|
|
377
380
|
remote_path: str,
|
|
378
381
|
file_path: str,
|
|
379
382
|
executor: ThreadPoolExecutor,
|
|
380
383
|
num_workers: int = 20,
|
|
381
384
|
progress_bar: Optional[tqdm] = None,
|
|
385
|
+
url: Optional[str] = None,
|
|
386
|
+
size: Optional[int] = None,
|
|
387
|
+
refresh_fn: Optional[Callable[[], _RefreshResponse]] = None,
|
|
382
388
|
) -> None:
|
|
383
|
-
self.api = ModelsStoreApi(client.api_client)
|
|
384
|
-
self.model_id = model_id
|
|
385
|
-
self.version = version
|
|
386
389
|
self.teamspace_id = teamspace_id
|
|
387
390
|
self.local_path = file_path
|
|
388
391
|
self.remote_path = remote_path
|
|
389
392
|
self.progress_bar = progress_bar
|
|
390
393
|
self.num_workers = num_workers
|
|
391
|
-
self._url =
|
|
392
|
-
self._size =
|
|
394
|
+
self._url = url
|
|
395
|
+
self._size = size
|
|
393
396
|
self.executor = executor
|
|
397
|
+
self.refresh_fn = refresh_fn
|
|
394
398
|
|
|
395
399
|
@backoff.on_exception(backoff.expo, ApiException, max_tries=10)
|
|
396
400
|
def refresh(self) -> None:
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
self._size = int(response.size)
|
|
401
|
+
if self.refresh_fn is not None:
|
|
402
|
+
response = self.refresh_fn()
|
|
403
|
+
self._url = response["url"]
|
|
404
|
+
self._size = response["size"]
|
|
402
405
|
|
|
403
406
|
@property
|
|
404
407
|
def url(self) -> str:
|
|
@@ -413,6 +416,11 @@ class _FileDownloader:
|
|
|
413
416
|
return
|
|
414
417
|
self.progress_bar.update(n)
|
|
415
418
|
|
|
419
|
+
def update_filename(self, desc: str) -> None:
|
|
420
|
+
if self.progress_bar is None:
|
|
421
|
+
return
|
|
422
|
+
self.progress_bar.set_description(f"{(desc[:72] + '...') if len(desc) > 75 else desc:<75.75}")
|
|
423
|
+
|
|
416
424
|
@backoff.on_exception(backoff.expo, (requests.exceptions.HTTPError), max_tries=10)
|
|
417
425
|
def _download_chunk(self, filename: str, start_end: Tuple[int]) -> None:
|
|
418
426
|
start, end = start_end
|
|
@@ -447,6 +455,8 @@ class _FileDownloader:
|
|
|
447
455
|
f.write(b"\x00" * remaining_size)
|
|
448
456
|
|
|
449
457
|
def _multipart_download(self, filename: str, num_workers: int) -> None:
|
|
458
|
+
self.update_filename(f"Downloading {self.remote_path}")
|
|
459
|
+
|
|
450
460
|
num_chunks = num_workers
|
|
451
461
|
chunk_size = math.ceil(self.size / num_chunks)
|
|
452
462
|
|
|
@@ -464,7 +474,8 @@ class _FileDownloader:
|
|
|
464
474
|
concurrent.futures.wait(futures)
|
|
465
475
|
|
|
466
476
|
def download(self) -> None:
|
|
467
|
-
self.
|
|
477
|
+
if self.url is None:
|
|
478
|
+
self.refresh()
|
|
468
479
|
|
|
469
480
|
tmp_filename = f"{self.local_path}.download"
|
|
470
481
|
|
|
@@ -539,6 +550,15 @@ def _download_model_files(
|
|
|
539
550
|
mininterval=1,
|
|
540
551
|
)
|
|
541
552
|
|
|
553
|
+
def refresh_fn(filename: str) -> _RefreshResponse:
|
|
554
|
+
resp = api.models_store_get_model_file_url(
|
|
555
|
+
project_id=response.project_id,
|
|
556
|
+
model_id=response.model_id,
|
|
557
|
+
version=response.version,
|
|
558
|
+
filepath=filename,
|
|
559
|
+
)
|
|
560
|
+
return {"url": resp.url, "size": int(resp.size)}
|
|
561
|
+
|
|
542
562
|
with ThreadPoolExecutor(max_workers=min(num_workers, len(response.filepaths))) as file_executor, ThreadPoolExecutor(
|
|
543
563
|
max_workers=num_workers
|
|
544
564
|
) as part_executor:
|
|
@@ -549,15 +569,13 @@ def _download_model_files(
|
|
|
549
569
|
local_file.parent.mkdir(parents=True, exist_ok=True)
|
|
550
570
|
|
|
551
571
|
file_downloader = _FileDownloader(
|
|
552
|
-
client=client,
|
|
553
|
-
model_id=response.model_id,
|
|
554
|
-
version=response.version,
|
|
555
572
|
teamspace_id=response.project_id,
|
|
556
573
|
remote_path=filepath,
|
|
557
574
|
file_path=str(local_file),
|
|
558
575
|
num_workers=num_workers,
|
|
559
576
|
progress_bar=pbar,
|
|
560
577
|
executor=part_executor,
|
|
578
|
+
refresh_fn=lambda f=filepath: refresh_fn(f),
|
|
561
579
|
)
|
|
562
580
|
|
|
563
581
|
futures.append(file_executor.submit(file_downloader.download))
|
|
@@ -568,6 +586,78 @@ def _download_model_files(
|
|
|
568
586
|
return response.filepaths
|
|
569
587
|
|
|
570
588
|
|
|
589
|
+
def _download_studio_files(
|
|
590
|
+
client: LightningClient,
|
|
591
|
+
teamspace_id: str,
|
|
592
|
+
cluster_id: str,
|
|
593
|
+
prefix: str,
|
|
594
|
+
download_dir: Path,
|
|
595
|
+
progress_bar: bool,
|
|
596
|
+
num_workers: int = os.cpu_count() * 4,
|
|
597
|
+
) -> None:
|
|
598
|
+
api = StorageServiceApi(client.api_client)
|
|
599
|
+
response = None
|
|
600
|
+
|
|
601
|
+
pbar = None
|
|
602
|
+
if progress_bar:
|
|
603
|
+
pbar = tqdm(
|
|
604
|
+
desc="Downloading files",
|
|
605
|
+
unit="B",
|
|
606
|
+
unit_scale=True,
|
|
607
|
+
unit_divisor=1000,
|
|
608
|
+
position=-1,
|
|
609
|
+
mininterval=1,
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
def refresh_fn(filename: str) -> _RefreshResponse:
|
|
613
|
+
resp = api.storage_service_list_project_artifacts(
|
|
614
|
+
project_id=teamspace_id,
|
|
615
|
+
cluster_id=cluster_id,
|
|
616
|
+
page_token="",
|
|
617
|
+
include_download_url=True,
|
|
618
|
+
prefix=prefix + filename,
|
|
619
|
+
page_size=1,
|
|
620
|
+
)
|
|
621
|
+
return {"url": resp.artifacts[0].url, "size": int(resp.artifacts[0].size_bytes)}
|
|
622
|
+
|
|
623
|
+
with ThreadPoolExecutor(max_workers=num_workers) as file_executor, ThreadPoolExecutor(
|
|
624
|
+
max_workers=num_workers
|
|
625
|
+
) as part_executor:
|
|
626
|
+
while response is None or (response is not None and response.next_page_token != ""):
|
|
627
|
+
response = api.storage_service_list_project_artifacts(
|
|
628
|
+
project_id=teamspace_id,
|
|
629
|
+
cluster_id=cluster_id,
|
|
630
|
+
page_token=response.next_page_token if response is not None else "",
|
|
631
|
+
include_download_url=True,
|
|
632
|
+
prefix=prefix,
|
|
633
|
+
page_size=1000,
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
page_futures = []
|
|
637
|
+
for file in response.artifacts:
|
|
638
|
+
local_file = download_dir / file.filename
|
|
639
|
+
local_file.parent.mkdir(parents=True, exist_ok=True)
|
|
640
|
+
|
|
641
|
+
file_downloader = _FileDownloader(
|
|
642
|
+
teamspace_id=teamspace_id,
|
|
643
|
+
remote_path=file.filename,
|
|
644
|
+
file_path=str(local_file),
|
|
645
|
+
num_workers=num_workers,
|
|
646
|
+
progress_bar=pbar,
|
|
647
|
+
executor=part_executor,
|
|
648
|
+
url=file.url,
|
|
649
|
+
size=int(file.size_bytes),
|
|
650
|
+
refresh_fn=lambda f=file: refresh_fn(f.filename),
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
page_futures.append(file_executor.submit(file_downloader.download))
|
|
654
|
+
|
|
655
|
+
if page_futures:
|
|
656
|
+
concurrent.futures.wait(page_futures)
|
|
657
|
+
|
|
658
|
+
pbar.set_description("Download complete")
|
|
659
|
+
|
|
660
|
+
|
|
571
661
|
def _create_app(
|
|
572
662
|
client: CloudSpaceServiceApi,
|
|
573
663
|
studio_id: str,
|
lightning_sdk/cli/config/get.py
CHANGED
|
@@ -39,3 +39,19 @@ def get_studio() -> None:
|
|
|
39
39
|
config = Config()
|
|
40
40
|
studio = config.get_value(DefaultConfigKeys.studio)
|
|
41
41
|
click.echo(studio)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@get.command("cloud-account")
|
|
45
|
+
def get_cloud_account() -> None:
|
|
46
|
+
"""Get the default cloud account name from the config."""
|
|
47
|
+
config = Config()
|
|
48
|
+
cloud_account = config.get_value(DefaultConfigKeys.cloud_account)
|
|
49
|
+
click.echo(cloud_account)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@get.command("cloud-provider")
|
|
53
|
+
def get_cloud_provider() -> None:
|
|
54
|
+
"""Get the default cloud provider name from the config."""
|
|
55
|
+
config = Config()
|
|
56
|
+
cloud_provider = config.get_value(DefaultConfigKeys.cloud_provider)
|
|
57
|
+
click.echo(cloud_provider)
|
lightning_sdk/cli/config/set.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
3
|
from lightning_sdk.cli.utils.resolve import resolve_teamspace_owner_name_format
|
|
4
|
+
from lightning_sdk.machine import CloudProvider
|
|
4
5
|
from lightning_sdk.organization import Organization
|
|
5
6
|
from lightning_sdk.studio import Studio
|
|
6
7
|
from lightning_sdk.utils.config import Config, DefaultConfigKeys
|
|
@@ -75,3 +76,29 @@ def set_teamspace(teamspace_name: str) -> None:
|
|
|
75
76
|
setattr(config, DefaultConfigKeys.teamspace_owner_type, "organization")
|
|
76
77
|
else:
|
|
77
78
|
setattr(config, DefaultConfigKeys.teamspace_owner_type, "user")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@set_value.command("cloud-account")
|
|
82
|
+
@click.argument("cloud_account_name")
|
|
83
|
+
def set_cloud_account(cloud_account_name: str) -> None:
|
|
84
|
+
"""Set the default cloud account name in the config."""
|
|
85
|
+
config = Config()
|
|
86
|
+
setattr(config, DefaultConfigKeys.cloud_account, cloud_account_name)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@set_value.command("cloud-provider")
|
|
90
|
+
@click.argument("cloud_provider_name")
|
|
91
|
+
def set_cloud_provider(cloud_provider_name: str) -> None:
|
|
92
|
+
"""Set the default cloud provider name in the config."""
|
|
93
|
+
config = Config()
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
cloud_provider = CloudProvider(cloud_provider_name)
|
|
97
|
+
except ValueError:
|
|
98
|
+
# TODO: make this a generic CLI error
|
|
99
|
+
raise ValueError(
|
|
100
|
+
f"Could not resolve cloud provider: '{cloud_provider_name}'. "
|
|
101
|
+
f"Supported values are: {', '.join(m.name for m in list(CloudProvider))}"
|
|
102
|
+
) from None
|
|
103
|
+
|
|
104
|
+
setattr(config, DefaultConfigKeys.cloud_provider, cloud_provider.name)
|
|
@@ -18,10 +18,16 @@ from lightning_sdk.studio import Studio
|
|
|
18
18
|
help="The cloud provider to start the studio on. Defaults to teamspace default.",
|
|
19
19
|
type=click.Choice(m.name for m in list(CloudProvider)),
|
|
20
20
|
)
|
|
21
|
+
@click.option(
|
|
22
|
+
"--cloud-account",
|
|
23
|
+
help="The cloud account to create the studio on. Defaults to teamspace default.",
|
|
24
|
+
type=click.STRING,
|
|
25
|
+
)
|
|
21
26
|
def create_studio(
|
|
22
27
|
studio_name: Optional[str] = None,
|
|
23
28
|
teamspace: Optional[str] = None,
|
|
24
29
|
cloud_provider: Optional[str] = None,
|
|
30
|
+
cloud_account: Optional[str] = None,
|
|
25
31
|
) -> None:
|
|
26
32
|
"""Create a new Studio.
|
|
27
33
|
|
|
@@ -42,8 +48,17 @@ def create_studio(
|
|
|
42
48
|
else:
|
|
43
49
|
resolved_teamspace = None
|
|
44
50
|
|
|
51
|
+
if cloud_provider is not None:
|
|
52
|
+
cloud_provider = CloudProvider(cloud_provider)
|
|
53
|
+
|
|
45
54
|
try:
|
|
46
|
-
studio = Studio(
|
|
55
|
+
studio = Studio(
|
|
56
|
+
studio_name,
|
|
57
|
+
teamspace=resolved_teamspace,
|
|
58
|
+
create_ok=True,
|
|
59
|
+
cloud_provider=cloud_provider,
|
|
60
|
+
cloud_account=cloud_account,
|
|
61
|
+
)
|
|
47
62
|
except (RuntimeError, ValueError, ApiException) as e:
|
|
48
63
|
print(e)
|
|
49
64
|
if studio_name:
|
|
@@ -22,9 +22,17 @@ from lightning_sdk.studio import Studio
|
|
|
22
22
|
@click.option("--interruptible", is_flag=True, help="Start the studio on an interruptible instance.")
|
|
23
23
|
@click.option(
|
|
24
24
|
"--cloud-provider",
|
|
25
|
-
help=
|
|
25
|
+
help=(
|
|
26
|
+
"The cloud provider to start the studio on. Defaults to teamspace default. "
|
|
27
|
+
"Only used if --create is specified."
|
|
28
|
+
),
|
|
26
29
|
type=click.Choice(m.name for m in list(CloudProvider)),
|
|
27
30
|
)
|
|
31
|
+
@click.option(
|
|
32
|
+
"--cloud-account",
|
|
33
|
+
help="The cloud account to start the studio on. Defaults to teamspace default. Only used if --create is specified.",
|
|
34
|
+
type=click.STRING,
|
|
35
|
+
)
|
|
28
36
|
def start_studio(
|
|
29
37
|
studio_name: Optional[str] = None,
|
|
30
38
|
teamspace: Optional[str] = None,
|
|
@@ -32,6 +40,7 @@ def start_studio(
|
|
|
32
40
|
machine: Optional[str] = None,
|
|
33
41
|
interruptible: bool = False,
|
|
34
42
|
cloud_provider: Optional[str] = None,
|
|
43
|
+
cloud_account: Optional[str] = None,
|
|
35
44
|
) -> None:
|
|
36
45
|
"""Start a Studio.
|
|
37
46
|
|
|
@@ -52,8 +61,17 @@ def start_studio(
|
|
|
52
61
|
else:
|
|
53
62
|
resolved_teamspace = None
|
|
54
63
|
|
|
64
|
+
if cloud_provider is not None:
|
|
65
|
+
cloud_provider = CloudProvider(cloud_provider)
|
|
66
|
+
|
|
55
67
|
try:
|
|
56
|
-
studio = Studio(
|
|
68
|
+
studio = Studio(
|
|
69
|
+
studio_name,
|
|
70
|
+
teamspace=resolved_teamspace,
|
|
71
|
+
create_ok=create,
|
|
72
|
+
cloud_provider=cloud_provider,
|
|
73
|
+
cloud_account=cloud_account,
|
|
74
|
+
)
|
|
57
75
|
except (RuntimeError, ValueError, ApiException):
|
|
58
76
|
if studio_name:
|
|
59
77
|
raise ValueError(f"Could not start Studio: '{studio_name}'. Does the Studio exist?") from None
|
|
@@ -638,6 +638,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_like_status import V1LikeSt
|
|
|
638
638
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_affiliate_links_response import V1ListAffiliateLinksResponse
|
|
639
639
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_agent_job_artifacts_response import V1ListAgentJobArtifactsResponse
|
|
640
640
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_agent_jobs_response import V1ListAgentJobsResponse
|
|
641
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_list_aggregated_pod_metrics_response import V1ListAggregatedPodMetricsResponse
|
|
641
642
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_assistants_response import V1ListAssistantsResponse
|
|
642
643
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_blog_posts_response import V1ListBlogPostsResponse
|
|
643
644
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_cloud_space_apps_response import V1ListCloudSpaceAppsResponse
|
|
@@ -160,6 +160,119 @@ class K8SClusterServiceApi(object):
|
|
|
160
160
|
_request_timeout=params.get('_request_timeout'),
|
|
161
161
|
collection_formats=collection_formats)
|
|
162
162
|
|
|
163
|
+
def k8_s_cluster_service_list_aggregated_pod_metrics(self, project_id: 'str', cluster_id: 'str', **kwargs) -> 'V1ListAggregatedPodMetricsResponse': # noqa: E501
|
|
164
|
+
"""k8_s_cluster_service_list_aggregated_pod_metrics # noqa: E501
|
|
165
|
+
|
|
166
|
+
This method makes a synchronous HTTP request by default. To make an
|
|
167
|
+
asynchronous HTTP request, please pass async_req=True
|
|
168
|
+
>>> thread = api.k8_s_cluster_service_list_aggregated_pod_metrics(project_id, cluster_id, async_req=True)
|
|
169
|
+
>>> result = thread.get()
|
|
170
|
+
|
|
171
|
+
:param async_req bool
|
|
172
|
+
:param str project_id: (required)
|
|
173
|
+
:param str cluster_id: (required)
|
|
174
|
+
:param str namespace:
|
|
175
|
+
:param datetime start: Date range.
|
|
176
|
+
:param datetime end:
|
|
177
|
+
:return: V1ListAggregatedPodMetricsResponse
|
|
178
|
+
If the method is called asynchronously,
|
|
179
|
+
returns the request thread.
|
|
180
|
+
"""
|
|
181
|
+
kwargs['_return_http_data_only'] = True
|
|
182
|
+
if kwargs.get('async_req'):
|
|
183
|
+
return self.k8_s_cluster_service_list_aggregated_pod_metrics_with_http_info(project_id, cluster_id, **kwargs) # noqa: E501
|
|
184
|
+
else:
|
|
185
|
+
(data) = self.k8_s_cluster_service_list_aggregated_pod_metrics_with_http_info(project_id, cluster_id, **kwargs) # noqa: E501
|
|
186
|
+
return data
|
|
187
|
+
|
|
188
|
+
def k8_s_cluster_service_list_aggregated_pod_metrics_with_http_info(self, project_id: 'str', cluster_id: 'str', **kwargs) -> 'V1ListAggregatedPodMetricsResponse': # noqa: E501
|
|
189
|
+
"""k8_s_cluster_service_list_aggregated_pod_metrics # noqa: E501
|
|
190
|
+
|
|
191
|
+
This method makes a synchronous HTTP request by default. To make an
|
|
192
|
+
asynchronous HTTP request, please pass async_req=True
|
|
193
|
+
>>> thread = api.k8_s_cluster_service_list_aggregated_pod_metrics_with_http_info(project_id, cluster_id, async_req=True)
|
|
194
|
+
>>> result = thread.get()
|
|
195
|
+
|
|
196
|
+
:param async_req bool
|
|
197
|
+
:param str project_id: (required)
|
|
198
|
+
:param str cluster_id: (required)
|
|
199
|
+
:param str namespace:
|
|
200
|
+
:param datetime start: Date range.
|
|
201
|
+
:param datetime end:
|
|
202
|
+
:return: V1ListAggregatedPodMetricsResponse
|
|
203
|
+
If the method is called asynchronously,
|
|
204
|
+
returns the request thread.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
all_params = ['project_id', 'cluster_id', 'namespace', 'start', 'end'] # noqa: E501
|
|
208
|
+
all_params.append('async_req')
|
|
209
|
+
all_params.append('_return_http_data_only')
|
|
210
|
+
all_params.append('_preload_content')
|
|
211
|
+
all_params.append('_request_timeout')
|
|
212
|
+
|
|
213
|
+
params = locals()
|
|
214
|
+
for key, val in six.iteritems(params['kwargs']):
|
|
215
|
+
if key not in all_params:
|
|
216
|
+
raise TypeError(
|
|
217
|
+
"Got an unexpected keyword argument '%s'"
|
|
218
|
+
" to method k8_s_cluster_service_list_aggregated_pod_metrics" % key
|
|
219
|
+
)
|
|
220
|
+
params[key] = val
|
|
221
|
+
del params['kwargs']
|
|
222
|
+
# verify the required parameter 'project_id' is set
|
|
223
|
+
if ('project_id' not in params or
|
|
224
|
+
params['project_id'] is None):
|
|
225
|
+
raise ValueError("Missing the required parameter `project_id` when calling `k8_s_cluster_service_list_aggregated_pod_metrics`") # noqa: E501
|
|
226
|
+
# verify the required parameter 'cluster_id' is set
|
|
227
|
+
if ('cluster_id' not in params or
|
|
228
|
+
params['cluster_id'] is None):
|
|
229
|
+
raise ValueError("Missing the required parameter `cluster_id` when calling `k8_s_cluster_service_list_aggregated_pod_metrics`") # noqa: E501
|
|
230
|
+
|
|
231
|
+
collection_formats = {}
|
|
232
|
+
|
|
233
|
+
path_params = {}
|
|
234
|
+
if 'project_id' in params:
|
|
235
|
+
path_params['projectId'] = params['project_id'] # noqa: E501
|
|
236
|
+
if 'cluster_id' in params:
|
|
237
|
+
path_params['clusterId'] = params['cluster_id'] # noqa: E501
|
|
238
|
+
|
|
239
|
+
query_params = []
|
|
240
|
+
if 'namespace' in params:
|
|
241
|
+
query_params.append(('namespace', params['namespace'])) # noqa: E501
|
|
242
|
+
if 'start' in params:
|
|
243
|
+
query_params.append(('start', params['start'])) # noqa: E501
|
|
244
|
+
if 'end' in params:
|
|
245
|
+
query_params.append(('end', params['end'])) # noqa: E501
|
|
246
|
+
|
|
247
|
+
header_params = {}
|
|
248
|
+
|
|
249
|
+
form_params = []
|
|
250
|
+
local_var_files = {}
|
|
251
|
+
|
|
252
|
+
body_params = None
|
|
253
|
+
# HTTP header `Accept`
|
|
254
|
+
header_params['Accept'] = self.api_client.select_header_accept(
|
|
255
|
+
['application/json']) # noqa: E501
|
|
256
|
+
|
|
257
|
+
# Authentication setting
|
|
258
|
+
auth_settings = [] # noqa: E501
|
|
259
|
+
|
|
260
|
+
return self.api_client.call_api(
|
|
261
|
+
'/v1/projects/{projectId}/clusters/{clusterId}/aggregated-metrics/pods', 'GET',
|
|
262
|
+
path_params,
|
|
263
|
+
query_params,
|
|
264
|
+
header_params,
|
|
265
|
+
body=body_params,
|
|
266
|
+
post_params=form_params,
|
|
267
|
+
files=local_var_files,
|
|
268
|
+
response_type='V1ListAggregatedPodMetricsResponse', # noqa: E501
|
|
269
|
+
auth_settings=auth_settings,
|
|
270
|
+
async_req=params.get('async_req'),
|
|
271
|
+
_return_http_data_only=params.get('_return_http_data_only'),
|
|
272
|
+
_preload_content=params.get('_preload_content', True),
|
|
273
|
+
_request_timeout=params.get('_request_timeout'),
|
|
274
|
+
collection_formats=collection_formats)
|
|
275
|
+
|
|
163
276
|
def k8_s_cluster_service_list_cluster_metrics(self, project_id: 'str', cluster_id: 'str', **kwargs) -> 'V1ListClusterMetricsResponse': # noqa: E501
|
|
164
277
|
"""k8_s_cluster_service_list_cluster_metrics # noqa: E501
|
|
165
278
|
|
|
@@ -590,6 +590,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_like_status import V1LikeSt
|
|
|
590
590
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_affiliate_links_response import V1ListAffiliateLinksResponse
|
|
591
591
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_agent_job_artifacts_response import V1ListAgentJobArtifactsResponse
|
|
592
592
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_agent_jobs_response import V1ListAgentJobsResponse
|
|
593
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_list_aggregated_pod_metrics_response import V1ListAggregatedPodMetricsResponse
|
|
593
594
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_assistants_response import V1ListAssistantsResponse
|
|
594
595
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_blog_posts_response import V1ListBlogPostsResponse
|
|
595
596
|
from lightning_sdk.lightning_cloud.openapi.models.v1_list_cloud_space_apps_response import V1ListCloudSpaceAppsResponse
|