vantage6 5.0.0a22__py3-none-any.whl → 5.0.0a29__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_client_script.py +23 -0
- tests_cli/test_server_cli.py +7 -6
- tests_cli/test_wizard.py +7 -7
- vantage6/cli/__build__ +1 -1
- vantage6/cli/algorithm/generate_algorithm_json.py +531 -0
- vantage6/cli/algostore/list.py +2 -1
- vantage6/cli/algostore/start.py +6 -6
- vantage6/cli/algostore/stop.py +3 -2
- vantage6/cli/cli.py +25 -0
- vantage6/cli/common/decorator.py +3 -1
- vantage6/cli/common/start.py +221 -12
- vantage6/cli/common/stop.py +90 -0
- vantage6/cli/common/utils.py +15 -20
- vantage6/cli/config.py +260 -0
- vantage6/cli/configuration_manager.py +8 -14
- vantage6/cli/configuration_wizard.py +66 -111
- vantage6/cli/context/__init__.py +2 -1
- vantage6/cli/context/algorithm_store.py +10 -7
- vantage6/cli/context/node.py +38 -54
- vantage6/cli/context/server.py +36 -5
- vantage6/cli/dev/create.py +88 -29
- vantage6/cli/dev/data/km_dataset.csv +2401 -0
- vantage6/cli/dev/remove.py +99 -98
- vantage6/cli/globals.py +24 -4
- vantage6/cli/node/common/__init__.py +6 -5
- vantage6/cli/node/new.py +4 -3
- vantage6/cli/node/remove.py +4 -2
- vantage6/cli/node/start.py +33 -42
- vantage6/cli/prometheus/monitoring_manager.py +146 -0
- vantage6/cli/prometheus/prometheus.yml +5 -0
- vantage6/cli/server/files.py +4 -2
- vantage6/cli/server/import_.py +7 -7
- vantage6/cli/server/list.py +2 -1
- vantage6/cli/server/new.py +25 -6
- vantage6/cli/server/shell.py +5 -4
- vantage6/cli/server/start.py +44 -213
- vantage6/cli/server/stop.py +36 -105
- vantage6/cli/server/version.py +5 -4
- vantage6/cli/template/algo_store_config.j2 +0 -1
- vantage6/cli/template/node_config.j2 +3 -1
- vantage6/cli/template/server_import_config.j2 +0 -2
- vantage6/cli/test/algo_test_scripts/algo_test_arguments.py +29 -0
- vantage6/cli/test/algo_test_scripts/algo_test_script.py +92 -0
- vantage6/cli/test/client_script.py +151 -0
- vantage6/cli/test/common/diagnostic_runner.py +2 -2
- vantage6/cli/test/feature_tester.py +5 -2
- vantage6/cli/use/context.py +46 -0
- vantage6/cli/use/namespace.py +55 -0
- vantage6/cli/utils.py +70 -4
- {vantage6-5.0.0a22.dist-info → vantage6-5.0.0a29.dist-info}/METADATA +15 -11
- vantage6-5.0.0a29.dist-info/RECORD +84 -0
- {vantage6-5.0.0a22.dist-info → vantage6-5.0.0a29.dist-info}/WHEEL +1 -1
- vantage6-5.0.0a22.dist-info/RECORD +0 -72
- {vantage6-5.0.0a22.dist-info → vantage6-5.0.0a29.dist-info}/entry_points.txt +0 -0
- {vantage6-5.0.0a22.dist-info → vantage6-5.0.0a29.dist-info}/top_level.txt +0 -0
vantage6/cli/config.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from os import PathLike
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import questionary
|
|
6
|
+
import yaml
|
|
7
|
+
from colorama import Fore, Style
|
|
8
|
+
from kubernetes import config
|
|
9
|
+
|
|
10
|
+
from vantage6.common import info, warning
|
|
11
|
+
|
|
12
|
+
from vantage6.cli.globals import (
|
|
13
|
+
DEFAULT_CLI_CONFIG_FILE,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CliConfig:
|
|
18
|
+
"""
|
|
19
|
+
A class to manage CLI configuration for Kubernetes context and namespace.
|
|
20
|
+
|
|
21
|
+
The CLI configuration is stored in a `config.yaml` file located at the path
|
|
22
|
+
specified by `DEFAULT_CLI_CONFIG_FILE`.
|
|
23
|
+
|
|
24
|
+
The `config.yaml` file has the following structure:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
kube:
|
|
28
|
+
last_context: <last_used_k8s_context>
|
|
29
|
+
last_namespace: <last_used_k8s_namespace>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Attributes
|
|
33
|
+
----------
|
|
34
|
+
config_path : PathLike
|
|
35
|
+
Path to the configuration file.
|
|
36
|
+
_cached_config : dict or None
|
|
37
|
+
Cached configuration data.
|
|
38
|
+
_cached_mtime : float or None
|
|
39
|
+
Last modification time of the configuration file.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, config_path: str | PathLike = DEFAULT_CLI_CONFIG_FILE) -> None:
|
|
43
|
+
"""
|
|
44
|
+
Initialize the CliConfig object.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
config_path : str or PathLike, optional
|
|
49
|
+
Path to the configuration file.
|
|
50
|
+
"""
|
|
51
|
+
self.config_path: PathLike = Path(config_path)
|
|
52
|
+
self._cached_config: dict | None = None
|
|
53
|
+
self._cached_mtime: float | None = None
|
|
54
|
+
|
|
55
|
+
def _load_config(self) -> dict:
|
|
56
|
+
"""
|
|
57
|
+
Load the configuration from the file.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
dict
|
|
62
|
+
The loaded configuration data.
|
|
63
|
+
"""
|
|
64
|
+
if self.config_path.exists():
|
|
65
|
+
with open(self.config_path, "r") as config_file:
|
|
66
|
+
return yaml.safe_load(config_file) or {}
|
|
67
|
+
return {}
|
|
68
|
+
|
|
69
|
+
def _save_config(self, config: dict) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Save the configuration to the file.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
config : dict
|
|
76
|
+
The configuration data to save.
|
|
77
|
+
"""
|
|
78
|
+
self.config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
with open(self.config_path, "w") as config_file:
|
|
80
|
+
yaml.dump(config, config_file)
|
|
81
|
+
|
|
82
|
+
def _reload_cache_lazy(self) -> None:
|
|
83
|
+
"""
|
|
84
|
+
Reload the configuration cache if the file has been modified.
|
|
85
|
+
"""
|
|
86
|
+
if self.config_path.exists():
|
|
87
|
+
mtime = os.path.getmtime(self.config_path)
|
|
88
|
+
if self._cached_mtime != mtime:
|
|
89
|
+
self._cached_config = self._load_config()
|
|
90
|
+
self._cached_mtime = mtime
|
|
91
|
+
else:
|
|
92
|
+
self._cached_config = {}
|
|
93
|
+
self._cached_mtime = None
|
|
94
|
+
|
|
95
|
+
def get_last_context(self) -> str | None:
|
|
96
|
+
"""
|
|
97
|
+
Get the last used Kubernetes context.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
str or None
|
|
102
|
+
The last used Kubernetes context, or None if not set.
|
|
103
|
+
"""
|
|
104
|
+
self._reload_cache_lazy()
|
|
105
|
+
return self._cached_config.get("kube", {}).get("last_context")
|
|
106
|
+
|
|
107
|
+
def set_last_context(self, context: str) -> None:
|
|
108
|
+
"""
|
|
109
|
+
Set the Kubernetes context.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
context : str
|
|
114
|
+
The Kubernetes context to set.
|
|
115
|
+
"""
|
|
116
|
+
config = self._load_config()
|
|
117
|
+
if "kube" not in config:
|
|
118
|
+
config["kube"] = {}
|
|
119
|
+
|
|
120
|
+
if config["kube"].get("last_context") != context:
|
|
121
|
+
config["kube"]["last_context"] = context
|
|
122
|
+
self._save_config(config)
|
|
123
|
+
self._reload_cache_lazy()
|
|
124
|
+
|
|
125
|
+
def get_last_namespace(self) -> str | None:
|
|
126
|
+
"""
|
|
127
|
+
Get the last used Kubernetes namespace.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
str or None
|
|
132
|
+
The last used Kubernetes namespace, or None if not set.
|
|
133
|
+
"""
|
|
134
|
+
self._reload_cache_lazy()
|
|
135
|
+
return self._cached_config.get("kube", {}).get("last_namespace")
|
|
136
|
+
|
|
137
|
+
def set_last_namespace(self, namespace: str) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Set the Kubernetes namespace.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
namespace : str
|
|
144
|
+
The Kubernetes namespace to set.
|
|
145
|
+
"""
|
|
146
|
+
config = self._load_config()
|
|
147
|
+
if "kube" not in config:
|
|
148
|
+
config["kube"] = {}
|
|
149
|
+
|
|
150
|
+
if config["kube"].get("last_namespace") != namespace:
|
|
151
|
+
config["kube"]["last_namespace"] = namespace
|
|
152
|
+
self._save_config(config)
|
|
153
|
+
self._reload_cache_lazy()
|
|
154
|
+
|
|
155
|
+
def remove_kube(self) -> None:
|
|
156
|
+
"""
|
|
157
|
+
Remove the last used context and namespace.
|
|
158
|
+
"""
|
|
159
|
+
if self.config_path.exists():
|
|
160
|
+
config = self._load_config()
|
|
161
|
+
if "kube" in config:
|
|
162
|
+
del config["kube"]
|
|
163
|
+
self._save_config(config)
|
|
164
|
+
self._reload_cache_lazy()
|
|
165
|
+
|
|
166
|
+
def get_active_settings(
|
|
167
|
+
self,
|
|
168
|
+
context: str | None,
|
|
169
|
+
namespace: str | None,
|
|
170
|
+
) -> tuple[str, str]:
|
|
171
|
+
"""
|
|
172
|
+
Get the active Kubernetes context and namespace.
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
context : str or None
|
|
177
|
+
The Kubernetes context to use.
|
|
178
|
+
namespace : str or None
|
|
179
|
+
The Kubernetes namespace to use.
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
tuple[str, str]
|
|
184
|
+
A tuple containing the active context and namespace.
|
|
185
|
+
"""
|
|
186
|
+
if not context:
|
|
187
|
+
_, active_context = config.list_kube_config_contexts()
|
|
188
|
+
context = active_context["name"]
|
|
189
|
+
|
|
190
|
+
if not namespace:
|
|
191
|
+
namespace = active_context["context"].get("namespace", "default")
|
|
192
|
+
|
|
193
|
+
return context, namespace
|
|
194
|
+
|
|
195
|
+
def compare_changes_config(
|
|
196
|
+
self,
|
|
197
|
+
context: str | None = None,
|
|
198
|
+
namespace: str | None = None,
|
|
199
|
+
) -> tuple[str, str]:
|
|
200
|
+
"""
|
|
201
|
+
Compare active settings with last used settings.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
context : str or None, optional
|
|
206
|
+
The Kubernetes context to use.
|
|
207
|
+
namespace : str or None, optional
|
|
208
|
+
The Kubernetes namespace to use.
|
|
209
|
+
|
|
210
|
+
Returns
|
|
211
|
+
-------
|
|
212
|
+
tuple[str, str]
|
|
213
|
+
A tuple containing the active context and namespace.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
active_context, active_namespace = self.get_active_settings(context, namespace)
|
|
217
|
+
last_context = self.get_last_context()
|
|
218
|
+
last_namespace = self.get_last_namespace()
|
|
219
|
+
|
|
220
|
+
# compare context
|
|
221
|
+
if not last_context:
|
|
222
|
+
self.set_last_context(context=active_context)
|
|
223
|
+
elif last_context != active_context:
|
|
224
|
+
warning("Are you using the correct context?")
|
|
225
|
+
warning(f"Current context: {Fore.YELLOW}{active_context}{Style.RESET_ALL}")
|
|
226
|
+
warning(f"Last context: {Fore.YELLOW}{last_context}{Style.RESET_ALL}")
|
|
227
|
+
|
|
228
|
+
active_context = questionary.select(
|
|
229
|
+
"Which context do you want to use?",
|
|
230
|
+
choices=[active_context, last_context],
|
|
231
|
+
default=active_context,
|
|
232
|
+
).ask()
|
|
233
|
+
|
|
234
|
+
if last_context != active_context:
|
|
235
|
+
self.set_last_context(context=active_context)
|
|
236
|
+
|
|
237
|
+
# compare namespace
|
|
238
|
+
if not last_namespace:
|
|
239
|
+
self.set_last_namespace(namespace=active_namespace)
|
|
240
|
+
elif last_namespace != active_namespace:
|
|
241
|
+
warning("Are you using the correct namespace?")
|
|
242
|
+
warning(
|
|
243
|
+
f"Current namespace: {Fore.YELLOW}{active_namespace}{Style.RESET_ALL}"
|
|
244
|
+
)
|
|
245
|
+
warning(
|
|
246
|
+
f"Last namespace: {Fore.YELLOW}{last_namespace}{Style.RESET_ALL}"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
active_namespace = questionary.select(
|
|
250
|
+
"Which namespace do you want to use?",
|
|
251
|
+
choices=[active_namespace, last_namespace],
|
|
252
|
+
default=active_namespace,
|
|
253
|
+
).ask()
|
|
254
|
+
|
|
255
|
+
if last_namespace != active_namespace:
|
|
256
|
+
self.set_last_namespace(namespace=active_namespace)
|
|
257
|
+
|
|
258
|
+
info(f"Using context: {Fore.YELLOW}{active_context}{Style.RESET_ALL}")
|
|
259
|
+
info(f"Using namespace: {Fore.YELLOW}{active_namespace}{Style.RESET_ALL}")
|
|
260
|
+
return active_context, active_namespace
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Self
|
|
2
|
+
|
|
3
|
+
from schema import And, Optional, Or, Use
|
|
2
4
|
|
|
3
5
|
from vantage6.common.configuration_manager import Configuration, ConfigurationManager
|
|
4
6
|
|
|
@@ -20,17 +22,8 @@ class ServerConfiguration(Configuration):
|
|
|
20
22
|
validators.
|
|
21
23
|
"""
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"ip": Use(str),
|
|
26
|
-
"port": Use(int),
|
|
27
|
-
Optional("api_path"): str,
|
|
28
|
-
"uri": Use(str),
|
|
29
|
-
"allow_drop_all": Use(bool),
|
|
30
|
-
"logging": {**LOGGING_VALIDATORS, "file": Use(str)},
|
|
31
|
-
Optional("server_name"): str,
|
|
32
|
-
Optional("runs_data_cleanup_days"): Use(int),
|
|
33
|
-
}
|
|
25
|
+
# TODO: explore how to validate helm values.yaml files, see issue 2105
|
|
26
|
+
VALIDATORS = {}
|
|
34
27
|
|
|
35
28
|
|
|
36
29
|
class NodeConfiguration(Configuration):
|
|
@@ -50,6 +43,7 @@ class NodeConfiguration(Configuration):
|
|
|
50
43
|
Optional("node_extra_env"): dict,
|
|
51
44
|
Optional("node_extra_mounts"): [str],
|
|
52
45
|
Optional("node_extra_hosts"): dict,
|
|
46
|
+
Optional("share_algorithm_logs"): Use(bool),
|
|
53
47
|
}
|
|
54
48
|
|
|
55
49
|
|
|
@@ -71,7 +65,7 @@ class NodeConfigurationManager(ConfigurationManager):
|
|
|
71
65
|
super().__init__(conf_class=NodeConfiguration, name=name)
|
|
72
66
|
|
|
73
67
|
@classmethod
|
|
74
|
-
def from_file(cls, path: str) ->
|
|
68
|
+
def from_file(cls, path: str) -> Self:
|
|
75
69
|
"""
|
|
76
70
|
Create a new instance of the NodeConfigurationManager from a
|
|
77
71
|
configuration file.
|
|
@@ -103,7 +97,7 @@ class ServerConfigurationManager(ConfigurationManager):
|
|
|
103
97
|
super().__init__(conf_class=ServerConfiguration, name=name)
|
|
104
98
|
|
|
105
99
|
@classmethod
|
|
106
|
-
def from_file(cls, path) ->
|
|
100
|
+
def from_file(cls, path) -> Self:
|
|
107
101
|
"""
|
|
108
102
|
Create a new instance of the ServerConfigurationManager from a
|
|
109
103
|
configuration file.
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
3
4
|
|
|
4
5
|
import questionary as q
|
|
5
6
|
|
|
6
|
-
from vantage6.common import
|
|
7
|
+
from vantage6.common import error, info, warning
|
|
8
|
+
from vantage6.common.client.node_client import NodeClient
|
|
9
|
+
from vantage6.common.context import AppContext
|
|
7
10
|
from vantage6.common.globals import (
|
|
8
11
|
DATABASE_TYPES,
|
|
12
|
+
DEFAULT_API_PATH,
|
|
9
13
|
InstanceType,
|
|
10
14
|
NodePolicy,
|
|
11
15
|
Ports,
|
|
12
|
-
DEFAULT_API_PATH,
|
|
13
16
|
RequiredNodeEnvVars,
|
|
14
17
|
)
|
|
15
|
-
|
|
16
|
-
from vantage6.
|
|
17
|
-
from vantage6.common import error, warning, info
|
|
18
|
-
from vantage6.cli.context import select_context_class
|
|
18
|
+
|
|
19
|
+
from vantage6.cli.config import CliConfig
|
|
19
20
|
from vantage6.cli.configuration_manager import (
|
|
20
21
|
NodeConfigurationManager,
|
|
21
22
|
ServerConfigurationManager,
|
|
22
23
|
)
|
|
24
|
+
from vantage6.cli.context import select_context_class
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
@@ -54,9 +56,9 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
54
56
|
|
|
55
57
|
# set default port to the https port if server_url is https
|
|
56
58
|
default_port = (
|
|
57
|
-
str(Ports.HTTPS
|
|
59
|
+
str(Ports.HTTPS)
|
|
58
60
|
if config["server_url"].startswith("https")
|
|
59
|
-
else str(Ports.DEV_SERVER
|
|
61
|
+
else str(Ports.DEV_SERVER)
|
|
60
62
|
)
|
|
61
63
|
|
|
62
64
|
config = config | q.unsafe_prompt(
|
|
@@ -182,8 +184,7 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
|
|
|
182
184
|
error(f"Could not authenticate with server: {e}")
|
|
183
185
|
error("Please check (1) your API key and (2) if your server is online")
|
|
184
186
|
warning(
|
|
185
|
-
"If you continue, you should provide your collaboration "
|
|
186
|
-
"settings manually."
|
|
187
|
+
"If you continue, you should provide your collaboration settings manually."
|
|
187
188
|
)
|
|
188
189
|
if q.confirm("Do you want to abort?", default=True).unsafe_ask():
|
|
189
190
|
exit(0)
|
|
@@ -312,10 +313,9 @@ def _get_common_server_config(instance_type: InstanceType, instance_name: str) -
|
|
|
312
313
|
"name": "port",
|
|
313
314
|
"message": "Enter port to which the server listens:",
|
|
314
315
|
"default": (
|
|
315
|
-
|
|
316
|
-
str(Ports.DEV_SERVER.value)
|
|
316
|
+
str(Ports.DEV_SERVER)
|
|
317
317
|
if instance_type == InstanceType.SERVER
|
|
318
|
-
else str(Ports.DEV_ALGO_STORE
|
|
318
|
+
else str(Ports.DEV_ALGO_STORE)
|
|
319
319
|
),
|
|
320
320
|
},
|
|
321
321
|
]
|
|
@@ -368,115 +368,69 @@ def _get_common_server_config(instance_type: InstanceType, instance_name: str) -
|
|
|
368
368
|
return config
|
|
369
369
|
|
|
370
370
|
|
|
371
|
-
def server_configuration_questionaire(
|
|
371
|
+
def server_configuration_questionaire(
|
|
372
|
+
instance_name: str,
|
|
373
|
+
) -> dict[str, Any]:
|
|
372
374
|
"""
|
|
373
|
-
|
|
375
|
+
Kubernetes-specific questionnaire to generate Helm values for server.
|
|
374
376
|
|
|
375
377
|
Parameters
|
|
376
378
|
----------
|
|
377
379
|
instance_name : str
|
|
378
|
-
Name of the server instance
|
|
380
|
+
Name of the server instance
|
|
379
381
|
|
|
380
382
|
Returns
|
|
381
383
|
-------
|
|
382
|
-
dict
|
|
383
|
-
|
|
384
|
+
dict[str, Any]
|
|
385
|
+
dictionary with Helm values for the server configuration
|
|
384
386
|
"""
|
|
387
|
+
# Get active kube namespace
|
|
388
|
+
cli_config = CliConfig()
|
|
389
|
+
kube_namespace = cli_config.get_last_namespace()
|
|
385
390
|
|
|
386
|
-
config
|
|
391
|
+
# Initialize config with basic structure
|
|
392
|
+
config = {"server": {}, "database": {}, "ui": {}}
|
|
387
393
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if is_mfa:
|
|
394
|
-
config["two_factor_auth"] = is_mfa
|
|
394
|
+
# === Server settings ===
|
|
395
|
+
config["server"]["description"] = q.text(
|
|
396
|
+
"Enter a human-readable description:",
|
|
397
|
+
default=f"Vantage6 server {instance_name}",
|
|
398
|
+
).unsafe_ask()
|
|
395
399
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
"
|
|
399
|
-
" development server running locally, this is the same as the "
|
|
400
|
-
"server url. If you are running a production server, this is the "
|
|
401
|
-
"url that users will connect to.",
|
|
402
|
-
default=current_server_url,
|
|
400
|
+
config["server"]["image"] = q.text(
|
|
401
|
+
"Server Docker image:",
|
|
402
|
+
default="harbor2.vantage6.ai/infrastructure/server:latest",
|
|
403
403
|
).unsafe_ask()
|
|
404
404
|
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
# === UI settings ===
|
|
406
|
+
config["ui"]["image"] = q.text(
|
|
407
|
+
"UI Docker image:",
|
|
408
|
+
default="harbor2.vantage6.ai/infrastructure/ui:latest",
|
|
407
409
|
).unsafe_ask()
|
|
408
|
-
if is_add_vpn:
|
|
409
|
-
vpn_config = q.unsafe_prompt(
|
|
410
|
-
[
|
|
411
|
-
{
|
|
412
|
-
"type": "text",
|
|
413
|
-
"name": "url",
|
|
414
|
-
"message": "VPN server URL:",
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
"type": "text",
|
|
418
|
-
"name": "portal_username",
|
|
419
|
-
"message": "VPN portal username:",
|
|
420
|
-
},
|
|
421
|
-
{
|
|
422
|
-
"type": "password",
|
|
423
|
-
"name": "portal_userpass",
|
|
424
|
-
"message": "VPN portal password:",
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
"type": "text",
|
|
428
|
-
"name": "client_id",
|
|
429
|
-
"message": "VPN client username:",
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
"type": "password",
|
|
433
|
-
"name": "client_secret",
|
|
434
|
-
"message": "VPN client password:",
|
|
435
|
-
},
|
|
436
|
-
{
|
|
437
|
-
"type": "text",
|
|
438
|
-
"name": "redirect_url",
|
|
439
|
-
"message": "Redirect url (should be local address of server)",
|
|
440
|
-
"default": "http://localhost",
|
|
441
|
-
},
|
|
442
|
-
]
|
|
443
|
-
)
|
|
444
|
-
config["vpn_server"] = vpn_config
|
|
445
410
|
|
|
446
|
-
|
|
447
|
-
|
|
411
|
+
# === Database settings ===
|
|
412
|
+
config["database"]["volumePath"] = q.text(
|
|
413
|
+
"Where is your server database located on the host machine?",
|
|
414
|
+
default=f"{Path.cwd()}/dev/.db/db_pv_server",
|
|
448
415
|
).unsafe_ask()
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
).unsafe_ask()
|
|
454
|
-
config["rabbitmq"] = {
|
|
455
|
-
"uri": rabbit_uri,
|
|
456
|
-
"start_with_server": run_rabbit_locally,
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
# add algorithm stores to this server
|
|
460
|
-
is_add_community_store = q.confirm(
|
|
461
|
-
"Do you want to make the algorithms from the community algorithm store "
|
|
462
|
-
"available to your users?"
|
|
416
|
+
|
|
417
|
+
config["database"]["k8sNodeName"] = q.text(
|
|
418
|
+
"What is the name of the k8s node where the databases are running?",
|
|
419
|
+
default="docker-desktop",
|
|
463
420
|
).unsafe_ask()
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
421
|
+
|
|
422
|
+
# === Keycloak settings ===
|
|
423
|
+
keycloak_url = f"http://vantage6-auth-keycloak.{kube_namespace}.svc.cluster.local"
|
|
424
|
+
config["server"]["keycloakUrl"] = keycloak_url
|
|
425
|
+
|
|
426
|
+
# === Other settings ===
|
|
427
|
+
log_level = q.select(
|
|
428
|
+
"Which level of logging would you like?",
|
|
429
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
430
|
+
default="INFO",
|
|
471
431
|
).unsafe_ask()
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
store_url = q.text(message="Enter the URL of the store:").unsafe_ask()
|
|
475
|
-
algorithm_stores.append({"name": store_name, "url": store_url})
|
|
476
|
-
add_more_stores = q.confirm(
|
|
477
|
-
"Do you want to add more algorithm stores?", default=False
|
|
478
|
-
).unsafe_ask()
|
|
479
|
-
config["algorithm_stores"] = algorithm_stores
|
|
432
|
+
|
|
433
|
+
config["server"]["logging"] = {"level": log_level}
|
|
480
434
|
|
|
481
435
|
return config
|
|
482
436
|
|
|
@@ -498,9 +452,7 @@ def algo_store_configuration_questionaire(instance_name: str) -> dict:
|
|
|
498
452
|
"""
|
|
499
453
|
config = _get_common_server_config(InstanceType.ALGORITHM_STORE, instance_name)
|
|
500
454
|
|
|
501
|
-
default_v6_server_uri =
|
|
502
|
-
f"http://localhost:{Ports.DEV_SERVER.value}{DEFAULT_API_PATH}"
|
|
503
|
-
)
|
|
455
|
+
default_v6_server_uri = f"http://localhost:{Ports.DEV_SERVER}{DEFAULT_API_PATH}"
|
|
504
456
|
default_root_username = "admin"
|
|
505
457
|
|
|
506
458
|
v6_server_uri = q.text(
|
|
@@ -520,7 +472,6 @@ def algo_store_configuration_questionaire(instance_name: str) -> dict:
|
|
|
520
472
|
}
|
|
521
473
|
|
|
522
474
|
# ask about openness of the algorithm store
|
|
523
|
-
config["policies"] = {"allow_localhost": False}
|
|
524
475
|
is_open = q.confirm(
|
|
525
476
|
"Do you want to open the algorithm store to the public? This will allow anyone "
|
|
526
477
|
"to view the algorithms, but they cannot modify them.",
|
|
@@ -530,19 +481,21 @@ def algo_store_configuration_questionaire(instance_name: str) -> dict:
|
|
|
530
481
|
open_algos_policy = "public"
|
|
531
482
|
else:
|
|
532
483
|
is_open_to_whitelist = q.confirm(
|
|
533
|
-
"Do you want to allow all users
|
|
484
|
+
"Do you want to allow all authenticated users to access "
|
|
534
485
|
"the algorithms in the store? If not allowing this, you will have to assign"
|
|
535
486
|
" the appropriate permissions to each user individually.",
|
|
536
487
|
default=True,
|
|
537
488
|
).unsafe_ask()
|
|
538
|
-
open_algos_policy = "
|
|
489
|
+
open_algos_policy = "authenticated" if is_open_to_whitelist else "private"
|
|
539
490
|
config["policies"]["algorithm_view"] = open_algos_policy
|
|
540
491
|
|
|
541
492
|
return config
|
|
542
493
|
|
|
543
494
|
|
|
544
495
|
def configuration_wizard(
|
|
545
|
-
type_: InstanceType,
|
|
496
|
+
type_: InstanceType,
|
|
497
|
+
instance_name: str,
|
|
498
|
+
system_folders: bool,
|
|
546
499
|
) -> Path:
|
|
547
500
|
"""
|
|
548
501
|
Create a configuration file for a node or server instance.
|
|
@@ -570,7 +523,9 @@ def configuration_wizard(
|
|
|
570
523
|
config = node_configuration_questionaire(dirs, instance_name)
|
|
571
524
|
elif type_ == InstanceType.SERVER:
|
|
572
525
|
conf_manager = ServerConfigurationManager
|
|
573
|
-
config = server_configuration_questionaire(
|
|
526
|
+
config = server_configuration_questionaire(
|
|
527
|
+
instance_name=instance_name,
|
|
528
|
+
)
|
|
574
529
|
else:
|
|
575
530
|
conf_manager = ServerConfigurationManager
|
|
576
531
|
config = algo_store_configuration_questionaire(instance_name)
|
vantage6/cli/context/__init__.py
CHANGED
|
@@ -10,8 +10,9 @@ more.
|
|
|
10
10
|
|
|
11
11
|
from colorama import Fore, Style
|
|
12
12
|
|
|
13
|
-
from vantage6.common.globals import InstanceType
|
|
14
13
|
from vantage6.common import error
|
|
14
|
+
from vantage6.common.globals import InstanceType
|
|
15
|
+
|
|
15
16
|
from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
|
|
16
17
|
from vantage6.cli.context.node import NodeContext
|
|
17
18
|
from vantage6.cli.context.server import ServerContext
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from vantage6.common.globals import APPNAME, InstanceType
|
|
4
|
+
|
|
5
|
+
from vantage6.cli._version import __version__
|
|
4
6
|
from vantage6.cli.configuration_manager import ServerConfigurationManager
|
|
7
|
+
from vantage6.cli.context.base_server import BaseServerContext
|
|
5
8
|
from vantage6.cli.globals import (
|
|
6
9
|
DEFAULT_SERVER_SYSTEM_FOLDERS as S_FOL,
|
|
7
|
-
ServerType,
|
|
8
10
|
AlgoStoreGlobals,
|
|
11
|
+
ServerType,
|
|
9
12
|
)
|
|
10
|
-
from vantage6.cli._version import __version__
|
|
11
|
-
from vantage6.cli.context.base_server import BaseServerContext
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class AlgorithmStoreContext(BaseServerContext):
|
|
@@ -28,7 +29,9 @@ class AlgorithmStoreContext(BaseServerContext):
|
|
|
28
29
|
|
|
29
30
|
def __init__(self, instance_name: str, system_folders: bool = S_FOL):
|
|
30
31
|
super().__init__(
|
|
31
|
-
InstanceType.ALGORITHM_STORE,
|
|
32
|
+
InstanceType.ALGORITHM_STORE,
|
|
33
|
+
instance_name,
|
|
34
|
+
system_folders=system_folders,
|
|
32
35
|
)
|
|
33
36
|
self.log.info("vantage6 version '%s'", __version__)
|
|
34
37
|
|
|
@@ -41,7 +44,7 @@ class AlgorithmStoreContext(BaseServerContext):
|
|
|
41
44
|
str
|
|
42
45
|
string representation of the database uri
|
|
43
46
|
"""
|
|
44
|
-
return super().get_database_uri(AlgoStoreGlobals.DB_URI_ENV_VAR)
|
|
47
|
+
return super().get_database_uri(AlgoStoreGlobals.DB_URI_ENV_VAR.value)
|
|
45
48
|
|
|
46
49
|
@property
|
|
47
50
|
def docker_container_name(self) -> str:
|
|
@@ -53,7 +56,7 @@ class AlgorithmStoreContext(BaseServerContext):
|
|
|
53
56
|
str
|
|
54
57
|
Server's docker container name
|
|
55
58
|
"""
|
|
56
|
-
return f"{APPNAME}-{self.name}-{self.scope}-{ServerType.ALGORITHM_STORE
|
|
59
|
+
return f"{APPNAME}-{self.name}-{self.scope}-{ServerType.ALGORITHM_STORE}"
|
|
57
60
|
|
|
58
61
|
@classmethod
|
|
59
62
|
def from_external_config_file(
|
|
@@ -79,7 +82,7 @@ class AlgorithmStoreContext(BaseServerContext):
|
|
|
79
82
|
return super().from_external_config_file(
|
|
80
83
|
path,
|
|
81
84
|
ServerType.ALGORITHM_STORE,
|
|
82
|
-
AlgoStoreGlobals.CONFIG_NAME_ENV_VAR,
|
|
85
|
+
AlgoStoreGlobals.CONFIG_NAME_ENV_VAR.value,
|
|
83
86
|
system_folders,
|
|
84
87
|
)
|
|
85
88
|
|