lightning-sdk 0.2.6__py3-none-any.whl → 0.2.8__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.
Files changed (42) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/api/ai_hub_api.py +1 -0
  3. lightning_sdk/api/lit_container_api.py +83 -30
  4. lightning_sdk/api/teamspace_api.py +8 -9
  5. lightning_sdk/api/utils.py +0 -1
  6. lightning_sdk/cli/docker.py +1 -1
  7. lightning_sdk/cli/download.py +10 -2
  8. lightning_sdk/cli/serve.py +51 -41
  9. lightning_sdk/cli/upload.py +41 -6
  10. lightning_sdk/lightning_cloud/openapi/__init__.py +8 -0
  11. lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +202 -0
  12. lightning_sdk/lightning_cloud/openapi/models/__init__.py +8 -0
  13. lightning_sdk/lightning_cloud/openapi/models/alerts_config_billing.py +175 -0
  14. lightning_sdk/lightning_cloud/openapi/models/alerts_config_studios.py +149 -0
  15. lightning_sdk/lightning_cloud/openapi/models/orgs_id_body.py +53 -1
  16. lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +27 -1
  17. lightning_sdk/lightning_cloud/openapi/models/server_id_alerts_body.py +27 -1
  18. lightning_sdk/lightning_cloud/openapi/models/v1_alert_method.py +102 -0
  19. lightning_sdk/lightning_cloud/openapi/models/v1_alerts_config.py +149 -0
  20. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_cold_start_metrics.py +617 -0
  21. lightning_sdk/lightning_cloud/openapi/models/v1_conversation_response_chunk.py +29 -3
  22. lightning_sdk/lightning_cloud/openapi/models/v1_create_project_request.py +27 -1
  23. lightning_sdk/lightning_cloud/openapi/models/v1_google_cloud_direct_v1.py +29 -3
  24. lightning_sdk/lightning_cloud/openapi/models/v1_list_cloud_space_cold_start_metrics_response.py +123 -0
  25. lightning_sdk/lightning_cloud/openapi/models/v1_message.py +29 -3
  26. lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +53 -1
  27. lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +27 -1
  28. lightning_sdk/lightning_cloud/openapi/models/v1_report_cloud_space_instance_stop_at_response.py +97 -0
  29. lightning_sdk/lightning_cloud/openapi/models/v1_server_alert.py +27 -1
  30. lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_phase.py +104 -0
  31. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +53 -1
  32. lightning_sdk/lightning_cloud/rest_client.py +42 -44
  33. lightning_sdk/lit_container.py +19 -4
  34. lightning_sdk/models.py +1 -1
  35. lightning_sdk/serve.py +107 -41
  36. lightning_sdk/teamspace.py +32 -18
  37. {lightning_sdk-0.2.6.dist-info → lightning_sdk-0.2.8.dist-info}/METADATA +1 -1
  38. {lightning_sdk-0.2.6.dist-info → lightning_sdk-0.2.8.dist-info}/RECORD +42 -34
  39. {lightning_sdk-0.2.6.dist-info → lightning_sdk-0.2.8.dist-info}/LICENSE +0 -0
  40. {lightning_sdk-0.2.6.dist-info → lightning_sdk-0.2.8.dist-info}/WHEEL +0 -0
  41. {lightning_sdk-0.2.6.dist-info → lightning_sdk-0.2.8.dist-info}/entry_points.txt +0 -0
  42. {lightning_sdk-0.2.6.dist-info → lightning_sdk-0.2.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,104 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ external/v1/auth_service.proto
5
+
6
+ No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501
7
+
8
+ OpenAPI spec version: version not set
9
+
10
+ Generated by: https://github.com/swagger-api/swagger-codegen.git
11
+
12
+ NOTE
13
+ ----
14
+ standard swagger-codegen-cli for this python client has been modified
15
+ by custom templates. The purpose of these templates is to include
16
+ typing information in the API and Model code. Please refer to the
17
+ main grid repository for more info
18
+ """
19
+
20
+ import pprint
21
+ import re # noqa: F401
22
+
23
+ from typing import TYPE_CHECKING
24
+
25
+ import six
26
+
27
+ if TYPE_CHECKING:
28
+ from datetime import datetime
29
+ from lightning_sdk.lightning_cloud.openapi.models import *
30
+
31
+ class V1ServerAlertPhase(object):
32
+ """NOTE: This class is auto generated by the swagger code generator program.
33
+
34
+ Do not edit the class manually.
35
+ """
36
+
37
+ """
38
+ allowed enum values
39
+ """
40
+ UNSPECIFIED = "SERVER_ALERT_PHASE_UNSPECIFIED"
41
+ STARTUP = "SERVER_ALERT_PHASE_STARTUP"
42
+ SHUTDOWN = "SERVER_ALERT_PHASE_SHUTDOWN"
43
+ """
44
+ Attributes:
45
+ swagger_types (dict): The key is attribute name
46
+ and the value is attribute type.
47
+ attribute_map (dict): The key is attribute name
48
+ and the value is json key in definition.
49
+ """
50
+ swagger_types = {
51
+ }
52
+
53
+ attribute_map = {
54
+ }
55
+
56
+ def __init__(self): # noqa: E501
57
+ """V1ServerAlertPhase - a model defined in Swagger""" # noqa: E501
58
+ self.discriminator = None
59
+
60
+ def to_dict(self) -> dict:
61
+ """Returns the model properties as a dict"""
62
+ result = {}
63
+
64
+ for attr, _ in six.iteritems(self.swagger_types):
65
+ value = getattr(self, attr)
66
+ if isinstance(value, list):
67
+ result[attr] = list(map(
68
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
69
+ value
70
+ ))
71
+ elif hasattr(value, "to_dict"):
72
+ result[attr] = value.to_dict()
73
+ elif isinstance(value, dict):
74
+ result[attr] = dict(map(
75
+ lambda item: (item[0], item[1].to_dict())
76
+ if hasattr(item[1], "to_dict") else item,
77
+ value.items()
78
+ ))
79
+ else:
80
+ result[attr] = value
81
+ if issubclass(V1ServerAlertPhase, dict):
82
+ for key, value in self.items():
83
+ result[key] = value
84
+
85
+ return result
86
+
87
+ def to_str(self) -> str:
88
+ """Returns the string representation of the model"""
89
+ return pprint.pformat(self.to_dict())
90
+
91
+ def __repr__(self) -> str:
92
+ """For `print` and `pprint`"""
93
+ return self.to_str()
94
+
95
+ def __eq__(self, other: 'V1ServerAlertPhase') -> bool:
96
+ """Returns true if both objects are equal"""
97
+ if not isinstance(other, V1ServerAlertPhase):
98
+ return False
99
+
100
+ return self.__dict__ == other.__dict__
101
+
102
+ def __ne__(self, other: 'V1ServerAlertPhase') -> bool:
103
+ """Returns true if both objects are not equal"""
104
+ return not self == other
@@ -79,6 +79,7 @@ class V1UserFeatures(object):
79
79
  'lambda_labs': 'bool',
80
80
  'landing_studios': 'bool',
81
81
  'lit_logger': 'bool',
82
+ 'manage_default_studio_machine': 'bool',
82
83
  'marketplace': 'bool',
83
84
  'mmt_fault_tolerance': 'bool',
84
85
  'mmt_strategy_selector': 'bool',
@@ -107,6 +108,7 @@ class V1UserFeatures(object):
107
108
  'runnable_public_studio_page': 'bool',
108
109
  'security_docs': 'bool',
109
110
  'show_dev_admin': 'bool',
111
+ 'single_wallet': 'bool',
110
112
  'slurm': 'bool',
111
113
  'slurm_machine_selector': 'bool',
112
114
  'stop_ide_container_on_shutdown': 'bool',
@@ -159,6 +161,7 @@ class V1UserFeatures(object):
159
161
  'lambda_labs': 'lambdaLabs',
160
162
  'landing_studios': 'landingStudios',
161
163
  'lit_logger': 'litLogger',
164
+ 'manage_default_studio_machine': 'manageDefaultStudioMachine',
162
165
  'marketplace': 'marketplace',
163
166
  'mmt_fault_tolerance': 'mmtFaultTolerance',
164
167
  'mmt_strategy_selector': 'mmtStrategySelector',
@@ -187,6 +190,7 @@ class V1UserFeatures(object):
187
190
  'runnable_public_studio_page': 'runnablePublicStudioPage',
188
191
  'security_docs': 'securityDocs',
189
192
  'show_dev_admin': 'showDevAdmin',
193
+ 'single_wallet': 'singleWallet',
190
194
  'slurm': 'slurm',
191
195
  'slurm_machine_selector': 'slurmMachineSelector',
192
196
  'stop_ide_container_on_shutdown': 'stopIdeContainerOnShutdown',
@@ -200,7 +204,7 @@ class V1UserFeatures(object):
200
204
  'vultr': 'vultr'
201
205
  }
202
206
 
203
- def __init__(self, affiliate_links: 'bool' =None, agents_v2: 'bool' =None, ai_hub_monetization: 'bool' =None, auto_fast_load: 'bool' =None, auto_join_orgs: 'bool' =None, b2c_experience: 'bool' =None, byoc_litcr: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, chat_models: 'bool' =None, cloud_space_environment_templates: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, custom_instance_types: 'bool' =None, datasets: 'bool' =None, default_one_cluster: 'bool' =None, deployment_alerts: 'bool' =None, deployment_persistent_disk: 'bool' =None, deployment_reservations: 'bool' =None, dgx_cloud: 'bool' =None, docs_agent: 'bool' =None, drive_v2: 'bool' =None, enable_crypto_crackdown: 'bool' =None, enable_storage_limits: 'bool' =None, enterprise_compute_admin: 'bool' =None, fair_share: 'bool' =None, featured_studios_admin: 'bool' =None, filestore: 'bool' =None, inactive_notify_delete: 'bool' =None, instant_capacity_reservation: 'bool' =None, job_artifacts_v2: 'bool' =None, lambda_labs: 'bool' =None, landing_studios: 'bool' =None, lit_logger: 'bool' =None, marketplace: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, multicloud_saas: 'bool' =None, multiple_studio_versions: 'bool' =None, org_admin_alerts: 'bool' =None, org_level_member_permissions: 'bool' =None, pipelines: 'bool' =None, plugin_distributed: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_lightning_apps: 'bool' =None, plugin_lightning_apps_distributed: 'bool' =None, plugin_milvus: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_react: 'bool' =None, plugin_service: 'bool' =None, plugin_sweeps: 'bool' =None, plugin_weviate: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, project_selector: 'bool' =None, publish_pipelines: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, security_docs: 'bool' =None, show_dev_admin: 'bool' =None, slurm: 'bool' =None, slurm_machine_selector: 'bool' =None, stop_ide_container_on_shutdown: 'bool' =None, studio_config: 'bool' =None, studio_on_stop: 'bool' =None, studio_version_visibility: 'bool' =None, studios_dashboard: 'bool' =None, teamspace_storage_tab: 'bool' =None, trainium2: 'bool' =None, use_rclone_mounts_only: 'bool' =None, vultr: 'bool' =None): # noqa: E501
207
+ def __init__(self, affiliate_links: 'bool' =None, agents_v2: 'bool' =None, ai_hub_monetization: 'bool' =None, auto_fast_load: 'bool' =None, auto_join_orgs: 'bool' =None, b2c_experience: 'bool' =None, byoc_litcr: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, chat_models: 'bool' =None, cloud_space_environment_templates: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, custom_instance_types: 'bool' =None, datasets: 'bool' =None, default_one_cluster: 'bool' =None, deployment_alerts: 'bool' =None, deployment_persistent_disk: 'bool' =None, deployment_reservations: 'bool' =None, dgx_cloud: 'bool' =None, docs_agent: 'bool' =None, drive_v2: 'bool' =None, enable_crypto_crackdown: 'bool' =None, enable_storage_limits: 'bool' =None, enterprise_compute_admin: 'bool' =None, fair_share: 'bool' =None, featured_studios_admin: 'bool' =None, filestore: 'bool' =None, inactive_notify_delete: 'bool' =None, instant_capacity_reservation: 'bool' =None, job_artifacts_v2: 'bool' =None, lambda_labs: 'bool' =None, landing_studios: 'bool' =None, lit_logger: 'bool' =None, manage_default_studio_machine: 'bool' =None, marketplace: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, multicloud_saas: 'bool' =None, multiple_studio_versions: 'bool' =None, org_admin_alerts: 'bool' =None, org_level_member_permissions: 'bool' =None, pipelines: 'bool' =None, plugin_distributed: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_lightning_apps: 'bool' =None, plugin_lightning_apps_distributed: 'bool' =None, plugin_milvus: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_react: 'bool' =None, plugin_service: 'bool' =None, plugin_sweeps: 'bool' =None, plugin_weviate: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, project_selector: 'bool' =None, publish_pipelines: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, security_docs: 'bool' =None, show_dev_admin: 'bool' =None, single_wallet: 'bool' =None, slurm: 'bool' =None, slurm_machine_selector: 'bool' =None, stop_ide_container_on_shutdown: 'bool' =None, studio_config: 'bool' =None, studio_on_stop: 'bool' =None, studio_version_visibility: 'bool' =None, studios_dashboard: 'bool' =None, teamspace_storage_tab: 'bool' =None, trainium2: 'bool' =None, use_rclone_mounts_only: 'bool' =None, vultr: 'bool' =None): # noqa: E501
204
208
  """V1UserFeatures - a model defined in Swagger""" # noqa: E501
205
209
  self._affiliate_links = None
206
210
  self._agents_v2 = None
@@ -240,6 +244,7 @@ class V1UserFeatures(object):
240
244
  self._lambda_labs = None
241
245
  self._landing_studios = None
242
246
  self._lit_logger = None
247
+ self._manage_default_studio_machine = None
243
248
  self._marketplace = None
244
249
  self._mmt_fault_tolerance = None
245
250
  self._mmt_strategy_selector = None
@@ -268,6 +273,7 @@ class V1UserFeatures(object):
268
273
  self._runnable_public_studio_page = None
269
274
  self._security_docs = None
270
275
  self._show_dev_admin = None
276
+ self._single_wallet = None
271
277
  self._slurm = None
272
278
  self._slurm_machine_selector = None
273
279
  self._stop_ide_container_on_shutdown = None
@@ -356,6 +362,8 @@ class V1UserFeatures(object):
356
362
  self.landing_studios = landing_studios
357
363
  if lit_logger is not None:
358
364
  self.lit_logger = lit_logger
365
+ if manage_default_studio_machine is not None:
366
+ self.manage_default_studio_machine = manage_default_studio_machine
359
367
  if marketplace is not None:
360
368
  self.marketplace = marketplace
361
369
  if mmt_fault_tolerance is not None:
@@ -412,6 +420,8 @@ class V1UserFeatures(object):
412
420
  self.security_docs = security_docs
413
421
  if show_dev_admin is not None:
414
422
  self.show_dev_admin = show_dev_admin
423
+ if single_wallet is not None:
424
+ self.single_wallet = single_wallet
415
425
  if slurm is not None:
416
426
  self.slurm = slurm
417
427
  if slurm_machine_selector is not None:
@@ -1233,6 +1243,27 @@ class V1UserFeatures(object):
1233
1243
 
1234
1244
  self._lit_logger = lit_logger
1235
1245
 
1246
+ @property
1247
+ def manage_default_studio_machine(self) -> 'bool':
1248
+ """Gets the manage_default_studio_machine of this V1UserFeatures. # noqa: E501
1249
+
1250
+
1251
+ :return: The manage_default_studio_machine of this V1UserFeatures. # noqa: E501
1252
+ :rtype: bool
1253
+ """
1254
+ return self._manage_default_studio_machine
1255
+
1256
+ @manage_default_studio_machine.setter
1257
+ def manage_default_studio_machine(self, manage_default_studio_machine: 'bool'):
1258
+ """Sets the manage_default_studio_machine of this V1UserFeatures.
1259
+
1260
+
1261
+ :param manage_default_studio_machine: The manage_default_studio_machine of this V1UserFeatures. # noqa: E501
1262
+ :type: bool
1263
+ """
1264
+
1265
+ self._manage_default_studio_machine = manage_default_studio_machine
1266
+
1236
1267
  @property
1237
1268
  def marketplace(self) -> 'bool':
1238
1269
  """Gets the marketplace of this V1UserFeatures. # noqa: E501
@@ -1821,6 +1852,27 @@ class V1UserFeatures(object):
1821
1852
 
1822
1853
  self._show_dev_admin = show_dev_admin
1823
1854
 
1855
+ @property
1856
+ def single_wallet(self) -> 'bool':
1857
+ """Gets the single_wallet of this V1UserFeatures. # noqa: E501
1858
+
1859
+
1860
+ :return: The single_wallet of this V1UserFeatures. # noqa: E501
1861
+ :rtype: bool
1862
+ """
1863
+ return self._single_wallet
1864
+
1865
+ @single_wallet.setter
1866
+ def single_wallet(self, single_wallet: 'bool'):
1867
+ """Sets the single_wallet of this V1UserFeatures.
1868
+
1869
+
1870
+ :param single_wallet: The single_wallet of this V1UserFeatures. # noqa: E501
1871
+ :type: bool
1872
+ """
1873
+
1874
+ self._single_wallet = single_wallet
1875
+
1824
1876
  @property
1825
1877
  def slurm(self) -> 'bool':
1826
1878
  """Gets the slurm of this V1UserFeatures. # noqa: E501
@@ -2,41 +2,39 @@ import functools
2
2
  import logging
3
3
  import time
4
4
  from functools import wraps
5
- from typing import Any, Callable, Optional
5
+ from typing import Callable, Optional, Any
6
6
 
7
7
  import urllib3
8
-
9
8
  from lightning_sdk.lightning_cloud import env
10
9
  from lightning_sdk.lightning_cloud.login import Auth
11
10
  from lightning_sdk.lightning_cloud.openapi import (
12
11
  ApiClient,
13
- AssistantsServiceApi,
14
12
  AuthServiceApi,
15
- BillingServiceApi,
16
- CloudSpaceEnvironmentTemplateServiceApi,
17
13
  CloudSpaceServiceApi,
18
14
  ClusterServiceApi,
19
15
  Configuration,
20
16
  DataConnectionServiceApi,
21
- DatasetServiceApi,
22
- DeploymentTemplatesServiceApi,
23
- EndpointServiceApi,
24
- JobsServiceApi,
25
17
  LightningappInstanceServiceApi,
26
18
  LightningappV2ServiceApi,
27
19
  LightningworkServiceApi,
28
- LitLoggerServiceApi,
29
- LitRegistryServiceApi,
30
- ModelsStoreApi,
31
- OrganizationsServiceApi,
32
- PipelinesServiceApi,
33
20
  ProjectsServiceApi,
34
- SchedulesServiceApi,
35
21
  SecretServiceApi,
36
- SlurmJobsUserServiceApi,
37
22
  SSHPublicKeyServiceApi,
38
- StorageServiceApi,
23
+ DatasetServiceApi,
24
+ OrganizationsServiceApi,
39
25
  UserServiceApi,
26
+ BillingServiceApi,
27
+ EndpointServiceApi,
28
+ SlurmJobsUserServiceApi,
29
+ LitLoggerServiceApi,
30
+ JobsServiceApi,
31
+ AssistantsServiceApi,
32
+ StorageServiceApi,
33
+ DeploymentTemplatesServiceApi,
34
+ ModelsStoreApi,
35
+ LitRegistryServiceApi,
36
+ PipelinesServiceApi,
37
+ SchedulesServiceApi,
40
38
  )
41
39
  from lightning_sdk.lightning_cloud.openapi.rest import ApiException
42
40
  from lightning_sdk.lightning_cloud.source_code.logs_socket_api import LightningLogsSocketAPI
@@ -73,34 +71,34 @@ def create_swagger_client(check_context=True):
73
71
 
74
72
 
75
73
  class GridRestClient(
76
- LightningLogsSocketAPI,
77
- LightningappInstanceServiceApi,
78
- LightningappV2ServiceApi,
79
- AuthServiceApi,
80
- CloudSpaceServiceApi,
81
- ClusterServiceApi,
82
- ProjectsServiceApi,
83
- LightningworkServiceApi,
84
- SecretServiceApi,
85
- SSHPublicKeyServiceApi,
86
- DataConnectionServiceApi,
87
- DatasetServiceApi,
88
- OrganizationsServiceApi,
89
- UserServiceApi,
90
- BillingServiceApi,
91
- EndpointServiceApi,
92
- SlurmJobsUserServiceApi,
93
- LitLoggerServiceApi,
94
- JobsServiceApi,
95
- AssistantsServiceApi,
96
- StorageServiceApi,
97
- DeploymentTemplatesServiceApi,
98
- ModelsStoreApi,
99
- LitRegistryServiceApi,
100
- PipelinesServiceApi,
101
- SchedulesServiceApi,
102
- CloudSpaceEnvironmentTemplateServiceApi,
74
+ LightningLogsSocketAPI,
75
+ LightningappInstanceServiceApi,
76
+ LightningappV2ServiceApi,
77
+ AuthServiceApi,
78
+ CloudSpaceServiceApi,
79
+ ClusterServiceApi,
80
+ ProjectsServiceApi,
81
+ LightningworkServiceApi,
82
+ SecretServiceApi,
83
+ SSHPublicKeyServiceApi,
84
+ DataConnectionServiceApi,
85
+ DatasetServiceApi,
86
+ OrganizationsServiceApi,
87
+ UserServiceApi,
88
+ BillingServiceApi,
89
+ EndpointServiceApi,
90
+ SlurmJobsUserServiceApi,
91
+ LitLoggerServiceApi,
92
+ JobsServiceApi,
93
+ AssistantsServiceApi,
94
+ StorageServiceApi,
95
+ DeploymentTemplatesServiceApi,
96
+ ModelsStoreApi,
97
+ LitRegistryServiceApi,
98
+ PipelinesServiceApi,
99
+ SchedulesServiceApi,
103
100
  ):
101
+
104
102
  def __init__(self, api_client: Optional[ApiClient] = None):
105
103
  api_client = api_client if api_client else create_swagger_client()
106
104
  api_client.request = request_auth_warning_wrapper(api_client.request)
@@ -64,7 +64,14 @@ class LitContainer:
64
64
  return self._api.delete_container(project_id, container)
65
65
 
66
66
  def upload_container(
67
- self, container: str, teamspace: str, org: Optional[str] = None, user: Optional[str] = None, tag: str = "latest"
67
+ self,
68
+ container: str,
69
+ teamspace: str,
70
+ org: Optional[str] = None,
71
+ user: Optional[str] = None,
72
+ tag: str = "latest",
73
+ cloud_account: Optional[str] = None,
74
+ platform: Optional[str] = "linux/amd64",
68
75
  ) -> None:
69
76
  """Upload a container to the docker registry.
70
77
 
@@ -74,18 +81,26 @@ class LitContainer:
74
81
  org: The organization which contains the container.
75
82
  user: The user which contains the container.
76
83
  tag: The tag to use for the container.
84
+ cloud_account: The cloud account where the container is stored.
85
+ platform: The platform the container is meant to run on.
77
86
  """
78
87
  try:
79
88
  teamspace = _resolve_teamspace(teamspace=teamspace, org=org, user=user)
80
89
  except Exception as e:
81
90
  raise ValueError(f"Could not resolve teamspace: {e}") from e
82
91
 
83
- resp = self._api.upload_container(container, teamspace, tag)
92
+ resp = self._api.upload_container(container, teamspace, tag, cloud_account, platform=platform)
84
93
  for line in resp:
85
94
  print(line)
86
95
 
87
96
  def download_container(
88
- self, container: str, teamspace: str, org: Optional[str] = None, user: Optional[str] = None, tag: str = "latest"
97
+ self,
98
+ container: str,
99
+ teamspace: str,
100
+ org: Optional[str] = None,
101
+ user: Optional[str] = None,
102
+ tag: str = "latest",
103
+ cloud_account: Optional[str] = None,
89
104
  ) -> None:
90
105
  """Download a container from the docker registry.
91
106
 
@@ -101,4 +116,4 @@ class LitContainer:
101
116
  except Exception as e:
102
117
  raise ValueError(f"Could not resolve teamspace: {e}") from e
103
118
 
104
- return self._api.download_container(container, teamspace, tag)
119
+ return self._api.download_container(container, teamspace, tag, cloud_account)
lightning_sdk/models.py CHANGED
@@ -144,7 +144,7 @@ def download_model(
144
144
 
145
145
  def upload_model(
146
146
  name: str,
147
- path: Union[Path, str] = ".",
147
+ path: Union[str, Path, List[Union[str, Path]]] = ".",
148
148
  cloud_account: Optional[str] = None,
149
149
  progress_bar: bool = True,
150
150
  ) -> UploadedModelInfo:
lightning_sdk/serve.py CHANGED
@@ -2,18 +2,18 @@ import os
2
2
  import shlex
3
3
  import subprocess
4
4
  from pathlib import Path
5
- from typing import Generator, Optional
5
+ from typing import Generator, List, Optional, Union
6
6
  from urllib.parse import urlencode
7
7
 
8
8
  import docker
9
9
  from rich.console import Console
10
- from rich.progress import Progress
11
10
 
12
11
  from lightning_sdk import Deployment, Machine, Teamspace
13
- from lightning_sdk.api.deployment_api import AutoScaleConfig
12
+ from lightning_sdk.api.deployment_api import AutoScaleConfig, DeploymentApi, Env, Secret
14
13
  from lightning_sdk.api.lit_container_api import LitContainerApi
15
- from lightning_sdk.api.utils import _get_cloud_url
14
+ from lightning_sdk.api.utils import _get_cloud_url, _get_registry_url
16
15
  from lightning_sdk.lightning_cloud import env
16
+ from lightning_sdk.lightning_cloud.env import LIGHTNING_CLOUD_URL
17
17
  from lightning_sdk.lightning_cloud.login import Auth, AuthServer
18
18
 
19
19
  _DOCKER_NOT_RUNNING_MSG = (
@@ -35,16 +35,18 @@ class _Auth(Auth):
35
35
  _AuthServer().login_with_browser(self)
36
36
 
37
37
 
38
+ def authenticate() -> None:
39
+ auth = _Auth()
40
+ auth.authenticate()
41
+
42
+
38
43
  class _LitServeDeployer:
39
- def __init__(self) -> None:
44
+ def __init__(self, name: Optional[str], teamspace: Optional[Teamspace]) -> None:
45
+ self.name = name
46
+ self.teamspace = teamspace
40
47
  self._console = Console()
41
48
  self._client = None
42
49
 
43
- @staticmethod
44
- def authenticate() -> None:
45
- auth = _Auth()
46
- auth.authenticate()
47
-
48
50
  @property
49
51
  def client(self) -> docker.DockerClient:
50
52
  if self._client is None:
@@ -56,6 +58,10 @@ class _LitServeDeployer:
56
58
  raise RuntimeError(_DOCKER_NOT_RUNNING_MSG) from None
57
59
  return self._client
58
60
 
61
+ @property
62
+ def created(self) -> bool:
63
+ return DeploymentApi().get_deployment_by_name(self.name, self.teamspace.id) is not None
64
+
59
65
  def dockerize_api(
60
66
  self,
61
67
  server_filename: str,
@@ -176,45 +182,79 @@ Update [underline]{os.path.abspath("Dockerfile")}[/underline] to add any additio
176
182
 
177
183
  return log_generator()
178
184
 
179
- def build_container(self, path: str, repository: str, tag: str, console: Console, progress: Progress) -> None:
180
- build_task = progress.add_task("Building Docker image", total=None)
185
+ def build_container(self, path: str, repository: str, tag: str) -> Generator[str, None, None]:
181
186
  build_logs = self._docker_build_with_logs(path, repository, tag=tag)
182
187
 
183
188
  for line in build_logs:
184
189
  if "error" in line:
185
- progress.stop()
186
- console.print(f"\n[red]{line}[/red]")
187
190
  raise RuntimeError(f"Failed to build image: {line}")
188
191
  else:
189
- console.print(
190
- line.strip(),
191
- )
192
- progress.update(build_task, description="Building Docker image")
193
-
194
- progress.update(build_task, description="[green]Build completed![/green]")
192
+ yield line.strip()
195
193
 
196
194
  def push_container(
197
- self, repository: str, tag: str, teamspace: Teamspace, lit_cr: LitContainerApi, progress: Progress
198
- ) -> dict:
199
- console = self._console
200
- push_task = progress.add_task("Pushing to registry", total=None)
201
- console.print("\nPushing image...", style="bold blue")
195
+ self,
196
+ repository: str,
197
+ tag: str,
198
+ teamspace: Teamspace,
199
+ lit_cr: LitContainerApi,
200
+ cloud_account: str,
201
+ ) -> Generator[dict, None, dict]:
202
202
  lit_cr.authenticate()
203
- push_status = lit_cr.upload_container(repository, teamspace, tag=tag)
204
- last_status = {}
203
+ push_status = lit_cr.upload_container(
204
+ repository, teamspace, tag=tag, cloud_account=cloud_account, platform=None
205
+ )
205
206
  for line in push_status:
206
- last_status = line
207
207
  if "error" in line:
208
- progress.stop()
209
- console.print(f"\n[red]{line}[/red]")
210
208
  raise RuntimeError(f"Failed to push image: {line}")
211
209
  if "status" in line:
212
- console.print(line["status"].strip())
213
- progress.update(push_task, description="Pushing to registry")
214
- progress.update(push_task, description="[green]Push completed![/green]")
215
- return last_status
210
+ yield {"status": line["status"].strip()}
216
211
 
217
- def _run_on_cloud(
212
+ registry_url = _get_registry_url()
213
+ container_basename = repository.split("/")[-1]
214
+ repository = (
215
+ f"{registry_url}/lit-container{f'-{cloud_account}' if cloud_account is not None else ''}/"
216
+ f"{teamspace.owner.name}/{teamspace.name}/{container_basename}"
217
+ )
218
+ yield {
219
+ "finish": True,
220
+ "status": "Container pushed successfully",
221
+ "url": f"{LIGHTNING_CLOUD_URL}/{teamspace.owner.name}/{teamspace.name}/containers/{container_basename}"
222
+ f"{f'?clusterId={cloud_account}' if cloud_account is not None else ''}",
223
+ "image": repository,
224
+ }
225
+
226
+ def _update_deployment(
227
+ self,
228
+ deployment: Deployment,
229
+ machine: Optional[Machine] = None,
230
+ image: Optional[str] = None,
231
+ entrypoint: Optional[str] = None,
232
+ command: Optional[str] = None,
233
+ env: Optional[List[Union[Env, Secret]]] = None,
234
+ min_replica: Optional[int] = 0,
235
+ max_replica: Optional[int] = 1,
236
+ spot: Optional[bool] = None,
237
+ replicas: Optional[int] = 1,
238
+ cloud_account: Optional[str] = None,
239
+ port: Optional[int] = 8000,
240
+ include_credentials: Optional[bool] = True,
241
+ ) -> None:
242
+ return deployment.update(
243
+ machine=machine,
244
+ image=image,
245
+ entrypoint=entrypoint,
246
+ command=command,
247
+ env=env,
248
+ max_replicas=max_replica,
249
+ min_replicas=min_replica,
250
+ replicas=replicas,
251
+ spot=spot,
252
+ cloud_account=cloud_account,
253
+ ports=[port],
254
+ include_credentials=include_credentials,
255
+ )
256
+
257
+ def run_on_cloud(
218
258
  self,
219
259
  deployment_name: str,
220
260
  teamspace: Teamspace,
@@ -229,18 +269,44 @@ Update [underline]{os.path.abspath("Dockerfile")}[/underline] to add any additio
229
269
  port: Optional[int] = 8000,
230
270
  include_credentials: Optional[bool] = True,
231
271
  ) -> dict:
272
+ """Run a deployment on the cloud. If the deployment already exists, it will be updated.
273
+
274
+ Args:
275
+ deployment_name: The name of the deployment.
276
+ teamspace: The teamspace to run the deployment on.
277
+ image: The image to run the deployment on.
278
+ metric: The metric to use for autoscaling. Defaults to None.
279
+ machine: The machine to run the deployment on. Defaults to None.
280
+ min_replica: The minimum number of replicas to run. Defaults to 0.
281
+ max_replica: The maximum number of replicas to run. Defaults to 1.
282
+ spot: Whether to run the deployment on spot instances. Defaults to None.
283
+ replicas: The number of replicas to run. Defaults to 1.
284
+ cloud_account: The cloud account to run the deployment on. Defaults to None.
285
+ port: The port to run the deployment on. Defaults to 8000.
286
+ include_credentials: Whether to include credentials in the deployment. Defaults to True.
287
+
288
+ Returns:
289
+ dict: The deployment and the URL of the deployment.
290
+ """
232
291
  url = f"{_get_cloud_url()}/{teamspace.owner.name}/{teamspace.name}/jobs/{deployment_name}"
233
292
  machine = machine or Machine.CPU
234
293
  metric = metric or ("CPU" if machine.is_cpu() else "GPU")
235
294
  deployment = Deployment(deployment_name, teamspace)
236
295
  if deployment.is_started:
237
- raise RuntimeError(
238
- f"Deployment with name {deployment_name} already running: {url} \n"
239
- "To update the deployment, use the Deployment API:\n"
240
- "from lightning_sdk import Deployment\n"
241
- f"deployment = Deployment('{deployment_name}', teamspace)\n"
242
- "deployment.update(...)"
296
+ self._console.print(f"Deployment with name {deployment_name} already running. Updating the deployment.")
297
+ self._update_deployment(
298
+ deployment,
299
+ machine,
300
+ image,
301
+ min_replica=min_replica,
302
+ max_replica=max_replica,
303
+ spot=spot,
304
+ replicas=replicas,
305
+ cloud_account=cloud_account,
306
+ port=port,
307
+ include_credentials=include_credentials,
243
308
  )
309
+ return {"deployment": deployment, "url": url, "updated": True}
244
310
  autoscale = AutoScaleConfig(min_replicas=min_replica, max_replicas=max_replica, metric=metric, threshold=0.95)
245
311
  deployment.start(
246
312
  machine=machine,