lightning-sdk 0.2.18__py3-none-any.whl → 0.2.20__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/deployment_api.py +2 -0
- lightning_sdk/api/license_api.py +28 -6
- lightning_sdk/cli/deploy/_auth.py +11 -19
- lightning_sdk/cli/entrypoint.py +20 -2
- lightning_sdk/deployment/deployment.py +2 -0
- lightning_sdk/lightning_cloud/login.py +2 -2
- lightning_sdk/lightning_cloud/openapi/__init__.py +10 -2
- lightning_sdk/lightning_cloud/openapi/api/__init__.py +1 -0
- lightning_sdk/lightning_cloud/openapi/api/blog_posts_service_api.py +533 -0
- lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +113 -0
- lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +121 -0
- lightning_sdk/lightning_cloud/openapi/models/__init__.py +9 -2
- lightning_sdk/lightning_cloud/openapi/models/alertingevents_id_body.py +409 -0
- lightning_sdk/lightning_cloud/openapi/models/blogposts_id_body.py +253 -0
- lightning_sdk/lightning_cloud/openapi/models/deployments_id_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/id_codeconfig_body.py +29 -3
- lightning_sdk/lightning_cloud/openapi/models/id_transfer_body.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/orgs_id_body.py +157 -157
- lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/update.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_author.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_blog_post.py +383 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template_config.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_state.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_create_blog_post_request.py +253 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_create_cloud_space_environment_template_request.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_daily_usage.py +81 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_data_connection.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_delete_blog_post_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_alerting_policy_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_organization_storage_metadata_response.py +157 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_get_project_storage_metadata_response.py +237 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_get_user_storage_breakdown_response.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_google_cloud_direct_v1.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_list_blog_posts_response.py +175 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_membership.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_message.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_notification_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +261 -157
- lightning_sdk/lightning_cloud/openapi/models/v1_product_license.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_membership.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_storage.py +199 -17
- lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_storage_asset.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_storage_asset_type.py +4 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_transaction.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_transfer_cloud_space_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_usage.py +105 -27
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +249 -145
- lightning_sdk/lightning_cloud/openapi/models/v1_volume.py +499 -31
- lightning_sdk/lightning_cloud/rest_client.py +13 -11
- lightning_sdk/lightning_cloud/source_code/logs_socket_api.py +8 -3
- lightning_sdk/serve.py +1 -0
- lightning_sdk/services/license.py +148 -27
- {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/METADATA +1 -1
- {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/RECORD +66 -58
- lightning_sdk/lightning_cloud/openapi/models/v1_ebs.py +0 -279
- lightning_sdk/lightning_cloud/openapi/models/v1_reservation_billing_session.py +0 -279
- {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/LICENSE +0 -0
- {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/WHEEL +0 -0
- {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/entry_points.txt +0 -0
- {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/top_level.txt +0 -0
|
@@ -3,11 +3,79 @@ import json
|
|
|
3
3
|
import os
|
|
4
4
|
import socket
|
|
5
5
|
import threading
|
|
6
|
+
from contextlib import suppress
|
|
6
7
|
from functools import partial
|
|
8
|
+
from importlib import metadata
|
|
7
9
|
from pathlib import Path
|
|
8
|
-
from typing import Optional
|
|
10
|
+
from typing import Optional, Tuple
|
|
9
11
|
|
|
10
|
-
from lightning_sdk.api.license_api import LicenseApi
|
|
12
|
+
from lightning_sdk.api.license_api import LICENSE_SIGNING_URL, LicenseApi, generate_url_user_settings
|
|
13
|
+
from lightning_sdk.lightning_cloud.login import Auth
|
|
14
|
+
|
|
15
|
+
MESSAGE_NOT_AUTHENTICATED = (
|
|
16
|
+
"┌─────────────────────────────────────────────────────────────────────────┐\n"
|
|
17
|
+
"│ ⚠️ No authenticated user found or license API is not available. │\n"
|
|
18
|
+
"│ │\n"
|
|
19
|
+
"│ Please make sure you are logged in and have a valid license. │\n"
|
|
20
|
+
"│ If you're not logged in, you can use the following command: │\n"
|
|
21
|
+
"│ │\n"
|
|
22
|
+
"│ lightning login │\n"
|
|
23
|
+
"└─────────────────────────────────────────────────────────────────────────┘"
|
|
24
|
+
)
|
|
25
|
+
MESSAGE_AUTH_NO_LICENSE = (
|
|
26
|
+
"┌──────────────────────────────────────────────────────────────────────────────────────────────┐\n"
|
|
27
|
+
"│ ⚠️ No valid license found for the authenticated user for product '{self.product_name}'. │\n"
|
|
28
|
+
"│ │\n"
|
|
29
|
+
"│ Please ensure you have an approved license for this product. │\n"
|
|
30
|
+
"│ If you believe this is an error, please contact support. │\n"
|
|
31
|
+
"│ │\n"
|
|
32
|
+
"│ You can review or update your license settings here: │\n"
|
|
33
|
+
f"│ {LICENSE_SIGNING_URL:<89}│\n"
|
|
34
|
+
"└──────────────────────────────────────────────────────────────────────────────────────────────┘"
|
|
35
|
+
)
|
|
36
|
+
MESSAGE_GUIDE_SIGN_LICENSE = (
|
|
37
|
+
"┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐\n"
|
|
38
|
+
"│ ⚠️ {reason} │\n"
|
|
39
|
+
"│ Details: license key ({license_strats}...{license_ends}) for package {package_name:<56} │\n"
|
|
40
|
+
"│ Please make sure you have signed the license agreement and set the license key. │\n"
|
|
41
|
+
"│ │\n"
|
|
42
|
+
f"│ Sign the license agreement here (if you dont have Lightning account, you will asked to create one): │\n"
|
|
43
|
+
f"│ {generate_url_user_settings():<102}\n"
|
|
44
|
+
"│ │\n"
|
|
45
|
+
"│ Once you have the license key, you may need to reinstall this package to activate it. Use the commands: │\n"
|
|
46
|
+
"│ │\n"
|
|
47
|
+
"│ export LIGHTNING_LICENSE_KEY=<your_license_key> │\n"
|
|
48
|
+
"│ pip install --force-reinstall --no-deps {package_name:<63} │\n"
|
|
49
|
+
"│ │\n"
|
|
50
|
+
"│ For more information, please refer to the documentation. │\n"
|
|
51
|
+
"└───────────────────────────────────────────────────────────────────────────────────────────────────────────┘"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def generate_message_guide_sign_license(package_name: str, reason: str, license_key: str = "") -> str:
|
|
56
|
+
"""Generate a default message for signing the license agreement."""
|
|
57
|
+
if not license_key:
|
|
58
|
+
license_key = "." * 64
|
|
59
|
+
return MESSAGE_GUIDE_SIGN_LICENSE.format(
|
|
60
|
+
package_name=package_name,
|
|
61
|
+
reason=reason.ljust(102, " "),
|
|
62
|
+
license_strats=license_key[:5],
|
|
63
|
+
license_ends=license_key[-5:],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
MESSAGE_WITH_KEY_OFFLINE = (
|
|
68
|
+
"┌──────────────────────────────────────────────────────────────────────────────────────┐\n"
|
|
69
|
+
"│ ⚠️ License key ({license_strats}...{license_ends}) is set, but the system is offline. │\n"
|
|
70
|
+
"│ │\n"
|
|
71
|
+
"│ Please ensure your license key is valid and that the system is connected online. │\n"
|
|
72
|
+
"└──────────────────────────────────────────────────────────────────────────────────────┘"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def generate_message_with_key_offline(license_key: str) -> str:
|
|
77
|
+
"""Generate a message for when the license key is set but the system is offline."""
|
|
78
|
+
return MESSAGE_WITH_KEY_OFFLINE.format(license_strats=license_key[:5], license_ends=license_key[-5:])
|
|
11
79
|
|
|
12
80
|
|
|
13
81
|
class LightningLicense:
|
|
@@ -33,19 +101,57 @@ class LightningLicense:
|
|
|
33
101
|
self._license_api = None
|
|
34
102
|
self._stream_messages = stream_messages
|
|
35
103
|
|
|
104
|
+
@property
|
|
105
|
+
def license_api(self) -> LicenseApi:
|
|
106
|
+
"""Get the LicenseApi instance."""
|
|
107
|
+
if not self._license_api:
|
|
108
|
+
with suppress(ValueError):
|
|
109
|
+
self._license_api = LicenseApi()
|
|
110
|
+
return self._license_api
|
|
111
|
+
|
|
36
112
|
def validate_license(self) -> bool:
|
|
37
113
|
"""Validate the license key."""
|
|
38
114
|
if not self.is_online():
|
|
39
115
|
raise ConnectionError("No internet connection.")
|
|
40
116
|
|
|
41
|
-
self.
|
|
42
|
-
return self._license_api.valid_license(
|
|
117
|
+
return self.license_api.valid_license(
|
|
43
118
|
license_key=self.license_key,
|
|
44
119
|
product_name=self.product_name,
|
|
45
120
|
product_version=self.product_version,
|
|
46
121
|
product_type=self.product_type,
|
|
47
122
|
)
|
|
48
123
|
|
|
124
|
+
def _auth_user_id(self) -> Tuple[Optional[str], Optional[str]]:
|
|
125
|
+
"""Get the authenticated user ID."""
|
|
126
|
+
try:
|
|
127
|
+
auth = Auth()
|
|
128
|
+
except ValueError:
|
|
129
|
+
return None, "No user credentials found. Please run `lightning login` to authenticate."
|
|
130
|
+
return auth.user_id, None
|
|
131
|
+
|
|
132
|
+
def _check_user_license(self, user_id: Optional[str] = None) -> bool:
|
|
133
|
+
"""Check if the authenticated user has a valid license for this product."""
|
|
134
|
+
if not user_id:
|
|
135
|
+
user_id, msg = self._auth_user_id()
|
|
136
|
+
if msg:
|
|
137
|
+
self._stream_messages(msg)
|
|
138
|
+
if not user_id:
|
|
139
|
+
return False
|
|
140
|
+
if not self.license_api:
|
|
141
|
+
self._stream_messages(MESSAGE_NOT_AUTHENTICATED)
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
licenses = self.license_api.list_user_licenses(user_id=user_id)
|
|
145
|
+
for license_info in licenses:
|
|
146
|
+
if (
|
|
147
|
+
license_info.product_name == self.product_name
|
|
148
|
+
and license_info.product_type == self.product_type
|
|
149
|
+
and license_info.is_valid
|
|
150
|
+
):
|
|
151
|
+
return True
|
|
152
|
+
self._stream_messages(MESSAGE_AUTH_NO_LICENSE)
|
|
153
|
+
return False
|
|
154
|
+
|
|
49
155
|
@staticmethod
|
|
50
156
|
def is_online(timeout: float = 2.0) -> bool:
|
|
51
157
|
"""Check if the system is online by attempting to connect to a public DNS server (Google's).
|
|
@@ -75,22 +181,33 @@ class LightningLicense:
|
|
|
75
181
|
if isinstance(self._is_valid, bool):
|
|
76
182
|
# if the license key is already validated, return the cached value
|
|
77
183
|
return self._is_valid
|
|
78
|
-
if not self.product_version:
|
|
79
|
-
self._stream_messages("Product version is not set correctly, consider leave it empty for auto-determine.")
|
|
80
|
-
if not self.license_key:
|
|
81
|
-
self._stream_messages(
|
|
82
|
-
"License key is not set neither cannot be found in the package root or user home."
|
|
83
|
-
" Please make sure you have signed the license agreement and set the license key."
|
|
84
|
-
" For more information, please refer to the documentation.",
|
|
85
|
-
)
|
|
86
184
|
is_online = self.is_online()
|
|
87
|
-
if
|
|
88
|
-
|
|
89
|
-
|
|
185
|
+
if is_online:
|
|
186
|
+
if self.license_key:
|
|
187
|
+
self._is_valid = self.validate_license()
|
|
188
|
+
else:
|
|
189
|
+
# try to check if the session has logged-in user and if the user has a valid license
|
|
190
|
+
self._stream_messages(
|
|
191
|
+
"Missing required license key for license validation."
|
|
192
|
+
f" Attempting to check if the authenticated user has a valid license for {self.product_name}."
|
|
193
|
+
)
|
|
194
|
+
user_id, auth_msg = self._auth_user_id()
|
|
195
|
+
if not user_id:
|
|
196
|
+
self._is_valid = False
|
|
197
|
+
if auth_msg:
|
|
198
|
+
self._stream_messages(auth_msg)
|
|
199
|
+
else:
|
|
200
|
+
self._is_valid = self._check_user_license(user_id=user_id)
|
|
201
|
+
elif self.license_key:
|
|
202
|
+
self._stream_messages(generate_message_with_key_offline(self.license_key))
|
|
203
|
+
else:
|
|
90
204
|
self._stream_messages(
|
|
91
|
-
|
|
92
|
-
|
|
205
|
+
generate_message_guide_sign_license(
|
|
206
|
+
package_name=self.product_name,
|
|
207
|
+
reason="License key is not set neither cannot be found in the package root or user home.",
|
|
208
|
+
)
|
|
93
209
|
)
|
|
210
|
+
|
|
94
211
|
return self._is_valid
|
|
95
212
|
|
|
96
213
|
@property
|
|
@@ -107,14 +224,17 @@ class LightningLicense:
|
|
|
107
224
|
"""
|
|
108
225
|
if not package_name:
|
|
109
226
|
return None
|
|
227
|
+
pkg_spec = importlib.util.find_spec(package_name)
|
|
228
|
+
if pkg_spec is None:
|
|
229
|
+
return None
|
|
230
|
+
pkg_locations = pkg_spec.submodule_search_locations
|
|
231
|
+
if not pkg_locations:
|
|
232
|
+
return None
|
|
110
233
|
try:
|
|
111
|
-
pkg_locations = importlib.util.find_spec(package_name).submodule_search_locations
|
|
112
|
-
if not pkg_locations:
|
|
113
|
-
return None
|
|
114
234
|
license_file = os.path.join(pkg_locations[0], ".license_key")
|
|
115
235
|
with open(license_file) as fp:
|
|
116
236
|
return fp.read().strip()
|
|
117
|
-
except
|
|
237
|
+
except FileNotFoundError:
|
|
118
238
|
return None
|
|
119
239
|
|
|
120
240
|
@staticmethod
|
|
@@ -146,9 +266,8 @@ class LightningLicense:
|
|
|
146
266
|
package_name: The name of the package. If not provided, it will be determined from the current module.
|
|
147
267
|
"""
|
|
148
268
|
try:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
except ImportError:
|
|
269
|
+
return metadata.version(package_name)
|
|
270
|
+
except metadata.PackageNotFoundError:
|
|
152
271
|
return None
|
|
153
272
|
|
|
154
273
|
@property
|
|
@@ -200,9 +319,11 @@ def check_license(
|
|
|
200
319
|
)
|
|
201
320
|
if lit_license.is_valid is False:
|
|
202
321
|
stream_messages(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
322
|
+
generate_message_guide_sign_license(
|
|
323
|
+
package_name=lit_license.product_name,
|
|
324
|
+
reason="License key is not valid or not set.",
|
|
325
|
+
license_key=lit_license.license_key,
|
|
326
|
+
)
|
|
206
327
|
)
|
|
207
328
|
|
|
208
329
|
|