remotivelabs-cli 0.3.3__tar.gz → 0.3.5__tar.gz

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.

Files changed (73) hide show
  1. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/PKG-INFO +1 -1
  2. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/signals.py +1 -1
  3. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/core.py +12 -1
  4. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/topology/cmd.py +43 -9
  5. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/topology/start_trial.py +46 -17
  6. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/utils/rest_helper.py +3 -1
  7. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/pyproject.toml +1 -1
  8. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/LICENSE +0 -0
  9. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/README.md +0 -0
  10. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/.DS_Store +0 -0
  11. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/__init__.py +0 -0
  12. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/api/cloud/tokens.py +0 -0
  13. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/__init__.py +0 -0
  14. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/discovery.py +0 -0
  15. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/export.py +0 -0
  16. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/files.py +0 -0
  17. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/lib/__about__.py +0 -0
  18. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/lib/broker.py +0 -0
  19. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/lib/client.py +0 -0
  20. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/lib/helper.py +0 -0
  21. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/lib/signalcreator.py +0 -0
  22. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/license_flows.py +0 -0
  23. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/licenses.py +0 -0
  24. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/playback.py +0 -0
  25. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/record.py +0 -0
  26. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/broker/scripting.py +0 -0
  27. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/__init__.py +0 -0
  28. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/auth/__init__.py +0 -0
  29. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/auth/cmd.py +0 -0
  30. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/auth/login.py +0 -0
  31. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/auth_tokens.py +0 -0
  32. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/brokers.py +0 -0
  33. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/configs.py +0 -0
  34. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/licenses/__init__.py +0 -0
  35. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/licenses/cmd.py +0 -0
  36. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/organisations.py +0 -0
  37. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/projects.py +0 -0
  38. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/recordings.py +0 -0
  39. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/recordings_playback.py +0 -0
  40. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/resumable_upload.py +0 -0
  41. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/sample_recordings.py +0 -0
  42. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/service_account_tokens.py +0 -0
  43. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/service_accounts.py +0 -0
  44. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/storage/__init__.py +0 -0
  45. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/storage/cmd.py +0 -0
  46. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/storage/copy.py +0 -0
  47. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/storage/uri_or_path.py +0 -0
  48. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/cloud/uri.py +0 -0
  49. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/connect/__init__.py +0 -0
  50. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/connect/connect.py +0 -0
  51. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/connect/protopie/protopie.py +0 -0
  52. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/remotive.py +0 -0
  53. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/__init__.py +0 -0
  54. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/config_file.py +0 -0
  55. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/migration/__init__.py +0 -0
  56. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/migration/migrate_all_token_files.py +0 -0
  57. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/migration/migrate_config_file.py +0 -0
  58. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/migration/migrate_legacy_dirs.py +0 -0
  59. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/migration/migrate_token_file.py +0 -0
  60. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/migration/migration_tools.py +0 -0
  61. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/state_file.py +0 -0
  62. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/settings/token_file.py +0 -0
  63. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/tools/__init__.py +0 -0
  64. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/tools/can/__init__.py +0 -0
  65. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/tools/can/can.py +0 -0
  66. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/tools/tools.py +0 -0
  67. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/topology/__init__.py +0 -0
  68. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/typer/__init__.py +0 -0
  69. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/typer/typer_utils.py +0 -0
  70. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/utils/__init__.py +0 -0
  71. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/utils/console.py +0 -0
  72. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/utils/time.py +0 -0
  73. {remotivelabs_cli-0.3.3 → remotivelabs_cli-0.3.5}/cli/utils/versions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: remotivelabs-cli
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Summary: CLI for operating RemotiveCloud and RemotiveBroker
5
5
  Author: Johan Rask
6
6
  Author-email: johan.rask@remotivelabs.com
