vantage6 5.0.0a0__py3-none-any.whl → 5.0.0a7__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 vantage6 might be problematic. Click here for more details.
- tests_cli/test_node_cli.py +33 -5
- tests_cli/test_server_cli.py +1 -1
- tests_cli/test_wizard.py +5 -5
- vantage6/cli/__build__ +1 -1
- vantage6/cli/__init__.py +1 -1
- vantage6/cli/algorithm/create.py +26 -8
- vantage6/cli/algorithm/update.py +5 -1
- vantage6/cli/algostore/attach.py +24 -7
- vantage6/cli/algostore/new.py +9 -3
- vantage6/cli/cli.py +2 -0
- vantage6/cli/common/start.py +1 -1
- vantage6/cli/common/utils.py +27 -4
- vantage6/cli/configuration_wizard.py +63 -51
- vantage6/cli/context/node.py +18 -1
- vantage6/cli/dev/create.py +3 -2
- vantage6/cli/dev/start.py +2 -2
- vantage6/cli/node/attach.py +7 -3
- vantage6/cli/node/clean.py +6 -2
- vantage6/cli/node/common/__init__.py +26 -4
- vantage6/cli/node/create_private_key.py +10 -2
- vantage6/cli/node/new.py +7 -3
- vantage6/cli/node/restart.py +128 -0
- vantage6/cli/node/set_api_key.py +7 -3
- vantage6/cli/node/start.py +12 -4
- vantage6/cli/node/stop.py +7 -3
- vantage6/cli/node/version.py +7 -3
- vantage6/cli/server/attach.py +7 -3
- vantage6/cli/server/new.py +7 -3
- vantage6/cli/server/start.py +1 -1
- vantage6/cli/server/stop.py +7 -3
- vantage6/cli/template/node_config.j2 +3 -1
- vantage6/cli/test/feature_tester.py +10 -3
- vantage6/cli/utils.py +5 -1
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a7.dist-info}/METADATA +5 -5
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a7.dist-info}/RECORD +38 -38
- vantage6/cli/dev/data/olympic_athletes_2016.csv +0 -2425
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a7.dist-info}/WHEEL +0 -0
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a7.dist-info}/entry_points.txt +0 -0
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a7.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import questionary as q
|
|
2
|
-
|
|
3
1
|
from pathlib import Path
|
|
4
2
|
|
|
3
|
+
import questionary as q
|
|
4
|
+
|
|
5
5
|
from vantage6.common import generate_apikey
|
|
6
6
|
from vantage6.common.globals import (
|
|
7
7
|
DATABASE_TYPES,
|
|
@@ -36,7 +36,7 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
36
36
|
dict
|
|
37
37
|
Dictionary with the new node configuration
|
|
38
38
|
"""
|
|
39
|
-
config = q.
|
|
39
|
+
config = q.unsafe_prompt(
|
|
40
40
|
[
|
|
41
41
|
{"type": "text", "name": "api_key", "message": "Enter given api-key:"},
|
|
42
42
|
{
|
|
@@ -57,7 +57,7 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
57
57
|
else str(Ports.DEV_SERVER.value)
|
|
58
58
|
)
|
|
59
59
|
|
|
60
|
-
config = config | q.
|
|
60
|
+
config = config | q.unsafe_prompt(
|
|
61
61
|
[
|
|
62
62
|
{
|
|
63
63
|
"type": "text",
|
|
@@ -81,8 +81,8 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
81
81
|
)
|
|
82
82
|
|
|
83
83
|
config["databases"] = list()
|
|
84
|
-
while q.confirm("Do you want to add a database?").
|
|
85
|
-
db_label = q.
|
|
84
|
+
while q.confirm("Do you want to add a database?").unsafe_ask():
|
|
85
|
+
db_label = q.unsafe_prompt(
|
|
86
86
|
[
|
|
87
87
|
{
|
|
88
88
|
"type": "text",
|
|
@@ -92,10 +92,10 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
92
92
|
}
|
|
93
93
|
]
|
|
94
94
|
)
|
|
95
|
-
db_path = q.
|
|
95
|
+
db_path = q.unsafe_prompt(
|
|
96
96
|
[{"type": "text", "name": "uri", "message": "Database URI:"}]
|
|
97
97
|
)
|
|
98
|
-
db_type = q.select("Database type:", choices=DATABASE_TYPES).
|
|
98
|
+
db_type = q.select("Database type:", choices=DATABASE_TYPES).unsafe_ask()
|
|
99
99
|
|
|
100
100
|
config["databases"].append(
|
|
101
101
|
{"label": db_label.get("label"), "uri": db_path.get("uri"), "type": db_type}
|
|
@@ -103,18 +103,18 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
103
103
|
|
|
104
104
|
is_add_vpn = q.confirm(
|
|
105
105
|
"Do you want to connect to a VPN server?", default=False
|
|
106
|
-
).
|
|
106
|
+
).unsafe_ask()
|
|
107
107
|
if is_add_vpn:
|
|
108
108
|
config["vpn_subnet"] = q.text(
|
|
109
109
|
message="Subnet of the VPN server you want to connect to:",
|
|
110
110
|
default="10.76.0.0/16",
|
|
111
|
-
).
|
|
111
|
+
).unsafe_ask()
|
|
112
112
|
|
|
113
113
|
is_policies = q.confirm(
|
|
114
114
|
"Do you want to limit the algorithms allowed to run on your node? This "
|
|
115
115
|
"should always be done for production scenarios.",
|
|
116
116
|
default=True,
|
|
117
|
-
).
|
|
117
|
+
).unsafe_ask()
|
|
118
118
|
policies = {}
|
|
119
119
|
if is_policies:
|
|
120
120
|
info(
|
|
@@ -124,12 +124,12 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
124
124
|
)
|
|
125
125
|
ask_single_algorithms = q.confirm(
|
|
126
126
|
"Do you want to enter a list of allowed algorithms?"
|
|
127
|
-
).
|
|
127
|
+
).unsafe_ask()
|
|
128
128
|
if ask_single_algorithms:
|
|
129
129
|
policies[NodePolicy.ALLOWED_ALGORITHMS.value] = _get_allowed_algorithms()
|
|
130
130
|
ask_algorithm_stores = q.confirm(
|
|
131
131
|
"Do you want to allow algorithms from specific algorithm stores?"
|
|
132
|
-
).
|
|
132
|
+
).unsafe_ask()
|
|
133
133
|
if ask_algorithm_stores:
|
|
134
134
|
policies[NodePolicy.ALLOWED_ALGORITHM_STORES.value] = (
|
|
135
135
|
_get_allowed_algorithm_stores()
|
|
@@ -141,7 +141,7 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
141
141
|
"stores? If not, algorithms will be allowed if they are in either the "
|
|
142
142
|
"list of allowed algorithms or one of the allowed algorithm stores.",
|
|
143
143
|
default=True,
|
|
144
|
-
).
|
|
144
|
+
).unsafe_ask()
|
|
145
145
|
policies["allow_either_whitelist_or_store"] = not require_both_whitelists
|
|
146
146
|
if policies:
|
|
147
147
|
config["policies"] = policies
|
|
@@ -149,7 +149,7 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
149
149
|
res = q.select(
|
|
150
150
|
"Which level of logging would you like?",
|
|
151
151
|
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NOTSET"],
|
|
152
|
-
).
|
|
152
|
+
).unsafe_ask()
|
|
153
153
|
|
|
154
154
|
config["logging"] = {
|
|
155
155
|
"level": res,
|
|
@@ -178,7 +178,7 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
178
178
|
"If you continue, you should provide your collaboration "
|
|
179
179
|
"settings manually."
|
|
180
180
|
)
|
|
181
|
-
if q.confirm("Do you want to abort?", default=True).
|
|
181
|
+
if q.confirm("Do you want to abort?", default=True).unsafe_ask():
|
|
182
182
|
exit(0)
|
|
183
183
|
|
|
184
184
|
if client.whoami is not None:
|
|
@@ -190,11 +190,13 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
190
190
|
f"Encryption is {'enabled' if encryption else 'disabled'}"
|
|
191
191
|
f" for this collaboration. Accept?",
|
|
192
192
|
default=True,
|
|
193
|
-
).
|
|
193
|
+
).unsafe_ask()
|
|
194
194
|
else:
|
|
195
|
-
encryption = q.confirm("Enable encryption?", default=True).
|
|
195
|
+
encryption = q.confirm("Enable encryption?", default=True).unsafe_ask()
|
|
196
196
|
|
|
197
|
-
private_key =
|
|
197
|
+
private_key = (
|
|
198
|
+
"" if not encryption else q.text("Path to private key file:").unsafe_ask()
|
|
199
|
+
)
|
|
198
200
|
|
|
199
201
|
config["encryption"] = {
|
|
200
202
|
"enabled": encryption is True or encryption == "true",
|
|
@@ -219,24 +221,22 @@ def _get_allowed_algorithms() -> list[str]:
|
|
|
219
221
|
"use strings to provide one algorithm at a time."
|
|
220
222
|
)
|
|
221
223
|
info("Examples:")
|
|
222
|
-
|
|
223
|
-
# flake8: noqa: W605
|
|
224
|
-
info("^harbor2\.vantage6\.ai/demo/average$ Allow the demo average algorithm")
|
|
224
|
+
info(r"^harbor2\.vantage6\.ai/demo/average$ Allow the demo average algorithm")
|
|
225
225
|
info(
|
|
226
|
-
"^harbor2\.vantage6\.ai/algorithms/.* Allow all algorithms from "
|
|
226
|
+
r"^harbor2\.vantage6\.ai/algorithms/.* Allow all algorithms from "
|
|
227
227
|
"harbor2.vantage6.ai/algorithms"
|
|
228
228
|
)
|
|
229
229
|
info(
|
|
230
|
-
"^harbor2\.vantage6\.ai/demo/average@sha256:82becede...$ Allow a "
|
|
230
|
+
r"^harbor2\.vantage6\.ai/demo/average@sha256:82becede...$ Allow a "
|
|
231
231
|
"specific hash of average algorithm"
|
|
232
232
|
)
|
|
233
233
|
allowed_algorithms = []
|
|
234
234
|
while True:
|
|
235
|
-
algo = q.text(message="Enter your algorithm expression:").
|
|
235
|
+
algo = q.text(message="Enter your algorithm expression:").unsafe_ask()
|
|
236
236
|
allowed_algorithms.append(algo)
|
|
237
237
|
if not q.confirm(
|
|
238
238
|
"Do you want to add another algorithm expression?", default=True
|
|
239
|
-
).
|
|
239
|
+
).unsafe_ask():
|
|
240
240
|
break
|
|
241
241
|
return allowed_algorithms
|
|
242
242
|
|
|
@@ -261,16 +261,16 @@ def _get_allowed_algorithm_stores() -> list[str]:
|
|
|
261
261
|
"community store"
|
|
262
262
|
)
|
|
263
263
|
info(
|
|
264
|
-
"^https://*\.vantage6\.ai$ Allow all algorithms from any "
|
|
264
|
+
r"^https://*\.vantage6\.ai$ Allow all algorithms from any "
|
|
265
265
|
"store hosted on vantage6.ai"
|
|
266
266
|
)
|
|
267
267
|
allowed_algorithm_stores = []
|
|
268
268
|
while True:
|
|
269
|
-
store = q.text(message="Enter the URL of the algorithm store:").
|
|
269
|
+
store = q.text(message="Enter the URL of the algorithm store:").unsafe_ask()
|
|
270
270
|
allowed_algorithm_stores.append(store)
|
|
271
271
|
if not q.confirm(
|
|
272
272
|
"Do you want to add another algorithm store?", default=True
|
|
273
|
-
).
|
|
273
|
+
).unsafe_ask():
|
|
274
274
|
break
|
|
275
275
|
return allowed_algorithm_stores
|
|
276
276
|
|
|
@@ -292,7 +292,7 @@ def _get_common_server_config(instance_type: InstanceType, instance_name: str) -
|
|
|
292
292
|
dict
|
|
293
293
|
Dictionary with new (partial) server configuration
|
|
294
294
|
"""
|
|
295
|
-
config = q.
|
|
295
|
+
config = q.unsafe_prompt(
|
|
296
296
|
[
|
|
297
297
|
{
|
|
298
298
|
"type": "text",
|
|
@@ -315,7 +315,7 @@ def _get_common_server_config(instance_type: InstanceType, instance_name: str) -
|
|
|
315
315
|
)
|
|
316
316
|
|
|
317
317
|
config.update(
|
|
318
|
-
q.
|
|
318
|
+
q.unsafe_prompt(
|
|
319
319
|
[
|
|
320
320
|
{
|
|
321
321
|
"type": "text",
|
|
@@ -336,7 +336,7 @@ def _get_common_server_config(instance_type: InstanceType, instance_name: str) -
|
|
|
336
336
|
res = q.select(
|
|
337
337
|
"Which level of logging would you like?",
|
|
338
338
|
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NOTSET"],
|
|
339
|
-
).
|
|
339
|
+
).unsafe_ask()
|
|
340
340
|
|
|
341
341
|
config["logging"] = {
|
|
342
342
|
"level": res,
|
|
@@ -378,11 +378,11 @@ def server_configuration_questionaire(instance_name: str) -> dict:
|
|
|
378
378
|
|
|
379
379
|
config = _get_common_server_config(InstanceType.SERVER, instance_name)
|
|
380
380
|
|
|
381
|
-
constant_jwt_secret = q.confirm("Do you want a constant JWT secret?").
|
|
381
|
+
constant_jwt_secret = q.confirm("Do you want a constant JWT secret?").unsafe_ask()
|
|
382
382
|
if constant_jwt_secret:
|
|
383
383
|
config["jwt_secret_key"] = generate_apikey()
|
|
384
384
|
|
|
385
|
-
is_mfa = q.confirm("Do you want to enforce two-factor authentication?").
|
|
385
|
+
is_mfa = q.confirm("Do you want to enforce two-factor authentication?").unsafe_ask()
|
|
386
386
|
if is_mfa:
|
|
387
387
|
config["two_factor_auth"] = is_mfa
|
|
388
388
|
|
|
@@ -393,11 +393,13 @@ def server_configuration_questionaire(instance_name: str) -> dict:
|
|
|
393
393
|
"server url. If you are running a production server, this is the "
|
|
394
394
|
"url that users will connect to.",
|
|
395
395
|
default=current_server_url,
|
|
396
|
-
).
|
|
396
|
+
).unsafe_ask()
|
|
397
397
|
|
|
398
|
-
is_add_vpn = q.confirm(
|
|
398
|
+
is_add_vpn = q.confirm(
|
|
399
|
+
"Do you want to add a VPN server?", default=False
|
|
400
|
+
).unsafe_ask()
|
|
399
401
|
if is_add_vpn:
|
|
400
|
-
vpn_config = q.
|
|
402
|
+
vpn_config = q.unsafe_prompt(
|
|
401
403
|
[
|
|
402
404
|
{
|
|
403
405
|
"type": "text",
|
|
@@ -434,12 +436,14 @@ def server_configuration_questionaire(instance_name: str) -> dict:
|
|
|
434
436
|
)
|
|
435
437
|
config["vpn_server"] = vpn_config
|
|
436
438
|
|
|
437
|
-
is_add_rabbitmq = q.confirm(
|
|
439
|
+
is_add_rabbitmq = q.confirm(
|
|
440
|
+
"Do you want to add a RabbitMQ message queue?"
|
|
441
|
+
).unsafe_ask()
|
|
438
442
|
if is_add_rabbitmq:
|
|
439
|
-
rabbit_uri = q.text(message="Enter the URI for your RabbitMQ:").
|
|
443
|
+
rabbit_uri = q.text(message="Enter the URI for your RabbitMQ:").unsafe_ask()
|
|
440
444
|
run_rabbit_locally = q.confirm(
|
|
441
445
|
"Do you want to run RabbitMQ locally? (Use only for testing)"
|
|
442
|
-
).
|
|
446
|
+
).unsafe_ask()
|
|
443
447
|
config["rabbitmq"] = {
|
|
444
448
|
"uri": rabbit_uri,
|
|
445
449
|
"start_with_server": run_rabbit_locally,
|
|
@@ -449,7 +453,7 @@ def server_configuration_questionaire(instance_name: str) -> dict:
|
|
|
449
453
|
is_add_community_store = q.confirm(
|
|
450
454
|
"Do you want to make the algorithms from the community algorithm store "
|
|
451
455
|
"available to your users?"
|
|
452
|
-
).
|
|
456
|
+
).unsafe_ask()
|
|
453
457
|
algorithm_stores = []
|
|
454
458
|
if is_add_community_store:
|
|
455
459
|
algorithm_stores.append(
|
|
@@ -457,14 +461,14 @@ def server_configuration_questionaire(instance_name: str) -> dict:
|
|
|
457
461
|
)
|
|
458
462
|
add_more_stores = q.confirm(
|
|
459
463
|
"Do you want to add more algorithm stores?", default=False
|
|
460
|
-
).
|
|
464
|
+
).unsafe_ask()
|
|
461
465
|
while add_more_stores:
|
|
462
|
-
store_name = q.text(message="Enter the name of the store:").
|
|
463
|
-
store_url = q.text(message="Enter the URL of the store:").
|
|
466
|
+
store_name = q.text(message="Enter the name of the store:").unsafe_ask()
|
|
467
|
+
store_url = q.text(message="Enter the URL of the store:").unsafe_ask()
|
|
464
468
|
algorithm_stores.append({"name": store_name, "url": store_url})
|
|
465
469
|
add_more_stores = q.confirm(
|
|
466
470
|
"Do you want to add more algorithm stores?", default=False
|
|
467
|
-
).
|
|
471
|
+
).unsafe_ask()
|
|
468
472
|
config["algorithm_stores"] = algorithm_stores
|
|
469
473
|
|
|
470
474
|
return config
|
|
@@ -487,19 +491,21 @@ def algo_store_configuration_questionaire(instance_name: str) -> dict:
|
|
|
487
491
|
"""
|
|
488
492
|
config = _get_common_server_config(InstanceType.ALGORITHM_STORE, instance_name)
|
|
489
493
|
|
|
490
|
-
default_v6_server_uri =
|
|
494
|
+
default_v6_server_uri = (
|
|
495
|
+
f"http://localhost:{Ports.DEV_SERVER.value}{DEFAULT_API_PATH}"
|
|
496
|
+
)
|
|
491
497
|
default_root_username = "root"
|
|
492
498
|
|
|
493
499
|
v6_server_uri = q.text(
|
|
494
500
|
"What is the Vantage6 server linked to the algorithm store? "
|
|
495
501
|
"Provide the link to the server endpoint.",
|
|
496
502
|
default=default_v6_server_uri,
|
|
497
|
-
).
|
|
503
|
+
).unsafe_ask()
|
|
498
504
|
|
|
499
505
|
root_username = q.text(
|
|
500
506
|
"What is the username of the root user?",
|
|
501
507
|
default=default_root_username,
|
|
502
|
-
).
|
|
508
|
+
).unsafe_ask()
|
|
503
509
|
|
|
504
510
|
config["root_user"] = {
|
|
505
511
|
"v6_server_uri": v6_server_uri,
|
|
@@ -512,7 +518,7 @@ def algo_store_configuration_questionaire(instance_name: str) -> dict:
|
|
|
512
518
|
"Do you want to open the algorithm store to the public? This will allow anyone "
|
|
513
519
|
"to view the algorithms, but they cannot modify them.",
|
|
514
520
|
default=False,
|
|
515
|
-
).
|
|
521
|
+
).unsafe_ask()
|
|
516
522
|
if is_open:
|
|
517
523
|
open_algos_policy = "public"
|
|
518
524
|
else:
|
|
@@ -521,7 +527,7 @@ def algo_store_configuration_questionaire(instance_name: str) -> dict:
|
|
|
521
527
|
"the algorithms in the store? If not allowing this, you will have to assign"
|
|
522
528
|
" the appropriate permissions to each user individually.",
|
|
523
529
|
default=True,
|
|
524
|
-
).
|
|
530
|
+
).unsafe_ask()
|
|
525
531
|
open_algos_policy = "whitelisted" if is_open_to_whitelist else "private"
|
|
526
532
|
config["policies"]["algorithm_view"] = open_algos_policy
|
|
527
533
|
|
|
@@ -610,4 +616,10 @@ def select_configuration_questionaire(type_: InstanceType, system_folders: bool)
|
|
|
610
616
|
raise Exception("No configurations could be found!")
|
|
611
617
|
|
|
612
618
|
# pop the question
|
|
613
|
-
|
|
619
|
+
try:
|
|
620
|
+
return q.select(
|
|
621
|
+
"Select the configuration you want to use:", choices=choices
|
|
622
|
+
).unsafe_ask()
|
|
623
|
+
except KeyboardInterrupt:
|
|
624
|
+
error("Aborted by user!")
|
|
625
|
+
exit(1)
|
vantage6/cli/context/node.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import hashlib
|
|
3
4
|
import os.path
|
|
4
5
|
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
from vantage6.common.context import AppContext
|
|
8
|
-
from vantage6.common.globals import APPNAME, InstanceType
|
|
9
|
+
from vantage6.common.globals import APPNAME, STRING_ENCODING, InstanceType
|
|
9
10
|
from vantage6.cli.configuration_manager import NodeConfigurationManager
|
|
10
11
|
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
11
12
|
from vantage6.cli._version import __version__
|
|
@@ -39,6 +40,7 @@ class NodeContext(AppContext):
|
|
|
39
40
|
system_folders: bool = N_FOL,
|
|
40
41
|
config_file: str = None,
|
|
41
42
|
print_log_header: bool = True,
|
|
43
|
+
logger_prefix: str = "",
|
|
42
44
|
):
|
|
43
45
|
super().__init__(
|
|
44
46
|
InstanceType.NODE,
|
|
@@ -46,9 +48,11 @@ class NodeContext(AppContext):
|
|
|
46
48
|
system_folders,
|
|
47
49
|
config_file,
|
|
48
50
|
print_log_header,
|
|
51
|
+
logger_prefix,
|
|
49
52
|
)
|
|
50
53
|
if print_log_header:
|
|
51
54
|
self.log.info("vantage6 version '%s'", __version__)
|
|
55
|
+
self.identifier = self.__create_node_identifier()
|
|
52
56
|
|
|
53
57
|
@classmethod
|
|
54
58
|
def from_external_config_file(
|
|
@@ -245,3 +249,16 @@ class NodeContext(AppContext):
|
|
|
245
249
|
URI to the database
|
|
246
250
|
"""
|
|
247
251
|
return self.config["databases"][label]
|
|
252
|
+
|
|
253
|
+
def __create_node_identifier(self) -> str:
|
|
254
|
+
"""
|
|
255
|
+
Create a unique identifier for the node.
|
|
256
|
+
|
|
257
|
+
Returns
|
|
258
|
+
-------
|
|
259
|
+
str
|
|
260
|
+
Unique identifier for the node
|
|
261
|
+
"""
|
|
262
|
+
return hashlib.sha256(
|
|
263
|
+
self.config.get("api_key").encode(STRING_ENCODING)
|
|
264
|
+
).hexdigest()[:16]
|
vantage6/cli/dev/create.py
CHANGED
|
@@ -485,8 +485,9 @@ def demo_network(
|
|
|
485
485
|
"--server-url",
|
|
486
486
|
type=str,
|
|
487
487
|
default="http://host.docker.internal",
|
|
488
|
-
help="Server URL to point to. If you are using Docker Desktop, "
|
|
489
|
-
"
|
|
488
|
+
help="Server URL to point to. If you are using Docker Desktop, the default "
|
|
489
|
+
"http://host.docker.internal should not be changed. If you are using Linux without"
|
|
490
|
+
" Docker Desktop, you should set this to http://172.17.0.1",
|
|
490
491
|
)
|
|
491
492
|
@click.option(
|
|
492
493
|
"-p",
|
vantage6/cli/dev/start.py
CHANGED
|
@@ -67,7 +67,7 @@ def start_demo_network(
|
|
|
67
67
|
cmd = ["v6", "algorithm-store", "start", "--name", f"{ctx.name}_store", "--user"]
|
|
68
68
|
if store_image:
|
|
69
69
|
cmd.extend(["--image", store_image])
|
|
70
|
-
subprocess.run(cmd)
|
|
70
|
+
subprocess.run(cmd, check=True)
|
|
71
71
|
|
|
72
72
|
# run all nodes that belong to this server
|
|
73
73
|
configs, _ = NodeContext.available_configurations(system_folders=False)
|
|
@@ -78,7 +78,7 @@ def start_demo_network(
|
|
|
78
78
|
cmd = ["v6", "node", "start", "--name", name]
|
|
79
79
|
if node_image:
|
|
80
80
|
cmd.extend(["--image", node_image])
|
|
81
|
-
subprocess.run(cmd)
|
|
81
|
+
subprocess.run(cmd, check=True)
|
|
82
82
|
|
|
83
83
|
# now that both server and store have been started, couple them
|
|
84
84
|
info("Linking local algorithm store to server...")
|
vantage6/cli/node/attach.py
CHANGED
|
@@ -45,9 +45,13 @@ def cli_node_attach(name: str, system_folders: bool) -> None:
|
|
|
45
45
|
return
|
|
46
46
|
|
|
47
47
|
if not name:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
try:
|
|
49
|
+
name = q.select(
|
|
50
|
+
"Select the node you wish to attach:", choices=running_node_names
|
|
51
|
+
).unsafe_ask()
|
|
52
|
+
except KeyboardInterrupt:
|
|
53
|
+
error("Aborted by user!")
|
|
54
|
+
return
|
|
51
55
|
else:
|
|
52
56
|
post_fix = "system" if system_folders else "user"
|
|
53
57
|
name = f"{APPNAME}-{name}-{post_fix}"
|
vantage6/cli/node/clean.py
CHANGED
|
@@ -26,8 +26,12 @@ def cli_node_clean() -> None:
|
|
|
26
26
|
msg += volume.name + ","
|
|
27
27
|
info(msg)
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
try:
|
|
30
|
+
confirm = q.confirm("Are you sure?").unsafe_ask()
|
|
31
|
+
except KeyboardInterrupt:
|
|
32
|
+
confirm = False
|
|
33
|
+
|
|
34
|
+
if confirm:
|
|
31
35
|
for volume in candidates:
|
|
32
36
|
try:
|
|
33
37
|
volume.remove()
|
|
@@ -38,7 +38,9 @@ def create_client(ctx: NodeContext) -> UserClient:
|
|
|
38
38
|
return UserClient(host, port, api_path, log_level="warn")
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
def create_client_and_authenticate(
|
|
41
|
+
def create_client_and_authenticate(
|
|
42
|
+
ctx: NodeContext, ask_mfa: bool = False
|
|
43
|
+
) -> UserClient:
|
|
42
44
|
"""
|
|
43
45
|
Generate a client and authenticate with the server.
|
|
44
46
|
|
|
@@ -46,6 +48,8 @@ def create_client_and_authenticate(ctx: NodeContext) -> UserClient:
|
|
|
46
48
|
----------
|
|
47
49
|
ctx : NodeContext
|
|
48
50
|
Context of the node loaded from the configuration file
|
|
51
|
+
ask_mfa : bool, optional
|
|
52
|
+
Whether to ask for MFA code, by default False
|
|
49
53
|
|
|
50
54
|
Returns
|
|
51
55
|
-------
|
|
@@ -54,11 +58,14 @@ def create_client_and_authenticate(ctx: NodeContext) -> UserClient:
|
|
|
54
58
|
"""
|
|
55
59
|
client = create_client(ctx)
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
try:
|
|
62
|
+
username, password, mfa_code = _get_auth_data()
|
|
63
|
+
except KeyboardInterrupt:
|
|
64
|
+
error("Authentication aborted.")
|
|
65
|
+
exit(1)
|
|
59
66
|
|
|
60
67
|
try:
|
|
61
|
-
client.authenticate(username, password)
|
|
68
|
+
client.authenticate(username, password, mfa_code=mfa_code)
|
|
62
69
|
|
|
63
70
|
except Exception as exc:
|
|
64
71
|
error("Could not authenticate with server!")
|
|
@@ -68,6 +75,21 @@ def create_client_and_authenticate(ctx: NodeContext) -> UserClient:
|
|
|
68
75
|
return client
|
|
69
76
|
|
|
70
77
|
|
|
78
|
+
def _get_auth_data() -> tuple[str, str, str]:
|
|
79
|
+
"""
|
|
80
|
+
Get authentication data from the user.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
tuple[str, str, str]
|
|
85
|
+
Tuple containing username, password and MFA code
|
|
86
|
+
"""
|
|
87
|
+
username = q.text("Username:").unsafe_ask()
|
|
88
|
+
password = q.password("Password:").unsafe_ask()
|
|
89
|
+
mfa_code = q.text("MFA code:").unsafe_ask()
|
|
90
|
+
return username, password, mfa_code
|
|
91
|
+
|
|
92
|
+
|
|
71
93
|
def select_node(name: str, system_folders: bool) -> tuple[str, str]:
|
|
72
94
|
"""
|
|
73
95
|
Let user select node through questionnaire if name is not given.
|
|
@@ -59,6 +59,13 @@ from vantage6.cli.node.common import select_node, create_client_and_authenticate
|
|
|
59
59
|
default=False,
|
|
60
60
|
help="Overwrite existing private key if present",
|
|
61
61
|
)
|
|
62
|
+
@click.option(
|
|
63
|
+
"--mfa",
|
|
64
|
+
"ask_mfa",
|
|
65
|
+
flag_value=True,
|
|
66
|
+
default=False,
|
|
67
|
+
help="Ask for multi-factor authentication code. Use this if MFA is enabled on the server.",
|
|
68
|
+
)
|
|
62
69
|
def cli_node_create_private_key(
|
|
63
70
|
name: str,
|
|
64
71
|
config: str,
|
|
@@ -66,6 +73,7 @@ def cli_node_create_private_key(
|
|
|
66
73
|
upload: bool,
|
|
67
74
|
organization_name: str,
|
|
68
75
|
overwrite: bool,
|
|
76
|
+
ask_mfa: bool,
|
|
69
77
|
) -> None:
|
|
70
78
|
"""
|
|
71
79
|
Create and upload a new private key
|
|
@@ -89,7 +97,7 @@ def cli_node_create_private_key(
|
|
|
89
97
|
# Authenticate with the server to obtain organization name if it wasn't
|
|
90
98
|
# provided
|
|
91
99
|
if organization_name is None:
|
|
92
|
-
client = create_client_and_authenticate(ctx)
|
|
100
|
+
client = create_client_and_authenticate(ctx, ask_mfa)
|
|
93
101
|
organization_name = client.whoami.organization_name
|
|
94
102
|
|
|
95
103
|
# create directory where private key goes if it doesn't exist yet
|
|
@@ -103,7 +111,7 @@ def cli_node_create_private_key(
|
|
|
103
111
|
warning(f"File '{Fore.CYAN}{file_}{Style.RESET_ALL}' exists!")
|
|
104
112
|
|
|
105
113
|
if overwrite:
|
|
106
|
-
warning("'--
|
|
114
|
+
warning("'--overwrite' specified, so it will be overwritten ...")
|
|
107
115
|
|
|
108
116
|
if file_.exists() and not overwrite:
|
|
109
117
|
error("Could not create private key!")
|
vantage6/cli/node/new.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import click
|
|
2
2
|
from colorama import Fore, Style
|
|
3
3
|
|
|
4
|
-
from vantage6.common import error, info,
|
|
4
|
+
from vantage6.common import error, info, ensure_config_dir_writable
|
|
5
5
|
from vantage6.cli.context.node import NodeContext
|
|
6
6
|
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
7
7
|
from vantage6.cli.configuration_wizard import configuration_wizard
|
|
@@ -41,13 +41,17 @@ def cli_node_new_configuration(name: str, system_folders: bool) -> None:
|
|
|
41
41
|
exit(1)
|
|
42
42
|
|
|
43
43
|
# Check that we can write in this folder
|
|
44
|
-
if not
|
|
44
|
+
if not ensure_config_dir_writable(system_folders):
|
|
45
45
|
error("Cannot write configuration file. Exiting...")
|
|
46
46
|
exit(1)
|
|
47
47
|
|
|
48
48
|
# create config in ctx location
|
|
49
49
|
flag = "--system" if system_folders else ""
|
|
50
|
-
|
|
50
|
+
try:
|
|
51
|
+
cfg_file = configuration_wizard(InstanceType.NODE, name, system_folders)
|
|
52
|
+
except KeyboardInterrupt:
|
|
53
|
+
error("Configuration creation aborted.")
|
|
54
|
+
exit(1)
|
|
51
55
|
info(f"New configuration created: {Fore.GREEN}{cfg_file}{Style.RESET_ALL}")
|
|
52
56
|
info(
|
|
53
57
|
f"You can start the node by running "
|