remotivelabs-cli 0.5.0a1__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.
- remotivelabs/cli/__init__.py +0 -0
- remotivelabs/cli/api/cloud/tokens.py +62 -0
- remotivelabs/cli/broker/__init__.py +33 -0
- remotivelabs/cli/broker/defaults.py +1 -0
- remotivelabs/cli/broker/discovery.py +43 -0
- remotivelabs/cli/broker/export.py +92 -0
- remotivelabs/cli/broker/files.py +119 -0
- remotivelabs/cli/broker/lib/__about__.py +4 -0
- remotivelabs/cli/broker/lib/broker.py +625 -0
- remotivelabs/cli/broker/lib/client.py +224 -0
- remotivelabs/cli/broker/lib/helper.py +277 -0
- remotivelabs/cli/broker/lib/signalcreator.py +196 -0
- remotivelabs/cli/broker/license_flows.py +167 -0
- remotivelabs/cli/broker/licenses.py +98 -0
- remotivelabs/cli/broker/playback.py +117 -0
- remotivelabs/cli/broker/record.py +41 -0
- remotivelabs/cli/broker/recording_session/__init__.py +3 -0
- remotivelabs/cli/broker/recording_session/client.py +67 -0
- remotivelabs/cli/broker/recording_session/cmd.py +254 -0
- remotivelabs/cli/broker/recording_session/time.py +49 -0
- remotivelabs/cli/broker/scripting.py +129 -0
- remotivelabs/cli/broker/signals.py +220 -0
- remotivelabs/cli/broker/version.py +31 -0
- remotivelabs/cli/cloud/__init__.py +17 -0
- remotivelabs/cli/cloud/auth/__init__.py +3 -0
- remotivelabs/cli/cloud/auth/cmd.py +128 -0
- remotivelabs/cli/cloud/auth/login.py +283 -0
- remotivelabs/cli/cloud/auth_tokens.py +149 -0
- remotivelabs/cli/cloud/brokers.py +109 -0
- remotivelabs/cli/cloud/configs.py +109 -0
- remotivelabs/cli/cloud/licenses/__init__.py +0 -0
- remotivelabs/cli/cloud/licenses/cmd.py +14 -0
- remotivelabs/cli/cloud/organisations.py +112 -0
- remotivelabs/cli/cloud/projects.py +44 -0
- remotivelabs/cli/cloud/recordings.py +580 -0
- remotivelabs/cli/cloud/recordings_playback.py +274 -0
- remotivelabs/cli/cloud/resumable_upload.py +87 -0
- remotivelabs/cli/cloud/sample_recordings.py +25 -0
- remotivelabs/cli/cloud/service_account_tokens.py +62 -0
- remotivelabs/cli/cloud/service_accounts.py +72 -0
- remotivelabs/cli/cloud/storage/__init__.py +5 -0
- remotivelabs/cli/cloud/storage/cmd.py +76 -0
- remotivelabs/cli/cloud/storage/copy.py +86 -0
- remotivelabs/cli/cloud/storage/uri_or_path.py +45 -0
- remotivelabs/cli/cloud/uri.py +113 -0
- remotivelabs/cli/connect/__init__.py +0 -0
- remotivelabs/cli/connect/connect.py +118 -0
- remotivelabs/cli/connect/protopie/protopie.py +185 -0
- remotivelabs/cli/py.typed +0 -0
- remotivelabs/cli/remotive.py +123 -0
- remotivelabs/cli/settings/__init__.py +20 -0
- remotivelabs/cli/settings/config_file.py +113 -0
- remotivelabs/cli/settings/core.py +333 -0
- remotivelabs/cli/settings/migration/__init__.py +0 -0
- remotivelabs/cli/settings/migration/migrate_all_token_files.py +80 -0
- remotivelabs/cli/settings/migration/migrate_config_file.py +64 -0
- remotivelabs/cli/settings/migration/migrate_legacy_dirs.py +50 -0
- remotivelabs/cli/settings/migration/migrate_token_file.py +52 -0
- remotivelabs/cli/settings/migration/migration_tools.py +38 -0
- remotivelabs/cli/settings/state_file.py +67 -0
- remotivelabs/cli/settings/token_file.py +128 -0
- remotivelabs/cli/tools/__init__.py +0 -0
- remotivelabs/cli/tools/can/__init__.py +0 -0
- remotivelabs/cli/tools/can/can.py +78 -0
- remotivelabs/cli/tools/tools.py +9 -0
- remotivelabs/cli/topology/__init__.py +28 -0
- remotivelabs/cli/topology/all.py +322 -0
- remotivelabs/cli/topology/cli/__init__.py +3 -0
- remotivelabs/cli/topology/cli/run_in_docker.py +58 -0
- remotivelabs/cli/topology/cli/topology_cli.py +16 -0
- remotivelabs/cli/topology/cmd.py +130 -0
- remotivelabs/cli/topology/start_trial.py +134 -0
- remotivelabs/cli/typer/__init__.py +0 -0
- remotivelabs/cli/typer/typer_utils.py +27 -0
- remotivelabs/cli/utils/__init__.py +0 -0
- remotivelabs/cli/utils/console.py +99 -0
- remotivelabs/cli/utils/rest_helper.py +369 -0
- remotivelabs/cli/utils/time.py +11 -0
- remotivelabs/cli/utils/versions.py +120 -0
- remotivelabs_cli-0.5.0a1.dist-info/METADATA +51 -0
- remotivelabs_cli-0.5.0a1.dist-info/RECORD +84 -0
- remotivelabs_cli-0.5.0a1.dist-info/WHEEL +4 -0
- remotivelabs_cli-0.5.0a1.dist-info/entry_points.txt +3 -0
- remotivelabs_cli-0.5.0a1.dist-info/licenses/LICENSE +17 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
import shutil
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
import typer
|
|
7
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
8
|
+
|
|
9
|
+
from remotivelabs.cli.typer import typer_utils
|
|
10
|
+
from remotivelabs.cli.utils.console import print_generic_error, print_success
|
|
11
|
+
from remotivelabs.cli.utils.rest_helper import RestHelper as Rest
|
|
12
|
+
|
|
13
|
+
app = typer_utils.create_typer()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.command("list")
|
|
17
|
+
def list_signal_databases(project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")) -> None:
|
|
18
|
+
"""
|
|
19
|
+
List available signal databases in project
|
|
20
|
+
"""
|
|
21
|
+
Rest.handle_get(f"/api/project/{project}/files/config")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@app.command("delete")
|
|
25
|
+
def delete(
|
|
26
|
+
signal_db_file: str = typer.Argument("", help="Signal database file"),
|
|
27
|
+
project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
|
|
28
|
+
) -> None:
|
|
29
|
+
"""
|
|
30
|
+
Deletes the specified signal database
|
|
31
|
+
"""
|
|
32
|
+
Rest.handle_delete(f"/api/project/{project}/files/config/{signal_db_file}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@app.command()
|
|
36
|
+
def upload(
|
|
37
|
+
path: Path = typer.Argument(
|
|
38
|
+
...,
|
|
39
|
+
exists=True,
|
|
40
|
+
file_okay=True,
|
|
41
|
+
dir_okay=False,
|
|
42
|
+
writable=False,
|
|
43
|
+
readable=True,
|
|
44
|
+
resolve_path=True,
|
|
45
|
+
help="Path to signal database file to upload",
|
|
46
|
+
),
|
|
47
|
+
project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
|
|
48
|
+
) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Uploads signal database to project
|
|
51
|
+
"""
|
|
52
|
+
res_text = Rest.handle_put(url=f"/api/project/{project}/files/config/{os.path.basename(path)}/uploadfile", return_response=True)
|
|
53
|
+
if res_text is not None:
|
|
54
|
+
res_json = res_text.json()
|
|
55
|
+
Rest.upload_file_with_signed_url(
|
|
56
|
+
path=path,
|
|
57
|
+
url=res_json["url"],
|
|
58
|
+
upload_headers={"Content-Type": "application/octet-stream"},
|
|
59
|
+
progress_label=f"Uploading {path}...",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@app.command()
|
|
64
|
+
def describe(
|
|
65
|
+
signal_db_file: str = typer.Argument("", help="Signal database file"),
|
|
66
|
+
project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
|
|
67
|
+
) -> None:
|
|
68
|
+
"""
|
|
69
|
+
Shows all metadata related to this signal database
|
|
70
|
+
"""
|
|
71
|
+
Rest.handle_get(f"/api/project/{project}/files/config/{signal_db_file}")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@app.command()
|
|
75
|
+
def download(
|
|
76
|
+
signal_db_file: str = typer.Argument("", help="Signal database file"),
|
|
77
|
+
project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
|
|
78
|
+
) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Downloads the specified signal database to disk
|
|
81
|
+
"""
|
|
82
|
+
with Progress(
|
|
83
|
+
SpinnerColumn(),
|
|
84
|
+
TextColumn("[progress.description]{task.description}"),
|
|
85
|
+
transient=True,
|
|
86
|
+
) as progress:
|
|
87
|
+
Rest.ensure_auth_token()
|
|
88
|
+
|
|
89
|
+
progress.add_task(description=f"Downloading {signal_db_file}", total=None)
|
|
90
|
+
|
|
91
|
+
# First request the download url from cloud. This is a public signed url that is valid
|
|
92
|
+
# for a short period of time
|
|
93
|
+
get_signed_url_resp = requests.get(
|
|
94
|
+
f"{Rest.get_base_url()}/api/project/{project}/files/config/{signal_db_file}/download",
|
|
95
|
+
headers=Rest.get_headers(),
|
|
96
|
+
allow_redirects=True,
|
|
97
|
+
timeout=60,
|
|
98
|
+
)
|
|
99
|
+
if get_signed_url_resp.status_code == 200:
|
|
100
|
+
# Next download the actual file
|
|
101
|
+
download_resp = requests.get(url=get_signed_url_resp.text, stream=True, timeout=60)
|
|
102
|
+
if download_resp.status_code == 200:
|
|
103
|
+
with open(signal_db_file, "wb") as out_file:
|
|
104
|
+
shutil.copyfileobj(download_resp.raw, out_file)
|
|
105
|
+
print_success(f"{signal_db_file} downloaded")
|
|
106
|
+
else:
|
|
107
|
+
print_generic_error(f"Got unexpected status {download_resp.status_code}")
|
|
108
|
+
else:
|
|
109
|
+
print_generic_error(f"Got unexpected status {get_signed_url_resp.status_code}\n")
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from remotivelabs.cli.typer import typer_utils
|
|
4
|
+
from remotivelabs.cli.utils.rest_helper import RestHelper
|
|
5
|
+
|
|
6
|
+
app = typer_utils.create_typer()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@app.command(help="List licenses for an organization")
|
|
10
|
+
def licenses(
|
|
11
|
+
organization: str = typer.Option(..., help="Organization ID", envvar="REMOTIVE_CLOUD_ORGANIZATION"),
|
|
12
|
+
filter_option: str = typer.Option("all", help="all, valid, expired"),
|
|
13
|
+
) -> None:
|
|
14
|
+
RestHelper.handle_get(f"/api/bu/{organization}/licenses", {"filter": filter_option})
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
from remotivelabs.cli.settings import settings
|
|
11
|
+
from remotivelabs.cli.typer import typer_utils
|
|
12
|
+
from remotivelabs.cli.utils.console import (
|
|
13
|
+
print_generic_error,
|
|
14
|
+
print_generic_message,
|
|
15
|
+
print_hint,
|
|
16
|
+
print_newline,
|
|
17
|
+
print_unformatted_to_stderr,
|
|
18
|
+
)
|
|
19
|
+
from remotivelabs.cli.utils.rest_helper import RestHelper
|
|
20
|
+
|
|
21
|
+
app = typer_utils.create_typer()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class Organisation:
|
|
26
|
+
display_name: str
|
|
27
|
+
uid: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _prompt_choice(choices: List[Organisation]) -> Optional[Organisation]:
|
|
31
|
+
table = Table("#", "Name", "Uid", "Default")
|
|
32
|
+
|
|
33
|
+
account = settings.get_active_account()
|
|
34
|
+
current_default_org = account.default_organization if account else None
|
|
35
|
+
|
|
36
|
+
for idx, choice in enumerate(choices, start=1):
|
|
37
|
+
table.add_row(
|
|
38
|
+
f"[yellow]{idx}",
|
|
39
|
+
f"[bold]{choice.display_name}[/bold]",
|
|
40
|
+
choice.uid,
|
|
41
|
+
":thumbsup:" if current_default_org is not None and current_default_org == choice.uid else "",
|
|
42
|
+
)
|
|
43
|
+
print_unformatted_to_stderr(table)
|
|
44
|
+
|
|
45
|
+
print_newline()
|
|
46
|
+
selection = typer.prompt(f"Enter the number(# 1-{len(choices)}) of the organization to select (or q to quit)")
|
|
47
|
+
|
|
48
|
+
if selection == "q":
|
|
49
|
+
return None
|
|
50
|
+
try:
|
|
51
|
+
index = int(selection) - 1
|
|
52
|
+
if 0 <= index < len(choices):
|
|
53
|
+
return choices[index]
|
|
54
|
+
raise ValueError
|
|
55
|
+
except ValueError:
|
|
56
|
+
print_generic_error("Invalid choice, please try again")
|
|
57
|
+
return _prompt_choice(choices)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@app.command("default")
|
|
61
|
+
def select_default_org(
|
|
62
|
+
organization_uid: str = typer.Argument(None, help="Organization uid or empty to select one"),
|
|
63
|
+
get: bool = typer.Option(False, help="Print current default organization"),
|
|
64
|
+
) -> None:
|
|
65
|
+
do_select_default_org(organization_uid, get)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def do_select_default_org(organisation_uid: Optional[str] = None, get: bool = False) -> None:
|
|
69
|
+
r"""
|
|
70
|
+
Set default organization for the currently activated user, empty to choose from available organizations or organization uid as argument
|
|
71
|
+
|
|
72
|
+
remotive cloud organizations default my_org \[set specific org uid]
|
|
73
|
+
remotive cloud organizations default \[select one from prompt]
|
|
74
|
+
remotive cloud organizations default --get \[print current default]
|
|
75
|
+
|
|
76
|
+
Note that service-accounts does Not have permission to list organizations and will get a 403 Forbidden response so you must
|
|
77
|
+
select the organization uid as argument
|
|
78
|
+
"""
|
|
79
|
+
active_account = settings.get_active_account()
|
|
80
|
+
if get:
|
|
81
|
+
if active_account and active_account.default_organization:
|
|
82
|
+
print_unformatted_to_stderr(active_account.default_organization)
|
|
83
|
+
else:
|
|
84
|
+
print_unformatted_to_stderr("No default organization set")
|
|
85
|
+
elif organisation_uid is not None:
|
|
86
|
+
settings.set_default_organisation(organisation_uid)
|
|
87
|
+
else:
|
|
88
|
+
if active_account:
|
|
89
|
+
token = settings.get_token_file(active_account.credentials_file)
|
|
90
|
+
if token and token.type != "authorized_user":
|
|
91
|
+
print_hint(
|
|
92
|
+
"You must supply the organization name as argument when using a service-account since the "
|
|
93
|
+
"service-account is not allowed to list"
|
|
94
|
+
)
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
r = RestHelper.handle_get("/api/bu", return_response=True)
|
|
98
|
+
orgs = r.json()
|
|
99
|
+
orgs = [Organisation(display_name=o["organisation"]["displayName"], uid=o["organisation"]["uid"]) for o in orgs]
|
|
100
|
+
|
|
101
|
+
selected = _prompt_choice(orgs)
|
|
102
|
+
|
|
103
|
+
if selected is not None:
|
|
104
|
+
typer.echo(f"Default organisation: {selected.display_name} (uid: {selected.uid})")
|
|
105
|
+
settings.set_default_organisation(selected.uid)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@app.command(name="list", help="List your available organizations")
|
|
109
|
+
def list_orgs() -> None:
|
|
110
|
+
r = RestHelper.handle_get("/api/bu", return_response=True)
|
|
111
|
+
orgs = [{"uid": org["organisation"]["uid"], "displayName": org["organisation"]["displayName"]} for org in r.json()]
|
|
112
|
+
print_generic_message(json.dumps(orgs))
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from remotivelabs.cli.typer import typer_utils
|
|
6
|
+
from remotivelabs.cli.utils.console import print_generic_error, print_generic_message
|
|
7
|
+
from remotivelabs.cli.utils.rest_helper import RestHelper as Rest
|
|
8
|
+
|
|
9
|
+
app = typer_utils.create_typer()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command(name="list", help="List your projects")
|
|
13
|
+
def list_projects(organization: str = typer.Option(..., help="Organization ID", envvar="REMOTIVE_CLOUD_ORGANIZATION")) -> None:
|
|
14
|
+
r = Rest.handle_get(url=f"/api/bu/{organization}/me", return_response=True)
|
|
15
|
+
if r is None:
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
if r.status_code == 200:
|
|
19
|
+
# extract the project uid parts
|
|
20
|
+
projects = r.json()["projects"]
|
|
21
|
+
projects = map(lambda p: p["uid"], projects)
|
|
22
|
+
print_generic_message(json.dumps(list(projects)))
|
|
23
|
+
else:
|
|
24
|
+
print_generic_error(f"Got unexpected status {r.status_code}\n")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@app.command(name="create")
|
|
28
|
+
def create_project(
|
|
29
|
+
project_uid: str = typer.Argument(help="Project UID"),
|
|
30
|
+
organization: str = typer.Option(..., help="Organization ID", envvar="REMOTIVE_CLOUD_ORGANIZATION"),
|
|
31
|
+
project_display_name: str = typer.Option(default="", help="Project display name"),
|
|
32
|
+
) -> None:
|
|
33
|
+
create_project_req = {
|
|
34
|
+
"uid": project_uid,
|
|
35
|
+
"displayName": project_display_name if project_display_name != "" else project_uid,
|
|
36
|
+
"description": "",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Rest.handle_post(url=f"/api/bu/{organization}/project", body=json.dumps(create_project_req))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@app.command(name="delete")
|
|
43
|
+
def delete(project: str = typer.Argument(help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")) -> None:
|
|
44
|
+
Rest.handle_delete(url=f"/api/project/{project}")
|