@@ -198,7 +198,7 @@ def namespaces(
198
198
 
199
199
  @app.command()
200
200
  def frame_distribution(
201
- url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
201
+ url: str = typer.Option(DEFAULT_GRPC_URL, help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
202
202
  api_key: str = typer.Option(None, help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
203
203
  namespace: str = typer.Option(..., help="Namespace"),
204
204
  ) -> None:
@@ -22,6 +22,10 @@ CONFIG_DIR_PATH = Path.home() / ".config" / "remotive"
22
22
  CLI_CONFIG_FILE_NAME = "config.json"
23
23
  CLI_INTERNAL_STATE_FILE_NAME = "app-state.json"
24
24
 
25
+ TOKEN_ENV = "REMOTIVE_CLOUD_AUTH_TOKEN"
26
+ # Deprecated in favour of name used in topology-cli
27
+ DEPR_TOKEN_ENV = "REMOTIVE_CLOUD_ACCESS_TOKEN"
28
+
25
29
 
26
30
  class InvalidSettingsFilePathError(Exception):
27
31
  """Raised when trying to access an invalid settings file or file path"""
@@ -91,8 +95,15 @@ class Settings:
91
95
 
92
96
  def get_active_token(self) -> str | None:
93
97
  """
94
- Get the token secret for the current active account
98
+ Get the token secret for the current active account or token specified by env variable
95
99
  """
100
+
101
+ token = os.environ[DEPR_TOKEN_ENV] if DEPR_TOKEN_ENV in os.environ else None
102
+ if not token:
103
+ token = os.environ[TOKEN_ENV] if TOKEN_ENV in os.environ else None
104
+ if token:
105
+ return token
106
+
96
107
  token_file = self.get_active_token_file()
97
108
  return token_file.token if token_file else None
98
109
 
@@ -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
- subscription = start_trial(organization)
35
- if subscription.type == "trial":
36
- print_generic_message(f"topology trial active, expires {subscription.end_date}")
37
- elif subscription.type == "paid":
38
- print_generic_message(f"you already have a topology subscription, expires {subscription.end_date or 'Never'}")
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 actived your account, please run [bold]remotive cloud auth activate[/bold] to choose an account"
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(f"Your Topology trial expired {e.subscription.end_date}, please contact support@remotivelabs.com")
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(f"Your Topology subscription has expired {e.subscription.end_date}, please contact support@remotivelabs.com")
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:
@@ -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: str):
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 start_trial(organization: str | None = None) -> Subscription:
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
- valid_org = organization or active_account.default_organization
88
- if not valid_org:
97
+ org_uid = organization_uid or active_account.default_organization
98
+ if not org_uid:
89
99
  raise MissingOrganizationError()
90
100
 
91
- res = RestHelper.handle_get(f"/api/bu/{valid_org}/features/topology", return_response=True, allow_status_codes=[403, 404])
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=valid_org)
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/{valid_org}/features/topology", return_response=True)
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
@@ -85,6 +85,7 @@ class RestHelper:
85
85
  TODO: remove setting org, as we already set the default organization as env in remotive.py?
86
86
  TODO: don't sys.exit, raise error instead
87
87
  """
88
+
88
89
  if "REMOTIVE_CLOUD_ORGANIZATION" not in os.environ:
89
90
  active_account = settings.get_active_account()
90
91
  if active_account:
@@ -94,7 +95,8 @@ class RestHelper:
94
95
 
95
96
  token = access_token
96
97
  if not token:
97
- token = os.environ.get("REMOTIVE_CLOUD_ACCESS_TOKEN", settings.get_active_token())
98
+ token = settings.get_active_token()
99
+
98
100
  if not token:
99
101
  if quiet:
100
102
  return
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "remotivelabs-cli"
3
- version = "0.3.3"
3
+ version = "0.3.5"
4
4
  description = "CLI for operating RemotiveCloud and RemotiveBroker"
5
5
  authors = ["Johan Rask <johan.rask@remotivelabs.com>"]
6
6
  readme = "README.md"