remotivelabs-cli 0.0.24__py3-none-any.whl → 0.0.26__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.
- cli/broker/brokers.py +2 -2
- cli/broker/export.py +5 -5
- cli/broker/files.py +5 -5
- cli/broker/lib/broker.py +59 -49
- cli/broker/license_flows.py +11 -9
- cli/broker/licenses.py +2 -2
- cli/broker/playback.py +14 -34
- cli/broker/record.py +3 -3
- cli/broker/scripting.py +4 -4
- cli/broker/signals.py +11 -11
- cli/cloud/__init__.py +0 -1
- cli/cloud/auth.py +40 -35
- cli/cloud/auth_tokens.py +39 -36
- cli/cloud/brokers.py +24 -33
- cli/cloud/cloud_cli.py +11 -7
- cli/cloud/configs.py +19 -11
- cli/cloud/filestorage.py +155 -0
- cli/cloud/projects.py +10 -7
- cli/cloud/recordings.py +127 -108
- cli/cloud/recordings_playback.py +52 -39
- cli/cloud/rest_helper.py +248 -190
- cli/cloud/resumable_upload.py +62 -0
- cli/cloud/sample_recordings.py +5 -5
- cli/cloud/service_account_tokens.py +18 -16
- cli/cloud/service_accounts.py +9 -9
- cli/connect/__init__.py +0 -1
- cli/connect/connect.py +7 -6
- cli/connect/protopie/protopie.py +32 -16
- cli/errors.py +6 -5
- cli/remotive.py +13 -9
- cli/requirements.txt +4 -1
- cli/settings.py +9 -9
- cli/tools/__init__.py +0 -1
- cli/tools/can/__init__.py +0 -1
- cli/tools/can/can.py +8 -8
- cli/tools/tools.py +2 -2
- {remotivelabs_cli-0.0.24.dist-info → remotivelabs_cli-0.0.26.dist-info}/METADATA +6 -4
- remotivelabs_cli-0.0.26.dist-info/RECORD +44 -0
- remotivelabs_cli-0.0.24.dist-info/RECORD +0 -42
- {remotivelabs_cli-0.0.24.dist-info → remotivelabs_cli-0.0.26.dist-info}/LICENSE +0 -0
- {remotivelabs_cli-0.0.24.dist-info → remotivelabs_cli-0.0.26.dist-info}/WHEEL +0 -0
- {remotivelabs_cli-0.0.24.dist-info → remotivelabs_cli-0.0.26.dist-info}/entry_points.txt +0 -0
cli/broker/record.py
CHANGED
@@ -9,7 +9,7 @@ from cli.errors import ErrorPrinter
|
|
9
9
|
|
10
10
|
from .lib.broker import Broker
|
11
11
|
|
12
|
-
app = typer.Typer(help=help)
|
12
|
+
app = typer.Typer(help=help) # type: ignore
|
13
13
|
|
14
14
|
|
15
15
|
@app.command()
|
@@ -18,7 +18,7 @@ def start(
|
|
18
18
|
namespace: List[str] = typer.Option(..., help="Namespace to record"),
|
19
19
|
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
20
20
|
api_key: str = typer.Option("offline", help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
21
|
-
):
|
21
|
+
) -> None:
|
22
22
|
try:
|
23
23
|
broker = Broker(url, api_key)
|
24
24
|
broker.record_multiple(namespace, filename)
|
@@ -32,7 +32,7 @@ def stop(
|
|
32
32
|
namespace: List[str] = typer.Option(..., help="Namespace to record"),
|
33
33
|
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
34
34
|
api_key: str = typer.Option("offline", help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
35
|
-
):
|
35
|
+
) -> None:
|
36
36
|
try:
|
37
37
|
broker = Broker(url, api_key)
|
38
38
|
broker.stop_multiple(namespace, filename)
|
cli/broker/scripting.py
CHANGED
@@ -16,7 +16,7 @@ app = typer.Typer(
|
|
16
16
|
)
|
17
17
|
|
18
18
|
|
19
|
-
def write(signal_name, script):
|
19
|
+
def write(signal_name: str, script: str) -> None:
|
20
20
|
path = f"{signal_name}.lua"
|
21
21
|
f = open(path, "w")
|
22
22
|
f.write(script)
|
@@ -29,7 +29,7 @@ def new_script(
|
|
29
29
|
input_signal: List[str] = typer.Option(..., help="Required input signal names"),
|
30
30
|
output_signal: str = typer.Option(..., help="Name of output signal"),
|
31
31
|
save: bool = typer.Option(False, help="Save file to disk - Default stored as __output_signal__.lua"),
|
32
|
-
):
|
32
|
+
) -> None:
|
33
33
|
def to_subscribable_signal(sig: str) -> tuple[str, str]:
|
34
34
|
arr = sig.split(":")
|
35
35
|
if len(arr) != 2:
|
@@ -39,7 +39,7 @@ def new_script(
|
|
39
39
|
|
40
40
|
signals_to_subscribe_to = list(map(to_subscribable_signal, input_signal))
|
41
41
|
|
42
|
-
def to_local_signal(sig_name: tuple[str, str]):
|
42
|
+
def to_local_signal(sig_name: tuple[str, str]) -> str:
|
43
43
|
t = Template(
|
44
44
|
"""
|
45
45
|
{
|
@@ -51,7 +51,7 @@ def new_script(
|
|
51
51
|
|
52
52
|
local_signals = ",".join(list(map(to_local_signal, signals_to_subscribe_to)))
|
53
53
|
|
54
|
-
def to_subscribe_pattern(sig_name: tuple[str, str]):
|
54
|
+
def to_subscribe_pattern(sig_name: tuple[str, str]) -> str:
|
55
55
|
t = Template(
|
56
56
|
"""
|
57
57
|
if (signals["$sig_name"] ~= nil) then
|
cli/broker/signals.py
CHANGED
@@ -5,10 +5,10 @@ import numbers
|
|
5
5
|
import os
|
6
6
|
import signal as os_signal
|
7
7
|
from pathlib import Path
|
8
|
-
from typing import List, TypedDict
|
8
|
+
from typing import Any, Dict, Iterable, List, TypedDict
|
9
9
|
|
10
10
|
import grpc
|
11
|
-
import plotext as plt
|
11
|
+
import plotext as plt # type: ignore
|
12
12
|
import typer
|
13
13
|
from rich import print as rich_rprint
|
14
14
|
|
@@ -16,7 +16,7 @@ from cli.errors import ErrorPrinter
|
|
16
16
|
|
17
17
|
from .lib.broker import Broker, SubscribableSignal
|
18
18
|
|
19
|
-
app = typer.Typer(help=help)
|
19
|
+
app = typer.Typer(help=help) # type: ignore
|
20
20
|
|
21
21
|
|
22
22
|
# signal_values:list = list()
|
@@ -24,17 +24,17 @@ app = typer.Typer(help=help)
|
|
24
24
|
|
25
25
|
class Signals(TypedDict):
|
26
26
|
name: str
|
27
|
-
signals: List
|
27
|
+
signals: List[Any]
|
28
28
|
|
29
29
|
|
30
|
-
signal_values = {}
|
30
|
+
signal_values: Dict[Any, Any] = {}
|
31
31
|
|
32
32
|
|
33
33
|
@app.command(help="List signals names on broker")
|
34
34
|
def signal_names(
|
35
35
|
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
36
36
|
api_key: str = typer.Option(None, help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
37
|
-
):
|
37
|
+
) -> None:
|
38
38
|
try:
|
39
39
|
broker = Broker(url, api_key)
|
40
40
|
# print("Listing available signals")
|
@@ -73,7 +73,7 @@ def subscribe( # noqa: C901
|
|
73
73
|
x_plot: bool = typer.Option(default=False, help="Experimental: Plot the signal in terminal. Note graphs are not " "aligned by time"),
|
74
74
|
x_plot_size: int = typer.Option(default=100, help="Experimental: how many points show for each plot"),
|
75
75
|
# samples: int = typer.Option(default=0, he)
|
76
|
-
):
|
76
|
+
) -> None:
|
77
77
|
"""
|
78
78
|
Subscribe to a selection of signals
|
79
79
|
|
@@ -100,10 +100,10 @@ def subscribe( # noqa: C901
|
|
100
100
|
|
101
101
|
plt.title("Signals")
|
102
102
|
|
103
|
-
def exit_on_ctrlc(sig, frame):
|
103
|
+
def exit_on_ctrlc(sig: Any, frame: Any) -> None:
|
104
104
|
os._exit(0)
|
105
105
|
|
106
|
-
def on_frame_plot(x):
|
106
|
+
def on_frame_plot(x: Iterable[Any]) -> None:
|
107
107
|
global signal_values
|
108
108
|
|
109
109
|
plt.clt() # to clear the terminal
|
@@ -144,7 +144,7 @@ def subscribe( # noqa: C901
|
|
144
144
|
plt.sleep(0.001) # to add
|
145
145
|
plt.show()
|
146
146
|
|
147
|
-
def on_frame_print(x):
|
147
|
+
def on_frame_print(x: Iterable[Any]) -> None:
|
148
148
|
rich_rprint(json.dumps(list(x)))
|
149
149
|
|
150
150
|
os_signal.signal(os_signal.SIGINT, exit_on_ctrlc)
|
@@ -181,7 +181,7 @@ def subscribe( # noqa: C901
|
|
181
181
|
def namespaces(
|
182
182
|
url: str = typer.Option(..., help="Broker URL", envvar="REMOTIVE_BROKER_URL"),
|
183
183
|
api_key: str = typer.Option(None, help="Cloud Broker API-KEY or access token", envvar="REMOTIVE_BROKER_API_KEY"),
|
184
|
-
):
|
184
|
+
) -> None:
|
185
185
|
try:
|
186
186
|
broker = Broker(url, api_key)
|
187
187
|
namespaces_json = broker.list_namespaces()
|
cli/cloud/__init__.py
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
|
cli/cloud/auth.py
CHANGED
@@ -4,29 +4,33 @@ import webbrowser
|
|
4
4
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
5
5
|
from pathlib import Path
|
6
6
|
from threading import Thread
|
7
|
+
from typing import Any
|
7
8
|
|
8
9
|
import typer
|
10
|
+
from typing_extensions import override
|
9
11
|
|
10
12
|
from cli import settings
|
11
13
|
|
12
14
|
from . import auth_tokens
|
13
|
-
from . import
|
15
|
+
from .rest_helper import RestHelper as Rest
|
14
16
|
|
15
|
-
|
17
|
+
APA = settings.CONFIG_DIR_NAME
|
16
18
|
|
17
|
-
|
19
|
+
HELP = """
|
18
20
|
Manage how you authenticate with our cloud platform
|
19
21
|
"""
|
20
22
|
|
21
|
-
|
23
|
+
httpd: HTTPServer
|
24
|
+
|
25
|
+
app = typer.Typer(help=HELP)
|
22
26
|
|
23
27
|
app.add_typer(auth_tokens.app, name="tokens", help="Manage users personal access tokens")
|
24
|
-
|
25
|
-
|
28
|
+
CONFIG_DIR_NAME = settings.CONFIG_DIR_NAME # str(Path.home()) + "/.config/.remotive/"
|
29
|
+
TOKEN_FILE_NAME = settings.TOKEN_FILE_NAME # str(Path.home()) + "/.config/.remotive/cloud.secret.token"
|
26
30
|
|
27
31
|
|
28
32
|
class S(BaseHTTPRequestHandler):
|
29
|
-
def _set_response(self):
|
33
|
+
def _set_response(self) -> None:
|
30
34
|
self.send_response(200)
|
31
35
|
# self.send_response(301)
|
32
36
|
# self.send_header('Location', 'https://cloud.remotivelabs.com')
|
@@ -34,10 +38,13 @@ class S(BaseHTTPRequestHandler):
|
|
34
38
|
self.send_header("Content-type", "text/html")
|
35
39
|
self.end_headers()
|
36
40
|
|
37
|
-
def log_message(self, format, *args):
|
41
|
+
def log_message(self, format: Any, *args: Any) -> None: # pylint: disable=W0622
|
38
42
|
return
|
39
43
|
|
40
|
-
|
44
|
+
# Please do not change this into lowercase!
|
45
|
+
@override
|
46
|
+
# type: ignore
|
47
|
+
def do_GET(self): # pylint: disable=invalid-name,
|
41
48
|
self._set_response()
|
42
49
|
self.wfile.write("Successfully setup CLI, return to your terminal to continue".encode("utf-8"))
|
43
50
|
path = self.path
|
@@ -47,15 +54,15 @@ class S(BaseHTTPRequestHandler):
|
|
47
54
|
killerthread = Thread(target=httpd.shutdown)
|
48
55
|
killerthread.start()
|
49
56
|
|
50
|
-
if not os.path.exists(
|
51
|
-
os.makedirs(
|
57
|
+
if not os.path.exists(CONFIG_DIR_NAME):
|
58
|
+
os.makedirs(CONFIG_DIR_NAME)
|
52
59
|
write_token(path[1:])
|
53
60
|
print("Successfully logged on, you are ready to go with cli")
|
54
61
|
|
55
62
|
|
56
|
-
def start_local_webserver(server_class=HTTPServer, handler_class=S, port=0):
|
63
|
+
def start_local_webserver(server_class: type = HTTPServer, handler_class: type = S, port: int = 0) -> None:
|
57
64
|
server_address = ("", port)
|
58
|
-
global httpd
|
65
|
+
global httpd # pylint: disable=W0603
|
59
66
|
httpd = server_class(server_address, handler_class)
|
60
67
|
|
61
68
|
|
@@ -65,7 +72,7 @@ def start_local_webserver(server_class=HTTPServer, handler_class=S, port=0):
|
|
65
72
|
|
66
73
|
|
67
74
|
@app.command(name="login")
|
68
|
-
def login():
|
75
|
+
def login() -> None:
|
69
76
|
"""
|
70
77
|
Login to the cli using browser
|
71
78
|
|
@@ -73,20 +80,21 @@ def login():
|
|
73
80
|
be the same as activating a personal access key or service-account access key.
|
74
81
|
"""
|
75
82
|
start_local_webserver()
|
76
|
-
webbrowser.open(f"{
|
83
|
+
webbrowser.open(f"{Rest.get_base_url()}/login?redirectUrl=http://localhost:{httpd.server_address[1]}", new=1, autoraise=True)
|
84
|
+
|
77
85
|
httpd.serve_forever()
|
78
86
|
|
79
87
|
|
80
88
|
@app.command()
|
81
|
-
def whoami():
|
89
|
+
def whoami() -> None:
|
82
90
|
"""
|
83
91
|
Validates authentication and fetches your user information
|
84
92
|
"""
|
85
|
-
|
93
|
+
Rest.handle_get("/api/whoami")
|
86
94
|
|
87
95
|
|
88
96
|
@app.command()
|
89
|
-
def print_access_token():
|
97
|
+
def print_access_token() -> None:
|
90
98
|
"""
|
91
99
|
Print current active access token
|
92
100
|
"""
|
@@ -94,36 +102,33 @@ def print_access_token():
|
|
94
102
|
|
95
103
|
|
96
104
|
@app.command(help="Clear access token")
|
97
|
-
def logout():
|
98
|
-
os.remove(settings.
|
105
|
+
def logout() -> None:
|
106
|
+
os.remove(settings.TOKEN_FILE_NAME)
|
99
107
|
print("Access token removed")
|
100
108
|
|
101
109
|
|
102
|
-
def read_token():
|
110
|
+
def read_token() -> str:
|
103
111
|
# f = open(token_file_name, "r")
|
104
112
|
# token = f.read()
|
105
113
|
# f.close()
|
106
114
|
return settings.read_token()
|
107
115
|
|
108
116
|
|
109
|
-
def read_file_with_path(file):
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
return token
|
117
|
+
def read_file_with_path(file: str) -> str:
|
118
|
+
with open(file, "r", encoding="utf8") as f:
|
119
|
+
token = f.read()
|
120
|
+
return token
|
114
121
|
|
115
122
|
|
116
|
-
def read_file(file):
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
return token
|
123
|
+
def read_file(file: str) -> str:
|
124
|
+
with open(str(Path.home()) + f"/.config/.remotive/{file}", "r", encoding="utf8") as f:
|
125
|
+
token = f.read()
|
126
|
+
return token
|
121
127
|
|
122
128
|
|
123
|
-
def write_token(token):
|
124
|
-
|
125
|
-
|
126
|
-
f.close()
|
129
|
+
def write_token(token: str) -> None:
|
130
|
+
with open(TOKEN_FILE_NAME, "w", encoding="utf8") as f:
|
131
|
+
f.write(token)
|
127
132
|
|
128
133
|
|
129
134
|
# Key stuff
|
cli/cloud/auth_tokens.py
CHANGED
@@ -5,18 +5,21 @@ from pathlib import Path
|
|
5
5
|
|
6
6
|
import typer
|
7
7
|
|
8
|
-
from . import
|
8
|
+
from .rest_helper import RestHelper as Rest
|
9
9
|
|
10
10
|
app = typer.Typer()
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
TOKEN_FILE_NAME = str(Path.home()) + "/.config/.remotive/cloud.secret.token"
|
13
|
+
CONFIG_DIR_NAME = str(Path.home()) + "/.config/.remotive/"
|
14
14
|
|
15
15
|
|
16
16
|
@app.command(name="create", help="Create and download a new personal access token")
|
17
|
-
def get_personal_access_token(activate: bool = typer.Option(False, help="Activate the token for use after download")):
|
18
|
-
|
19
|
-
response =
|
17
|
+
def get_personal_access_token(activate: bool = typer.Option(False, help="Activate the token for use after download")) -> None: # pylint: disable=W0621
|
18
|
+
Rest.ensure_auth_token()
|
19
|
+
response = Rest.handle_post(url="/api/me/keys", return_response=True)
|
20
|
+
|
21
|
+
if response is None:
|
22
|
+
return
|
20
23
|
|
21
24
|
if response.status_code == 200:
|
22
25
|
name = response.json()["name"]
|
@@ -34,19 +37,19 @@ def get_personal_access_token(activate: bool = typer.Option(False, help="Activat
|
|
34
37
|
|
35
38
|
|
36
39
|
@app.command(name="list", help="List personal access tokens")
|
37
|
-
def list_personal_access_tokens():
|
38
|
-
|
39
|
-
|
40
|
+
def list_personal_access_tokens() -> None:
|
41
|
+
Rest.ensure_auth_token()
|
42
|
+
Rest.handle_get("/api/me/keys")
|
40
43
|
|
41
44
|
|
42
45
|
@app.command(name="revoke", help="Revoke the specified access token")
|
43
|
-
def revoke(name: str = typer.Option(..., help="Name of the access token to revoke")):
|
44
|
-
|
45
|
-
|
46
|
+
def revoke(name: str = typer.Option(..., help="Name of the access token to revoke")) -> None:
|
47
|
+
Rest.ensure_auth_token()
|
48
|
+
Rest.handle_delete(f"/api/me/keys/{name}")
|
46
49
|
|
47
50
|
|
48
51
|
@app.command()
|
49
|
-
def describe(file: str = typer.Option(..., help="File name")):
|
52
|
+
def describe(file: str = typer.Option(..., help="File name")) -> None:
|
50
53
|
"""
|
51
54
|
Show contents of specified access token file
|
52
55
|
"""
|
@@ -54,7 +57,7 @@ def describe(file: str = typer.Option(..., help="File name")):
|
|
54
57
|
|
55
58
|
|
56
59
|
@app.command()
|
57
|
-
def activate(file: str = typer.Argument(..., help="File name")):
|
60
|
+
def activate(file: str = typer.Argument(..., help="File name")) -> None:
|
58
61
|
"""
|
59
62
|
Activate a access token file to be used for authentication.
|
60
63
|
|
@@ -66,7 +69,7 @@ def activate(file: str = typer.Argument(..., help="File name")):
|
|
66
69
|
do_activate(file)
|
67
70
|
|
68
71
|
|
69
|
-
def do_activate(file: str):
|
72
|
+
def do_activate(file: str) -> None:
|
70
73
|
# Best effort to read file
|
71
74
|
if os.path.exists(file):
|
72
75
|
token_file = json.loads(read_file_with_path(file))
|
@@ -79,38 +82,38 @@ def do_activate(file: str):
|
|
79
82
|
|
80
83
|
|
81
84
|
@app.command(name="list-files")
|
82
|
-
def list_files():
|
85
|
+
def list_files() -> None:
|
83
86
|
"""
|
84
87
|
List personal access token files in remotivelabs config directory
|
85
88
|
"""
|
86
|
-
personal_files = filter(lambda f: f.startswith("personal"), os.listdir(
|
89
|
+
personal_files = filter(lambda f: f.startswith("personal"), os.listdir(CONFIG_DIR_NAME))
|
87
90
|
for file in personal_files:
|
88
91
|
print(file)
|
89
92
|
|
90
93
|
|
91
|
-
def read_file(file):
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
def read_file(file: str) -> str:
|
95
|
+
with open(str(Path.home()) + f"/.config/.remotive/{file}", "r", encoding="utf8") as f:
|
96
|
+
token = f.read()
|
97
|
+
f.close()
|
98
|
+
return token
|
96
99
|
|
97
100
|
|
98
|
-
def read_file_with_path(file):
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
101
|
+
def read_file_with_path(file: str) -> str:
|
102
|
+
with open(file, "r", encoding="utf8") as f:
|
103
|
+
token = f.read()
|
104
|
+
f.close()
|
105
|
+
return token
|
103
106
|
|
104
107
|
|
105
|
-
def write_token(token):
|
106
|
-
|
107
|
-
|
108
|
-
|
108
|
+
def write_token(token: str) -> None:
|
109
|
+
with open(TOKEN_FILE_NAME, "w", encoding="utf8") as f:
|
110
|
+
f.write(token)
|
111
|
+
f.close()
|
109
112
|
|
110
113
|
|
111
|
-
def write_personal_token(file: str, token: str):
|
114
|
+
def write_personal_token(file: str, token: str) -> str:
|
112
115
|
path = str(Path.home()) + f"/.config/.remotive/{file}"
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
116
|
+
with open(path, "w", encoding="utf8") as f:
|
117
|
+
f.write(token)
|
118
|
+
f.close()
|
119
|
+
return path
|
cli/cloud/brokers.py
CHANGED
@@ -1,49 +1,40 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import json
|
2
4
|
import os
|
3
5
|
import signal as os_signal
|
6
|
+
from typing import Any, Union
|
4
7
|
|
8
|
+
import requests
|
5
9
|
import typer
|
6
10
|
import websocket
|
7
|
-
from rich.progress import Progress, SpinnerColumn, TextColumn
|
8
11
|
|
9
|
-
from . import
|
12
|
+
from .rest_helper import RestHelper as Rest
|
10
13
|
|
11
14
|
app = typer.Typer()
|
12
15
|
|
13
16
|
|
14
17
|
@app.command("list", help="Lists brokers in project")
|
15
|
-
def list(project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")):
|
16
|
-
|
18
|
+
def list(project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")) -> None: # pylint: disable=W0622
|
19
|
+
Rest.handle_get(f"/api/project/{project}/brokers")
|
17
20
|
|
18
21
|
|
19
22
|
@app.command("describe", help="Shows details about a specific broker")
|
20
|
-
def describe(name: str, project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")):
|
21
|
-
|
23
|
+
def describe(name: str, project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")) -> None:
|
24
|
+
Rest.handle_get(f"/api/project/{project}/brokers/{name}")
|
22
25
|
|
23
26
|
|
24
27
|
@app.command("delete", help="Stops and deletes a broker from project")
|
25
|
-
def stop(name: str, project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")):
|
26
|
-
|
27
|
-
SpinnerColumn(),
|
28
|
-
TextColumn("[progress.description]{task.description}"),
|
29
|
-
transient=True,
|
30
|
-
) as progress:
|
31
|
-
progress.add_task(description=f"Deleting broker {name}...", total=None)
|
32
|
-
rest.handle_delete(f"/api/project/{project}/brokers/{name}")
|
28
|
+
def stop(name: str, project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")) -> None:
|
29
|
+
Rest.handle_delete(f"/api/project/{project}/brokers/{name}")
|
33
30
|
|
34
31
|
|
35
32
|
@app.command(help="Deletes your personal broker from project")
|
36
|
-
def delete_personal(project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")):
|
37
|
-
|
38
|
-
SpinnerColumn(),
|
39
|
-
TextColumn("[progress.description]{task.description}"),
|
40
|
-
transient=True,
|
41
|
-
) as progress:
|
42
|
-
progress.add_task(description="Deleting personal broker...", total=None)
|
43
|
-
rest.handle_delete(f"/api/project/{project}/brokers/personal")
|
33
|
+
def delete_personal(project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT")) -> None:
|
34
|
+
Rest.handle_delete(f"/api/project/{project}/brokers/personal")
|
44
35
|
|
45
36
|
|
46
|
-
def do_start(name: str, project: str, api_key: str, tag: str, return_response: bool = False):
|
37
|
+
def do_start(name: str, project: str, api_key: str, tag: str, return_response: bool = False) -> Union[requests.Response, None]:
|
47
38
|
if tag == "":
|
48
39
|
tag_to_use = None
|
49
40
|
else:
|
@@ -53,7 +44,7 @@ def do_start(name: str, project: str, api_key: str, tag: str, return_response: b
|
|
53
44
|
body = {"size": "S", "tag": tag_to_use}
|
54
45
|
else:
|
55
46
|
body = {"size": "S", "apiKey": api_key, "tag": tag_to_use}
|
56
|
-
return
|
47
|
+
return Rest.handle_post(
|
57
48
|
f"/api/project/{project}/brokers/{name}",
|
58
49
|
body=json.dumps(body),
|
59
50
|
return_response=return_response,
|
@@ -68,7 +59,7 @@ def start(
|
|
68
59
|
tag: str = typer.Option("", help="Optional specific tag/version"),
|
69
60
|
silent: bool = typer.Option(False, help="Optional specific tag/version"),
|
70
61
|
api_key: str = typer.Option("", help="Start with your own api-key"),
|
71
|
-
):
|
62
|
+
) -> None:
|
72
63
|
# with Progress(
|
73
64
|
# SpinnerColumn(),
|
74
65
|
# TextColumn("[progress.description]{task.description}"),
|
@@ -84,7 +75,7 @@ def logs(
|
|
84
75
|
tail: bool = typer.Option(False, help="Tail the broker log"),
|
85
76
|
history_minutes: str = typer.Option(10, help="History in minutes minutes to fetch"),
|
86
77
|
project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
|
87
|
-
):
|
78
|
+
) -> None:
|
88
79
|
"""
|
89
80
|
Exposes broker logs history or real-time tail of the broker.
|
90
81
|
|
@@ -92,30 +83,30 @@ def logs(
|
|
92
83
|
|
93
84
|
"""
|
94
85
|
|
95
|
-
def exit_on_ctrlc(
|
86
|
+
def exit_on_ctrlc(__sig: Any, __frame: Any) -> None:
|
96
87
|
wsapp.close()
|
97
88
|
os._exit(0)
|
98
89
|
|
99
90
|
os_signal.signal(os_signal.SIGINT, exit_on_ctrlc)
|
100
91
|
|
101
|
-
def on_message(
|
92
|
+
def on_message(__wsapp: Any, message: str) -> None:
|
102
93
|
print(message)
|
103
94
|
|
104
|
-
def on_error(wsapp, err):
|
95
|
+
def on_error(wsapp: Any, err: str) -> None: # pylint: disable=W0613
|
105
96
|
print("EXAMPLE error encountered: ", err)
|
106
97
|
|
107
|
-
|
98
|
+
Rest.ensure_auth_token()
|
108
99
|
# This will work with both http -> ws and https -> wss
|
109
|
-
ws_url =
|
100
|
+
ws_url = Rest.get_base_url().replace("http", "ws")
|
110
101
|
|
111
102
|
if tail:
|
112
103
|
q = "?tail=yes"
|
113
|
-
elif history_minutes != 10:
|
104
|
+
elif history_minutes != "10":
|
114
105
|
q = f"?history={history_minutes}"
|
115
106
|
else:
|
116
107
|
q = ""
|
117
108
|
|
118
109
|
wsapp = websocket.WebSocketApp(
|
119
|
-
f"{ws_url}/api/project/{project}/brokers/{broker_name}/logs{q}", header=
|
110
|
+
f"{ws_url}/api/project/{project}/brokers/{broker_name}/logs{q}", header=Rest.get_headers(), on_message=on_message, on_error=on_error
|
120
111
|
)
|
121
112
|
wsapp.run_forever()
|
cli/cloud/cloud_cli.py
CHANGED
@@ -2,8 +2,9 @@ import json
|
|
2
2
|
|
3
3
|
import typer
|
4
4
|
|
5
|
-
from . import
|
6
|
-
|
5
|
+
from cli.cloud.rest_helper import RestHelper
|
6
|
+
|
7
|
+
from . import auth, brokers, configs, filestorage, projects, recordings, sample_recordings, service_accounts
|
7
8
|
|
8
9
|
app = typer.Typer()
|
9
10
|
|
@@ -11,14 +12,16 @@ app = typer.Typer()
|
|
11
12
|
@app.command(help="List licenses for an organisation")
|
12
13
|
def licenses(
|
13
14
|
organisation: str = typer.Option(..., help="Organisation ID", envvar="REMOTIVE_CLOUD_ORGANISATION"),
|
14
|
-
|
15
|
-
):
|
16
|
-
|
15
|
+
filter_option: str = typer.Option("all", help="all, valid, expired"),
|
16
|
+
) -> None:
|
17
|
+
RestHelper.handle_get(f"/api/bu/{organisation}/licenses", {"filter": filter_option})
|
17
18
|
|
18
19
|
|
19
20
|
@app.command(help="List your available organisations")
|
20
|
-
def organisations():
|
21
|
-
r =
|
21
|
+
def organisations() -> None:
|
22
|
+
r = RestHelper.handle_get("/api/home", return_response=True)
|
23
|
+
if r is None:
|
24
|
+
return
|
22
25
|
if r.status_code == 200:
|
23
26
|
j = list(map(lambda x: x["billableUnitUser"]["billableUnit"]["uid"], r.json()))
|
24
27
|
print(json.dumps(j))
|
@@ -32,6 +35,7 @@ app.add_typer(auth.app, name="auth")
|
|
32
35
|
app.add_typer(brokers.app, name="brokers", help="Manage cloud broker lifecycle")
|
33
36
|
app.add_typer(recordings.app, name="recordings", help="Manage recordings")
|
34
37
|
app.add_typer(configs.app, name="signal-databases", help="Manage signal databases")
|
38
|
+
app.add_typer(filestorage.app, name="storage")
|
35
39
|
app.add_typer(service_accounts.app, name="service-accounts", help="Manage project service account keys")
|
36
40
|
app.add_typer(sample_recordings.app, name="samples", help="Manage sample recordings")
|
37
41
|
|