remotivelabs-cli 0.3.2__py3-none-any.whl → 0.3.4__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 remotivelabs-cli might be problematic. Click here for more details.
- cli/cloud/auth/login.py +3 -26
- cli/cloud/auth_tokens.py +4 -1
- cli/topology/cmd.py +43 -9
- cli/topology/start_trial.py +46 -17
- {remotivelabs_cli-0.3.2.dist-info → remotivelabs_cli-0.3.4.dist-info}/METADATA +1 -1
- {remotivelabs_cli-0.3.2.dist-info → remotivelabs_cli-0.3.4.dist-info}/RECORD +9 -9
- {remotivelabs_cli-0.3.2.dist-info → remotivelabs_cli-0.3.4.dist-info}/LICENSE +0 -0
- {remotivelabs_cli-0.3.2.dist-info → remotivelabs_cli-0.3.4.dist-info}/WHEEL +0 -0
- {remotivelabs_cli-0.3.2.dist-info → remotivelabs_cli-0.3.4.dist-info}/entry_points.txt +0 -0
cli/cloud/auth/login.py
CHANGED
|
@@ -184,32 +184,9 @@ def login(headless: bool = False) -> bool: # noqa: C901, PLR0915
|
|
|
184
184
|
Initiate login
|
|
185
185
|
"""
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
active_token_file = settings.get_active_token_file()
|
|
192
|
-
if active_token_file:
|
|
193
|
-
# check if the active token is valid, if not, prompt user to select a new token
|
|
194
|
-
if not Rest.has_access("/api/whoami") or active_token_file.is_expired():
|
|
195
|
-
settings.clear_active_account()
|
|
196
|
-
newly_activated_token_file = _do_prompt_to_use_existing_credentials()
|
|
197
|
-
if newly_activated_token_file:
|
|
198
|
-
return True
|
|
199
|
-
|
|
200
|
-
# intentional fall through to login since we have no token
|
|
201
|
-
|
|
202
|
-
else:
|
|
203
|
-
# no active token, prompt user to select a new token
|
|
204
|
-
newly_activated_token_file = _do_prompt_to_use_existing_credentials()
|
|
205
|
-
if newly_activated_token_file:
|
|
206
|
-
return True
|
|
207
|
-
|
|
208
|
-
# intentional fall through to login since we have no token
|
|
209
|
-
|
|
210
|
-
#
|
|
211
|
-
# 2. Login in if no valid token found...
|
|
212
|
-
#
|
|
187
|
+
newly_activated_token_file = _do_prompt_to_use_existing_credentials()
|
|
188
|
+
if newly_activated_token_file:
|
|
189
|
+
return True
|
|
213
190
|
|
|
214
191
|
prepare_local_webserver()
|
|
215
192
|
|
cli/cloud/auth_tokens.py
CHANGED
|
@@ -19,7 +19,7 @@ def _prompt_choice( # noqa: C901
|
|
|
19
19
|
) -> Optional[TokenFile]:
|
|
20
20
|
accounts = settings.list_accounts()
|
|
21
21
|
|
|
22
|
-
table = Table("#", "Active", "Type", "Token", "Account", "Created", "Expires")
|
|
22
|
+
table = Table("#", "Active", "Type", "Token ID", "Account", "Created", "Expires")
|
|
23
23
|
|
|
24
24
|
included_tokens: list[TokenFile] = []
|
|
25
25
|
excluded_tokens: list[TokenFile] = []
|
|
@@ -56,6 +56,9 @@ def _prompt_choice( # noqa: C901
|
|
|
56
56
|
str(choice.expires),
|
|
57
57
|
)
|
|
58
58
|
print_unformatted(table)
|
|
59
|
+
print_unformatted(
|
|
60
|
+
":point_right: To get the access token for your activated account, use [bold]remotive cloud auth print-access-token[/bold]"
|
|
61
|
+
)
|
|
59
62
|
|
|
60
63
|
if skip_prompt:
|
|
61
64
|
return None
|
cli/topology/cmd.py
CHANGED
|
@@ -5,10 +5,12 @@ import typer
|
|
|
5
5
|
from cli.topology.start_trial import (
|
|
6
6
|
MissingOrganizationError,
|
|
7
7
|
NoActiveAccountError,
|
|
8
|
+
NoOrganizationOrPermissionError,
|
|
8
9
|
NotAuthorizedError,
|
|
9
10
|
NotAuthorizedToStartTrialError,
|
|
10
11
|
NotSignedInError,
|
|
11
12
|
SubscriptionExpiredError,
|
|
13
|
+
get_organization_and_account,
|
|
12
14
|
start_trial,
|
|
13
15
|
)
|
|
14
16
|
from cli.typer import typer_utils
|
|
@@ -30,12 +32,34 @@ def start_trial_cmd( # noqa: C901
|
|
|
30
32
|
|
|
31
33
|
You can read more at https://docs.remotivelabs.com/docs/remotive-topology.
|
|
32
34
|
"""
|
|
35
|
+
|
|
33
36
|
try:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
(valid_organization, _) = get_organization_and_account(organization_uid=organization)
|
|
38
|
+
ok_to_start_trial = typer.confirm(
|
|
39
|
+
f"You are about to start trial of RemotiveTopology for {valid_organization.display_name}"
|
|
40
|
+
f" (uid={valid_organization.uid}), continue?",
|
|
41
|
+
default=True,
|
|
42
|
+
)
|
|
43
|
+
if not ok_to_start_trial:
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
(subscription, created) = start_trial(organization)
|
|
47
|
+
|
|
48
|
+
def print_start_trial_result() -> None:
|
|
49
|
+
assert subscription.type in ("trial", "paid"), f"Unexpected subscription type: {subscription.type}"
|
|
50
|
+
kind = None
|
|
51
|
+
status = None
|
|
52
|
+
if subscription.type == "trial":
|
|
53
|
+
status = "started now" if created else "is already active"
|
|
54
|
+
kind = "trial subscription"
|
|
55
|
+
elif subscription.type == "paid":
|
|
56
|
+
status = "started now" if created else "is already started"
|
|
57
|
+
kind = "subscription"
|
|
58
|
+
|
|
59
|
+
end_text = subscription.end_date or "Never"
|
|
60
|
+
print_generic_message(f"RemotiveTopology {kind} for {valid_organization.display_name} {status}, expires {end_text}")
|
|
61
|
+
|
|
62
|
+
print_start_trial_result()
|
|
39
63
|
|
|
40
64
|
except NotSignedInError:
|
|
41
65
|
print_generic_error(
|
|
@@ -46,7 +70,7 @@ def start_trial_cmd( # noqa: C901
|
|
|
46
70
|
|
|
47
71
|
except NoActiveAccountError:
|
|
48
72
|
print_hint(
|
|
49
|
-
"You have not
|
|
73
|
+
"You have not activated your account, please run [bold]remotive cloud auth activate[/bold] to choose an account"
|
|
50
74
|
"or [bold]remotive cloud auth login[/bold] to sign-in"
|
|
51
75
|
)
|
|
52
76
|
raise typer.Exit(3)
|
|
@@ -63,15 +87,25 @@ def start_trial_cmd( # noqa: C901
|
|
|
63
87
|
raise typer.Exit(5)
|
|
64
88
|
|
|
65
89
|
except NotAuthorizedToStartTrialError as e:
|
|
66
|
-
print_generic_error(f"You are not allowed to start-trial topology in organization {e.organization}")
|
|
90
|
+
print_generic_error(f"You are not allowed to start-trial topology in organization {e.organization.display_name}.")
|
|
67
91
|
raise typer.Exit(6)
|
|
68
92
|
|
|
69
93
|
except SubscriptionExpiredError as e:
|
|
70
94
|
if e.subscription.type == "trial":
|
|
71
|
-
print_generic_error(
|
|
95
|
+
print_generic_error(
|
|
96
|
+
f"RemotiveTopology trial in {e.organization.display_name} expired"
|
|
97
|
+
f" {e.subscription.end_date}, please contact support@remotivelabs.com"
|
|
98
|
+
)
|
|
72
99
|
raise typer.Exit(7)
|
|
73
100
|
|
|
74
|
-
print_generic_error(
|
|
101
|
+
print_generic_error(
|
|
102
|
+
f"RemotiveTopology subscription in {e.organization.display_name} has expired"
|
|
103
|
+
f" {e.subscription.end_date}, please contact support@remotivelabs.com"
|
|
104
|
+
)
|
|
105
|
+
raise typer.Exit(7)
|
|
106
|
+
|
|
107
|
+
except NoOrganizationOrPermissionError as e:
|
|
108
|
+
print_generic_error(f"Organization id {e.organization} does not exist or you do not have permission to access it.")
|
|
75
109
|
raise typer.Exit(7)
|
|
76
110
|
|
|
77
111
|
except Exception as e:
|
cli/topology/start_trial.py
CHANGED
|
@@ -26,6 +26,14 @@ class NotAuthorizedError(Exception):
|
|
|
26
26
|
self.account = account
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
class NoOrganizationOrPermissionError(Exception):
|
|
30
|
+
"""Raised when the user is trying to access an organization that it does not have access to or it does not exist"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, account: Account, organization_uid: str):
|
|
33
|
+
self.account = account
|
|
34
|
+
self.organization = organization_uid
|
|
35
|
+
|
|
36
|
+
|
|
29
37
|
class MissingOrganizationError(Exception):
|
|
30
38
|
"""Raised when the user has not specified an organization and no default organization is set"""
|
|
31
39
|
|
|
@@ -33,7 +41,7 @@ class MissingOrganizationError(Exception):
|
|
|
33
41
|
class NotAuthorizedToStartTrialError(Exception):
|
|
34
42
|
"""Raised when the user is not authorized to start a topology trial"""
|
|
35
43
|
|
|
36
|
-
def __init__(self, account: Account, organization:
|
|
44
|
+
def __init__(self, account: Account, organization: Organization):
|
|
37
45
|
self.account = account
|
|
38
46
|
self.organization = organization
|
|
39
47
|
|
|
@@ -41,8 +49,15 @@ class NotAuthorizedToStartTrialError(Exception):
|
|
|
41
49
|
class SubscriptionExpiredError(Exception):
|
|
42
50
|
"""Raised when the subscription has expired"""
|
|
43
51
|
|
|
44
|
-
def __init__(self, subscription: Subscription):
|
|
52
|
+
def __init__(self, subscription: Subscription, organization: Organization):
|
|
45
53
|
self.subscription = subscription
|
|
54
|
+
self.organization = organization
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class Organization:
|
|
59
|
+
uid: str
|
|
60
|
+
display_name: str
|
|
46
61
|
|
|
47
62
|
|
|
48
63
|
@dataclass
|
|
@@ -67,12 +82,7 @@ class Subscription:
|
|
|
67
82
|
)
|
|
68
83
|
|
|
69
84
|
|
|
70
|
-
def
|
|
71
|
-
"""
|
|
72
|
-
Start a 30 day trial subscription for running RemotiveTopology.
|
|
73
|
-
|
|
74
|
-
# TODO: move authentication (and basic authorization) to a logged_in decorator
|
|
75
|
-
"""
|
|
85
|
+
def get_organization_and_account(organization_uid: str | None = None) -> tuple[Organization, Account]:
|
|
76
86
|
active_account = settings.get_active_account()
|
|
77
87
|
active_token_file = settings.get_active_token_file()
|
|
78
88
|
|
|
@@ -84,22 +94,41 @@ def start_trial(organization: str | None = None) -> Subscription:
|
|
|
84
94
|
if not RestHelper.has_access("/api/whoami"):
|
|
85
95
|
raise NotAuthorizedError(account=active_account)
|
|
86
96
|
|
|
87
|
-
|
|
88
|
-
if not
|
|
97
|
+
org_uid = organization_uid or active_account.default_organization
|
|
98
|
+
if not org_uid:
|
|
89
99
|
raise MissingOrganizationError()
|
|
90
100
|
|
|
91
|
-
|
|
101
|
+
response = RestHelper.handle_get(f"/api/bu/{organization_uid}", return_response=True, allow_status_codes=[403, 404])
|
|
102
|
+
if response.status_code in (403, 404):
|
|
103
|
+
raise NoOrganizationOrPermissionError(account=active_account, organization_uid=org_uid)
|
|
104
|
+
|
|
105
|
+
display_name = response.json()["displayName"]
|
|
106
|
+
|
|
107
|
+
return Organization(uid=org_uid, display_name=display_name), active_account
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def start_trial(organization_uid: str | None = None) -> tuple[Subscription, bool]:
|
|
111
|
+
"""
|
|
112
|
+
Start a 30 day trial subscription for running RemotiveTopology,
|
|
113
|
+
If a trial is already started in this organization, returns the existing trial instead.
|
|
114
|
+
Returns (subscription, created_now).
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
(organization, active_account) = get_organization_and_account(organization_uid)
|
|
118
|
+
|
|
119
|
+
res = RestHelper.handle_get(f"/api/bu/{organization.uid}/features/topology", return_response=True, allow_status_codes=[403, 404])
|
|
92
120
|
if res.status_code == 403:
|
|
93
|
-
raise NotAuthorizedToStartTrialError(account=active_account, organization=
|
|
121
|
+
raise NotAuthorizedToStartTrialError(account=active_account, organization=organization)
|
|
122
|
+
|
|
123
|
+
created_now = False
|
|
94
124
|
if res.status_code == 404:
|
|
95
|
-
created = RestHelper.handle_post(f"/api/bu/{
|
|
125
|
+
created = RestHelper.handle_post(f"/api/bu/{organization.uid}/features/topology", return_response=True)
|
|
96
126
|
subscription = Subscription.from_dict(created.json())
|
|
127
|
+
created_now = True
|
|
97
128
|
else:
|
|
98
|
-
# 200 OK means we already have a valid subscription
|
|
99
129
|
subscription = Subscription.from_dict(res.json())
|
|
100
130
|
|
|
101
|
-
# check subscription validity
|
|
102
131
|
if subscription.end_date < datetime.datetime.now().date():
|
|
103
|
-
raise SubscriptionExpiredError(subscription=subscription)
|
|
132
|
+
raise SubscriptionExpiredError(subscription=subscription, organization=organization)
|
|
104
133
|
|
|
105
|
-
return subscription
|
|
134
|
+
return subscription, created_now
|
|
@@ -19,8 +19,8 @@ cli/broker/signals.py,sha256=1xldsY3SVcVp-EEsrd6_uoBjrTRMSEONHpOA6SmWxJ4,8245
|
|
|
19
19
|
cli/cloud/__init__.py,sha256=xFaDg2zho_glvDBDB0_8HRNICVwHeYFEz-yMhzTcCjI,987
|
|
20
20
|
cli/cloud/auth/__init__.py,sha256=MtQ01-n8CgZb9Y_SvxwZUgj44Yo0dFAU3_XwhQiUYtw,54
|
|
21
21
|
cli/cloud/auth/cmd.py,sha256=lv9D0Q7G1RgI2IO1vkz_VVBA_STCPmdJax3QkeiMwg4,3968
|
|
22
|
-
cli/cloud/auth/login.py,sha256=
|
|
23
|
-
cli/cloud/auth_tokens.py,sha256=
|
|
22
|
+
cli/cloud/auth/login.py,sha256=s_VdOunFLFWVl68sGTJgaJNksQquYGTfm5pJ6mBbEx0,10321
|
|
23
|
+
cli/cloud/auth_tokens.py,sha256=Tj6-fMkOGjT_XHU8m8nMQcIj55MaLwqfedv15yKsYp0,5225
|
|
24
24
|
cli/cloud/brokers.py,sha256=cXYKm_-CYJZH0muXAPwUMKIiqBiW6Y9WG5kmkQb3FuU,3849
|
|
25
25
|
cli/cloud/configs.py,sha256=atInBsh16woPmjC0dpnRTpbY4WRgseBOWe8VwpqwO_o,3745
|
|
26
26
|
cli/cloud/licenses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -58,8 +58,8 @@ cli/tools/can/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
58
58
|
cli/tools/can/can.py,sha256=ovTqzsjJP-z9H5RiJ3f_OXMpELqM3d09JY4JfPpT3-Q,2171
|
|
59
59
|
cli/tools/tools.py,sha256=jhLfrFDqkmWV3eBAzNwBf6WgDGrz7sOhgVCia36Twn8,232
|
|
60
60
|
cli/topology/__init__.py,sha256=MyorYLmC2wAd_z5GdQENEYLgoCiNYgwQ16BOX93IBtI,52
|
|
61
|
-
cli/topology/cmd.py,sha256=
|
|
62
|
-
cli/topology/start_trial.py,sha256=
|
|
61
|
+
cli/topology/cmd.py,sha256=TCSwURxTmAyU4Lvu-Rk8ymPardmAARuFEn-kTckksvw,4408
|
|
62
|
+
cli/topology/start_trial.py,sha256=b0PWAFS9Q67kCLq9zZ-t6vl0c3WMiF4BF4nN5yqyZ-I,4538
|
|
63
63
|
cli/typer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
64
|
cli/typer/typer_utils.py,sha256=eUrVOEOKY_MnfiJMAxvEurP1Q79z9pq83mJjocP8lhI,686
|
|
65
65
|
cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -67,8 +67,8 @@ cli/utils/console.py,sha256=JF39S9oS1lehFexjdLQKp17oINNvFZJLg_M2SDCjkvA,1754
|
|
|
67
67
|
cli/utils/rest_helper.py,sha256=ZHc7TMNVa07kJWDQ_OEoeaGhzYu8BinSXJJX8R_wX_8,14135
|
|
68
68
|
cli/utils/time.py,sha256=TEKcNZ-pQoJ7cZ6hQmVD0sTRwRm2rBy51-MuDNdO4S4,296
|
|
69
69
|
cli/utils/versions.py,sha256=mHs_BCk0-wwPfCHIIQBlpFkgipSWkw9jUaZ-USH8ODY,3824
|
|
70
|
-
remotivelabs_cli-0.3.
|
|
71
|
-
remotivelabs_cli-0.3.
|
|
72
|
-
remotivelabs_cli-0.3.
|
|
73
|
-
remotivelabs_cli-0.3.
|
|
74
|
-
remotivelabs_cli-0.3.
|
|
70
|
+
remotivelabs_cli-0.3.4.dist-info/LICENSE,sha256=qDPP_yfuv1fF-u7EfexN-cN3M8aFgGVndGhGLovLKz0,608
|
|
71
|
+
remotivelabs_cli-0.3.4.dist-info/METADATA,sha256=ROqIXVSgE__Tey6UbKorZorckyXtHcvSRc21IeMQqEE,1521
|
|
72
|
+
remotivelabs_cli-0.3.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
73
|
+
remotivelabs_cli-0.3.4.dist-info/entry_points.txt,sha256=lvDhPgagLqW_KTnLPCwKSqfYlEp-1uYVosRiPjsVj10,45
|
|
74
|
+
remotivelabs_cli-0.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|