vantage6 4.2.1__py3-none-any.whl → 4.3.0b3__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_example.py +0 -1
- tests_cli/test_node_cli.py +74 -79
- tests_cli/test_server_cli.py +22 -22
- tests_cli/test_wizard.py +41 -29
- vantage6/cli/__build__ +1 -1
- vantage6/cli/_version.py +11 -8
- vantage6/cli/algorithm/create.py +14 -14
- vantage6/cli/algorithm/update.py +9 -6
- vantage6/cli/algostore/attach.py +32 -0
- vantage6/cli/algostore/new.py +55 -0
- vantage6/cli/algostore/start.py +102 -0
- vantage6/cli/algostore/stop.py +60 -0
- vantage6/cli/cli.py +32 -12
- vantage6/cli/common/decorator.py +92 -0
- vantage6/cli/common/start.py +232 -0
- vantage6/cli/configuration_manager.py +22 -32
- vantage6/cli/configuration_wizard.py +255 -193
- vantage6/cli/context/__init__.py +86 -0
- vantage6/cli/context/algorithm_store.py +130 -0
- vantage6/cli/context/base_server.py +89 -0
- vantage6/cli/context/node.py +254 -0
- vantage6/cli/context/server.py +127 -0
- vantage6/cli/dev/create.py +180 -113
- vantage6/cli/dev/remove.py +20 -19
- vantage6/cli/dev/start.py +10 -10
- vantage6/cli/dev/stop.py +7 -5
- vantage6/cli/globals.py +24 -0
- vantage6/cli/node/attach.py +21 -10
- vantage6/cli/node/clean.py +4 -2
- vantage6/cli/node/common/__init__.py +15 -11
- vantage6/cli/node/create_private_key.py +58 -27
- vantage6/cli/node/files.py +14 -6
- vantage6/cli/node/list.py +18 -24
- vantage6/cli/node/new.py +21 -12
- vantage6/cli/node/remove.py +31 -22
- vantage6/cli/node/set_api_key.py +18 -12
- vantage6/cli/node/start.py +38 -12
- vantage6/cli/node/stop.py +32 -18
- vantage6/cli/node/version.py +23 -13
- vantage6/cli/rabbitmq/__init__.py +9 -9
- vantage6/cli/rabbitmq/definitions.py +24 -28
- vantage6/cli/rabbitmq/queue_manager.py +37 -40
- vantage6/cli/server/attach.py +16 -11
- vantage6/cli/server/common/__init__.py +37 -25
- vantage6/cli/server/files.py +1 -1
- vantage6/cli/server/import_.py +45 -37
- vantage6/cli/server/list.py +22 -23
- vantage6/cli/server/new.py +20 -14
- vantage6/cli/server/remove.py +5 -4
- vantage6/cli/server/shell.py +17 -6
- vantage6/cli/server/start.py +118 -174
- vantage6/cli/server/stop.py +31 -23
- vantage6/cli/server/version.py +16 -13
- vantage6/cli/test/common/diagnostic_runner.py +30 -34
- vantage6/cli/test/feature_tester.py +51 -25
- vantage6/cli/test/integration_test.py +69 -29
- vantage6/cli/utils.py +6 -5
- {vantage6-4.2.1.dist-info → vantage6-4.3.0b3.dist-info}/METADATA +5 -3
- vantage6-4.3.0b3.dist-info/RECORD +68 -0
- vantage6/cli/context.py +0 -416
- vantage6-4.2.1.dist-info/RECORD +0 -58
- {vantage6-4.2.1.dist-info → vantage6-4.3.0b3.dist-info}/WHEEL +0 -0
- {vantage6-4.2.1.dist-info → vantage6-4.3.0b3.dist-info}/entry_points.txt +0 -0
- {vantage6-4.2.1.dist-info → vantage6-4.3.0b3.dist-info}/top_level.txt +0 -0
|
@@ -3,14 +3,16 @@ import questionary as q
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
from vantage6.common import generate_apikey
|
|
6
|
-
from vantage6.common.globals import DATABASE_TYPES
|
|
6
|
+
from vantage6.common.globals import DATABASE_TYPES, InstanceType
|
|
7
7
|
from vantage6.common.client.node_client import NodeClient
|
|
8
|
+
from vantage6.common.context import AppContext
|
|
8
9
|
from vantage6.common import error, warning
|
|
9
|
-
from vantage6.cli.context import
|
|
10
|
+
from vantage6.cli.context import select_context_class
|
|
10
11
|
from vantage6.cli.configuration_manager import (
|
|
11
12
|
NodeConfigurationManager,
|
|
12
|
-
ServerConfigurationManager
|
|
13
|
+
ServerConfigurationManager,
|
|
13
14
|
)
|
|
15
|
+
from vantage6.cli.globals import AlgoStoreGlobals, ServerGlobals
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
@@ -29,75 +31,69 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
29
31
|
dict
|
|
30
32
|
Dictionary with the new node configuration
|
|
31
33
|
"""
|
|
32
|
-
config = q.prompt(
|
|
33
|
-
|
|
34
|
-
"type": "text",
|
|
35
|
-
"name": "api_key",
|
|
36
|
-
"message": "Enter given api-key:"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"type": "text",
|
|
40
|
-
"name": "server_url",
|
|
41
|
-
"message": "The base-URL of the server:",
|
|
42
|
-
"default": "http://localhost"
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"type": "text",
|
|
46
|
-
"name": "port",
|
|
47
|
-
"message": "Enter port to which the server listens:",
|
|
48
|
-
"default": "5000"
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"type": "text",
|
|
52
|
-
"name": "api_path",
|
|
53
|
-
"message": "Path of the api:",
|
|
54
|
-
"default": "/api"
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
"type": "text",
|
|
58
|
-
"name": "task_dir",
|
|
59
|
-
"message": "Task directory path:",
|
|
60
|
-
"default": str(dirs["data"])
|
|
61
|
-
}
|
|
62
|
-
])
|
|
63
|
-
|
|
64
|
-
config["databases"] = list()
|
|
65
|
-
while q.confirm("Do you want to add a database?").ask():
|
|
66
|
-
db_label = q.prompt([
|
|
34
|
+
config = q.prompt(
|
|
35
|
+
[
|
|
36
|
+
{"type": "text", "name": "api_key", "message": "Enter given api-key:"},
|
|
67
37
|
{
|
|
68
38
|
"type": "text",
|
|
69
|
-
"name": "
|
|
70
|
-
"message": "
|
|
71
|
-
"default": "
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
39
|
+
"name": "server_url",
|
|
40
|
+
"message": "The base-URL of the server:",
|
|
41
|
+
"default": "http://localhost",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"type": "text",
|
|
45
|
+
"name": "port",
|
|
46
|
+
"message": "Enter port to which the server listens:",
|
|
47
|
+
"default": "5000",
|
|
48
|
+
},
|
|
75
49
|
{
|
|
76
50
|
"type": "text",
|
|
77
|
-
"name": "
|
|
78
|
-
"message": "
|
|
79
|
-
|
|
80
|
-
|
|
51
|
+
"name": "api_path",
|
|
52
|
+
"message": "Path of the api:",
|
|
53
|
+
"default": "/api",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "text",
|
|
57
|
+
"name": "task_dir",
|
|
58
|
+
"message": "Task directory path:",
|
|
59
|
+
"default": str(dirs["data"]),
|
|
60
|
+
},
|
|
61
|
+
]
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
config["databases"] = list()
|
|
65
|
+
while q.confirm("Do you want to add a database?").ask():
|
|
66
|
+
db_label = q.prompt(
|
|
67
|
+
[
|
|
68
|
+
{
|
|
69
|
+
"type": "text",
|
|
70
|
+
"name": "label",
|
|
71
|
+
"message": "Enter unique label for the database:",
|
|
72
|
+
"default": "default",
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
)
|
|
76
|
+
db_path = q.prompt(
|
|
77
|
+
[{"type": "text", "name": "uri", "message": "Database URI:"}]
|
|
78
|
+
)
|
|
81
79
|
db_type = q.select("Database type:", choices=DATABASE_TYPES).ask()
|
|
82
80
|
|
|
83
81
|
config["databases"].append(
|
|
84
|
-
{
|
|
85
|
-
"label": db_label.get("label"),
|
|
86
|
-
"uri": db_path.get("uri"),
|
|
87
|
-
"type": db_type
|
|
88
|
-
}
|
|
82
|
+
{"label": db_label.get("label"), "uri": db_path.get("uri"), "type": db_type}
|
|
89
83
|
)
|
|
90
84
|
|
|
91
|
-
res = q.select(
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
res = q.select(
|
|
86
|
+
"Which level of logging would you like?",
|
|
87
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NOTSET"],
|
|
88
|
+
).ask()
|
|
94
89
|
|
|
95
90
|
is_add_vpn = q.confirm(
|
|
96
|
-
"Do you want to connect to a VPN server?", default=False
|
|
91
|
+
"Do you want to connect to a VPN server?", default=False
|
|
92
|
+
).ask()
|
|
97
93
|
if is_add_vpn:
|
|
98
|
-
config[
|
|
94
|
+
config["vpn_subnet"] = q.text(
|
|
99
95
|
message="Subnet of the VPN server you want to connect to:",
|
|
100
|
-
default=
|
|
96
|
+
default="10.76.0.0/16",
|
|
101
97
|
).ask()
|
|
102
98
|
|
|
103
99
|
config["logging"] = {
|
|
@@ -113,19 +109,20 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
113
109
|
{"name": "engineio.client", "level": "warning"},
|
|
114
110
|
{"name": "docker.utils.config", "level": "warning"},
|
|
115
111
|
{"name": "docker.auth", "level": "warning"},
|
|
116
|
-
]
|
|
112
|
+
],
|
|
117
113
|
}
|
|
118
114
|
|
|
119
115
|
# Check if we can login to the server to retrieve collaboration settings
|
|
120
|
-
client = NodeClient(config[
|
|
121
|
-
config['api_path'])
|
|
116
|
+
client = NodeClient(config["server_url"], config["port"], config["api_path"])
|
|
122
117
|
try:
|
|
123
|
-
client.authenticate(config[
|
|
118
|
+
client.authenticate(config["api_key"])
|
|
124
119
|
except Exception as e:
|
|
125
120
|
error(f"Could not authenticate with server: {e}")
|
|
126
121
|
error("Please check (1) your API key and (2) if your server is online")
|
|
127
|
-
warning(
|
|
128
|
-
|
|
122
|
+
warning(
|
|
123
|
+
"If you continue, you should provide your collaboration "
|
|
124
|
+
"settings manually."
|
|
125
|
+
)
|
|
129
126
|
if q.confirm("Do you want to abort?", default=True).ask():
|
|
130
127
|
exit(0)
|
|
131
128
|
|
|
@@ -134,140 +131,102 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
134
131
|
# TODO when we build collaboration policies, update this to provide
|
|
135
132
|
# the node admin with a list of all policies, and whether or not
|
|
136
133
|
# to accept them
|
|
137
|
-
q.confirm(
|
|
138
|
-
|
|
134
|
+
q.confirm(
|
|
135
|
+
f"Encryption is {'enabled' if encryption else 'disabled'}"
|
|
136
|
+
f" for this collaboration. Accept?",
|
|
137
|
+
default=True,
|
|
138
|
+
).ask()
|
|
139
139
|
else:
|
|
140
140
|
encryption = q.confirm("Enable encryption?", default=True).ask()
|
|
141
141
|
|
|
142
|
-
private_key = "" if not encryption else
|
|
143
|
-
q.text("Path to private key file:").ask()
|
|
142
|
+
private_key = "" if not encryption else q.text("Path to private key file:").ask()
|
|
144
143
|
|
|
145
|
-
config["encryption"] = {
|
|
146
|
-
"enabled": encryption == "true",
|
|
147
|
-
"private_key": private_key
|
|
148
|
-
}
|
|
144
|
+
config["encryption"] = {"enabled": encryption == "true", "private_key": private_key}
|
|
149
145
|
|
|
150
146
|
return config
|
|
151
147
|
|
|
152
148
|
|
|
153
|
-
def
|
|
149
|
+
def _get_common_server_config(
|
|
150
|
+
instance_type: InstanceType, instance_name: str, include_api_path: bool = True
|
|
151
|
+
) -> dict:
|
|
154
152
|
"""
|
|
155
|
-
|
|
153
|
+
Part of the questionaire that is common to all server types (vantage6
|
|
154
|
+
server and algorithm store server).
|
|
156
155
|
|
|
157
156
|
Parameters
|
|
158
157
|
----------
|
|
158
|
+
instance_type : InstanceType
|
|
159
|
+
Type of server instance.
|
|
159
160
|
instance_name : str
|
|
160
|
-
Name of the
|
|
161
|
+
Name of the server instance.
|
|
162
|
+
include_api_path : bool
|
|
163
|
+
Whether to include the api path in the questionaire.
|
|
161
164
|
|
|
162
165
|
Returns
|
|
163
166
|
-------
|
|
164
167
|
dict
|
|
165
|
-
Dictionary with
|
|
168
|
+
Dictionary with new (partial) server configuration
|
|
166
169
|
"""
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
{
|
|
170
|
-
"type": "text",
|
|
171
|
-
"name": "description",
|
|
172
|
-
"message": "Enter a human-readable description:"
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
"type": "text",
|
|
176
|
-
"name": "ip",
|
|
177
|
-
"message": "ip:",
|
|
178
|
-
"default": "0.0.0.0"
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
"type": "text",
|
|
182
|
-
"name": "port",
|
|
183
|
-
"message": "Enter port to which the server listens:",
|
|
184
|
-
"default": "5000"
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
"type": "text",
|
|
188
|
-
"name": "api_path",
|
|
189
|
-
"message": "Path of the api:",
|
|
190
|
-
"default": "/api"
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
"type": "text",
|
|
194
|
-
"name": "uri",
|
|
195
|
-
"message": "Database URI:",
|
|
196
|
-
"default": "sqlite:///default.sqlite"
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
"type": "select",
|
|
200
|
-
"name": "allow_drop_all",
|
|
201
|
-
"message": "Allowed to drop all tables: ",
|
|
202
|
-
"choices": ["True", "False"]
|
|
203
|
-
}
|
|
204
|
-
])
|
|
205
|
-
|
|
206
|
-
constant_jwt_secret = q.confirm("Do you want a constant JWT secret?").ask()
|
|
207
|
-
if constant_jwt_secret:
|
|
208
|
-
config["jwt_secret_key"] = generate_apikey()
|
|
209
|
-
|
|
210
|
-
res = q.select("Which level of logging would you like?",
|
|
211
|
-
choices=["DEBUG", "INFO", "WARNING", "ERROR",
|
|
212
|
-
"CRITICAL", "NOTSET"]).ask()
|
|
213
|
-
|
|
214
|
-
is_mfa = q.confirm(
|
|
215
|
-
"Do you want to enforce two-factor authentication?"
|
|
216
|
-
).ask()
|
|
217
|
-
if is_mfa:
|
|
218
|
-
config['two_factor_auth'] = is_mfa
|
|
219
|
-
|
|
220
|
-
is_add_vpn = q.confirm(
|
|
221
|
-
"Do you want to add a VPN server?", default=False).ask()
|
|
222
|
-
if is_add_vpn:
|
|
223
|
-
vpn_config = q.prompt([
|
|
224
|
-
{
|
|
225
|
-
"type": "text",
|
|
226
|
-
"name": "url",
|
|
227
|
-
"message": "VPN server URL:",
|
|
228
|
-
},
|
|
170
|
+
config = q.prompt(
|
|
171
|
+
[
|
|
229
172
|
{
|
|
230
173
|
"type": "text",
|
|
231
|
-
"name": "
|
|
232
|
-
"message": "
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
"type": "password",
|
|
236
|
-
"name": "portal_userpass",
|
|
237
|
-
"message": "VPN portal password:",
|
|
174
|
+
"name": "description",
|
|
175
|
+
"message": "Enter a human-readable description:",
|
|
238
176
|
},
|
|
177
|
+
{"type": "text", "name": "ip", "message": "ip:", "default": "0.0.0.0"},
|
|
239
178
|
{
|
|
240
179
|
"type": "text",
|
|
241
|
-
"name": "
|
|
242
|
-
"message": "
|
|
180
|
+
"name": "port",
|
|
181
|
+
"message": "Enter port to which the server listens:",
|
|
182
|
+
"default": (
|
|
183
|
+
# Note that .value is required in YAML to get proper str value
|
|
184
|
+
ServerGlobals.PORT.value
|
|
185
|
+
if instance_type == InstanceType.SERVER
|
|
186
|
+
else AlgoStoreGlobals.PORT.value
|
|
187
|
+
),
|
|
243
188
|
},
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
189
|
+
]
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# TODO v5+ remove api_path. It complicates configuration
|
|
193
|
+
if include_api_path:
|
|
194
|
+
config.update(
|
|
195
|
+
q.prompt(
|
|
196
|
+
[
|
|
197
|
+
{
|
|
198
|
+
"type": "text",
|
|
199
|
+
"name": "api_path",
|
|
200
|
+
"message": "Path of the api:",
|
|
201
|
+
"default": "/api",
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
config.update(
|
|
208
|
+
q.prompt(
|
|
209
|
+
[
|
|
210
|
+
{
|
|
211
|
+
"type": "text",
|
|
212
|
+
"name": "uri",
|
|
213
|
+
"message": "Database URI:",
|
|
214
|
+
"default": "sqlite:///default.sqlite",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"type": "select",
|
|
218
|
+
"name": "allow_drop_all",
|
|
219
|
+
"message": "Allowed to drop all tables: ",
|
|
220
|
+
"choices": ["True", "False"],
|
|
221
|
+
},
|
|
222
|
+
]
|
|
223
|
+
)
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
res = q.select(
|
|
227
|
+
"Which level of logging would you like?",
|
|
228
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NOTSET"],
|
|
229
|
+
).ask()
|
|
271
230
|
|
|
272
231
|
config["logging"] = {
|
|
273
232
|
"level": res,
|
|
@@ -284,21 +243,123 @@ def server_configuration_questionaire(instance_name: str) -> dict:
|
|
|
284
243
|
{"name": "engineio.server", "level": "warning"},
|
|
285
244
|
{"name": "sqlalchemy.engine", "level": "warning"},
|
|
286
245
|
{"name": "requests_oauthlib.oauth2_session", "level": "warning"},
|
|
287
|
-
]
|
|
246
|
+
],
|
|
288
247
|
}
|
|
289
248
|
|
|
290
249
|
return config
|
|
291
250
|
|
|
292
251
|
|
|
293
|
-
def
|
|
294
|
-
|
|
252
|
+
def server_configuration_questionaire(instance_name: str) -> dict:
|
|
253
|
+
"""
|
|
254
|
+
Questionary to generate a config file for the server instance.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
instance_name : str
|
|
259
|
+
Name of the server instance.
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
dict
|
|
264
|
+
Dictionary with the new server configuration
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
config = _get_common_server_config(
|
|
268
|
+
InstanceType.SERVER, instance_name, include_api_path=True
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
constant_jwt_secret = q.confirm("Do you want a constant JWT secret?").ask()
|
|
272
|
+
if constant_jwt_secret:
|
|
273
|
+
config["jwt_secret_key"] = generate_apikey()
|
|
274
|
+
|
|
275
|
+
is_mfa = q.confirm("Do you want to enforce two-factor authentication?").ask()
|
|
276
|
+
if is_mfa:
|
|
277
|
+
config["two_factor_auth"] = is_mfa
|
|
278
|
+
|
|
279
|
+
is_add_vpn = q.confirm("Do you want to add a VPN server?", default=False).ask()
|
|
280
|
+
if is_add_vpn:
|
|
281
|
+
vpn_config = q.prompt(
|
|
282
|
+
[
|
|
283
|
+
{
|
|
284
|
+
"type": "text",
|
|
285
|
+
"name": "url",
|
|
286
|
+
"message": "VPN server URL:",
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"type": "text",
|
|
290
|
+
"name": "portal_username",
|
|
291
|
+
"message": "VPN portal username:",
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"type": "password",
|
|
295
|
+
"name": "portal_userpass",
|
|
296
|
+
"message": "VPN portal password:",
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"type": "text",
|
|
300
|
+
"name": "client_id",
|
|
301
|
+
"message": "VPN client username:",
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"type": "password",
|
|
305
|
+
"name": "client_secret",
|
|
306
|
+
"message": "VPN client password:",
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"type": "text",
|
|
310
|
+
"name": "redirect_url",
|
|
311
|
+
"message": "Redirect url (should be local address of server)",
|
|
312
|
+
"default": "http://localhost",
|
|
313
|
+
},
|
|
314
|
+
]
|
|
315
|
+
)
|
|
316
|
+
config["vpn_server"] = vpn_config
|
|
317
|
+
|
|
318
|
+
is_add_rabbitmq = q.confirm("Do you want to add a RabbitMQ message queue?").ask()
|
|
319
|
+
if is_add_rabbitmq:
|
|
320
|
+
rabbit_uri = q.text(message="Enter the URI for your RabbitMQ:").ask()
|
|
321
|
+
run_rabbit_locally = q.confirm(
|
|
322
|
+
"Do you want to run RabbitMQ locally? (Use only for testing)"
|
|
323
|
+
).ask()
|
|
324
|
+
config["rabbitmq"] = {
|
|
325
|
+
"uri": rabbit_uri,
|
|
326
|
+
"start_with_server": run_rabbit_locally,
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return config
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def algo_store_configuration_questionaire(instance_name: str) -> dict:
|
|
333
|
+
"""
|
|
334
|
+
Questionary to generate a config file for the algorithm store server
|
|
335
|
+
instance.
|
|
336
|
+
|
|
337
|
+
Parameters
|
|
338
|
+
----------
|
|
339
|
+
instance_name : str
|
|
340
|
+
Name of the server instance.
|
|
341
|
+
|
|
342
|
+
Returns
|
|
343
|
+
-------
|
|
344
|
+
dict
|
|
345
|
+
Dictionary with the new server configuration
|
|
346
|
+
"""
|
|
347
|
+
config = _get_common_server_config(
|
|
348
|
+
InstanceType.ALGORITHM_STORE, instance_name, include_api_path=False
|
|
349
|
+
)
|
|
350
|
+
return config
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def configuration_wizard(
|
|
354
|
+
type_: InstanceType, instance_name: str, system_folders: bool
|
|
355
|
+
) -> Path:
|
|
295
356
|
"""
|
|
296
357
|
Create a configuration file for a node or server instance.
|
|
297
358
|
|
|
298
359
|
Parameters
|
|
299
360
|
----------
|
|
300
|
-
type_ :
|
|
301
|
-
Type of the instance
|
|
361
|
+
type_ : InstanceType
|
|
362
|
+
Type of the instance to create a configuration for
|
|
302
363
|
instance_name : str
|
|
303
364
|
Name of the instance
|
|
304
365
|
system_folders : bool
|
|
@@ -310,15 +371,18 @@ def configuration_wizard(type_: str, instance_name: str,
|
|
|
310
371
|
Path to the configuration file
|
|
311
372
|
"""
|
|
312
373
|
# for defaults and where to save the config
|
|
313
|
-
dirs =
|
|
374
|
+
dirs = AppContext.instance_folders(type_, instance_name, system_folders)
|
|
314
375
|
|
|
315
376
|
# invoke questionaire to create configuration file
|
|
316
|
-
if type_ ==
|
|
377
|
+
if type_ == InstanceType.NODE:
|
|
317
378
|
conf_manager = NodeConfigurationManager
|
|
318
379
|
config = node_configuration_questionaire(dirs, instance_name)
|
|
319
|
-
|
|
380
|
+
elif type_ == InstanceType.SERVER:
|
|
320
381
|
conf_manager = ServerConfigurationManager
|
|
321
382
|
config = server_configuration_questionaire(instance_name)
|
|
383
|
+
else:
|
|
384
|
+
conf_manager = ServerConfigurationManager
|
|
385
|
+
config = algo_store_configuration_questionaire(instance_name)
|
|
322
386
|
|
|
323
387
|
# in the case of an environment we need to add it to the current
|
|
324
388
|
# configuration. In the case of application we can simply overwrite this
|
|
@@ -336,15 +400,15 @@ def configuration_wizard(type_: str, instance_name: str,
|
|
|
336
400
|
return config_file
|
|
337
401
|
|
|
338
402
|
|
|
339
|
-
def select_configuration_questionaire(type_:
|
|
403
|
+
def select_configuration_questionaire(type_: InstanceType, system_folders: bool) -> str:
|
|
340
404
|
"""
|
|
341
405
|
Ask which configuration the user wants to use. It shows only configurations
|
|
342
406
|
that are in the default folder.
|
|
343
407
|
|
|
344
408
|
Parameters
|
|
345
409
|
----------
|
|
346
|
-
type_ :
|
|
347
|
-
Type of the instance
|
|
410
|
+
type_ : InstanceType
|
|
411
|
+
Type of the instance to create a configuration for
|
|
348
412
|
system_folders : bool
|
|
349
413
|
Whether to use the system folders or not
|
|
350
414
|
|
|
@@ -353,21 +417,19 @@ def select_configuration_questionaire(type_: str, system_folders: bool) -> str:
|
|
|
353
417
|
str
|
|
354
418
|
Name of the configuration
|
|
355
419
|
"""
|
|
356
|
-
context =
|
|
420
|
+
context = select_context_class(type_)
|
|
357
421
|
configs, _ = context.available_configurations(system_folders)
|
|
358
422
|
|
|
359
423
|
# each collection (file) can contain multiple configs. (e.g. test,
|
|
360
424
|
# dev)
|
|
361
425
|
choices = []
|
|
362
426
|
for config_collection in configs:
|
|
363
|
-
choices.append(
|
|
364
|
-
title=f"{config_collection.name:25}",
|
|
365
|
-
|
|
366
|
-
))
|
|
427
|
+
choices.append(
|
|
428
|
+
q.Choice(title=f"{config_collection.name:25}", value=config_collection.name)
|
|
429
|
+
)
|
|
367
430
|
|
|
368
431
|
if not choices:
|
|
369
432
|
raise Exception("No configurations could be found!")
|
|
370
433
|
|
|
371
434
|
# pop the question
|
|
372
|
-
return q.select("Select the configuration you want to use:",
|
|
373
|
-
choices=choices).ask()
|
|
435
|
+
return q.select("Select the configuration you want to use:", choices=choices).ask()
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The context module in the CLI package contains the Context classes of instances
|
|
3
|
+
started from the CLI, such as nodes and servers. These contexts are related to
|
|
4
|
+
the host system and therefore part of the CLI package.
|
|
5
|
+
|
|
6
|
+
All classes are derived from the abstract AppContext class and provide the
|
|
7
|
+
vantage6 applications with naming conventions, standard file locations, and
|
|
8
|
+
more.
|
|
9
|
+
"""
|
|
10
|
+
from colorama import Fore, Style
|
|
11
|
+
|
|
12
|
+
from vantage6.common.globals import InstanceType
|
|
13
|
+
from vantage6.common import error
|
|
14
|
+
from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
|
|
15
|
+
from vantage6.cli.context.node import NodeContext
|
|
16
|
+
from vantage6.cli.context.server import ServerContext
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def select_context_class(
|
|
20
|
+
type_: InstanceType,
|
|
21
|
+
) -> ServerContext | NodeContext | AlgorithmStoreContext:
|
|
22
|
+
"""
|
|
23
|
+
Select the context class based on the type of instance.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
type_ : InstanceType
|
|
28
|
+
The type of instance for which the context should be inserted
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
ServerContext | NodeContext | AlgorithmStoreContext
|
|
33
|
+
Specialized subclass of AppContext for the given instance type
|
|
34
|
+
|
|
35
|
+
Raises
|
|
36
|
+
------
|
|
37
|
+
NotImplementedError
|
|
38
|
+
If the type_ is not implemented
|
|
39
|
+
"""
|
|
40
|
+
if type_ == InstanceType.SERVER:
|
|
41
|
+
return ServerContext
|
|
42
|
+
elif type_ == InstanceType.ALGORITHM_STORE:
|
|
43
|
+
return AlgorithmStoreContext
|
|
44
|
+
elif type_ == InstanceType.NODE:
|
|
45
|
+
return NodeContext
|
|
46
|
+
else:
|
|
47
|
+
raise NotImplementedError
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_context(
|
|
51
|
+
type_: InstanceType, name: str, system_folders: bool
|
|
52
|
+
) -> ServerContext | NodeContext | AlgorithmStoreContext:
|
|
53
|
+
"""
|
|
54
|
+
Load the server context from the configuration file.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
type_ : InstanceType
|
|
59
|
+
The type of instance to get the context for
|
|
60
|
+
name : str
|
|
61
|
+
Name of the instance
|
|
62
|
+
system_folders : bool
|
|
63
|
+
Wether to use system folders or if False, the user folders
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
AppContext
|
|
68
|
+
Specialized subclass context of AppContext for the given instance type
|
|
69
|
+
"""
|
|
70
|
+
ctx_class = select_context_class(type_)
|
|
71
|
+
if not ctx_class.config_exists(name, system_folders):
|
|
72
|
+
scope = "system" if system_folders else "user"
|
|
73
|
+
error(
|
|
74
|
+
f"Configuration {Fore.RED}{name}{Style.RESET_ALL} does not "
|
|
75
|
+
f"exist in the {Fore.RED}{scope}{Style.RESET_ALL} folders!"
|
|
76
|
+
)
|
|
77
|
+
exit(1)
|
|
78
|
+
|
|
79
|
+
# We do not want to log this here, we do this in the container and not on
|
|
80
|
+
# the host. We only want CLI logging here.
|
|
81
|
+
ctx_class.LOGGING_ENABLED = False
|
|
82
|
+
|
|
83
|
+
# create server context, and initialize db
|
|
84
|
+
ctx = ctx_class(name, system_folders=system_folders)
|
|
85
|
+
|
|
86
|
+
return ctx
|