vantage6 5.0.0a36__py3-none-any.whl → 5.0.0a38__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.

Files changed (80) hide show
  1. vantage6/cli/algorithm/generate_algorithm_json.py +0 -1
  2. vantage6/cli/algostore/attach.py +28 -3
  3. vantage6/cli/algostore/list.py +2 -2
  4. vantage6/cli/algostore/new.py +3 -2
  5. vantage6/cli/algostore/start.py +25 -6
  6. vantage6/cli/algostore/stop.py +3 -0
  7. vantage6/cli/algostore/version.py +62 -0
  8. vantage6/cli/auth/attach.py +1 -1
  9. vantage6/cli/auth/list.py +2 -2
  10. vantage6/cli/auth/new.py +3 -2
  11. vantage6/cli/auth/remove.py +58 -0
  12. vantage6/cli/auth/start.py +27 -9
  13. vantage6/cli/auth/stop.py +3 -0
  14. vantage6/cli/cli.py +21 -0
  15. vantage6/cli/common/attach.py +114 -0
  16. vantage6/cli/common/decorator.py +25 -4
  17. vantage6/cli/common/list.py +68 -0
  18. vantage6/cli/common/new.py +27 -7
  19. vantage6/cli/common/remove.py +18 -0
  20. vantage6/cli/common/start.py +48 -40
  21. vantage6/cli/common/stop.py +16 -4
  22. vantage6/cli/common/utils.py +65 -74
  23. vantage6/cli/common/version.py +82 -0
  24. vantage6/cli/config.py +10 -2
  25. vantage6/cli/{configuration_wizard.py → configuration_create.py} +22 -14
  26. vantage6/cli/configuration_manager.py +70 -21
  27. vantage6/cli/context/__init__.py +10 -5
  28. vantage6/cli/context/algorithm_store.py +13 -7
  29. vantage6/cli/context/auth.py +23 -5
  30. vantage6/cli/context/node.py +25 -8
  31. vantage6/cli/context/server.py +18 -6
  32. vantage6/cli/globals.py +1 -0
  33. vantage6/cli/node/attach.py +27 -3
  34. vantage6/cli/node/common/__init__.py +26 -10
  35. vantage6/cli/node/common/task_cleanup.py +153 -0
  36. vantage6/cli/node/list.py +3 -44
  37. vantage6/cli/node/new.py +13 -6
  38. vantage6/cli/node/set_api_key.py +1 -1
  39. vantage6/cli/node/start.py +30 -7
  40. vantage6/cli/node/stop.py +151 -7
  41. vantage6/cli/node/version.py +96 -33
  42. vantage6/cli/sandbox/config/base.py +109 -0
  43. vantage6/cli/sandbox/config/core.py +300 -0
  44. vantage6/cli/sandbox/config/node.py +311 -0
  45. vantage6/cli/sandbox/data/km_dataset.csv +2401 -0
  46. vantage6/cli/sandbox/data/olympic_athletes_2016.csv +2425 -0
  47. vantage6/cli/sandbox/new.py +207 -0
  48. vantage6/cli/sandbox/populate/__init__.py +173 -0
  49. vantage6/cli/sandbox/populate/helpers/connect_store.py +203 -0
  50. vantage6/cli/sandbox/populate/helpers/delete_fixtures.py +67 -0
  51. vantage6/cli/sandbox/populate/helpers/load_fixtures.py +476 -0
  52. vantage6/cli/sandbox/populate/helpers/utils.py +35 -0
  53. vantage6/cli/sandbox/remove.py +155 -0
  54. vantage6/cli/sandbox/start.py +349 -0
  55. vantage6/cli/sandbox/stop.py +106 -0
  56. vantage6/cli/server/attach.py +28 -3
  57. vantage6/cli/server/common/__init__.py +5 -6
  58. vantage6/cli/server/import_.py +137 -119
  59. vantage6/cli/server/list.py +2 -2
  60. vantage6/cli/server/new.py +5 -3
  61. vantage6/cli/server/start.py +21 -4
  62. vantage6/cli/server/stop.py +2 -0
  63. vantage6/cli/server/version.py +31 -18
  64. vantage6/cli/template/algo_store_config.j2 +3 -0
  65. vantage6/cli/template/auth_config.j2 +24 -1
  66. vantage6/cli/template/node_config.j2 +2 -0
  67. vantage6/cli/template/server_config.j2 +10 -7
  68. vantage6/cli/use/context.py +8 -1
  69. vantage6/cli/use/namespace.py +10 -7
  70. vantage6/cli/utils.py +33 -1
  71. vantage6/cli/utils_kubernetes.py +270 -0
  72. {vantage6-5.0.0a36.dist-info → vantage6-5.0.0a38.dist-info}/METADATA +4 -4
  73. vantage6-5.0.0a38.dist-info/RECORD +102 -0
  74. vantage6/cli/rabbitmq/__init__.py +0 -0
  75. vantage6/cli/rabbitmq/definitions.py +0 -26
  76. vantage6/cli/rabbitmq/queue_manager.py +0 -220
  77. vantage6/cli/rabbitmq/rabbitmq.config +0 -8
  78. vantage6-5.0.0a36.dist-info/RECORD +0 -86
  79. {vantage6-5.0.0a36.dist-info → vantage6-5.0.0a38.dist-info}/WHEEL +0 -0
  80. {vantage6-5.0.0a36.dist-info → vantage6-5.0.0a38.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,300 @@
1
+ from pathlib import Path
2
+
3
+ from vantage6.common.globals import HTTP_LOCALHOST, InstanceType, Ports
4
+
5
+ from vantage6.cli.common.new import new
6
+ from vantage6.cli.sandbox.config.base import BaseSandboxConfigManager
7
+
8
+
9
+ class CoreSandboxConfigManager(BaseSandboxConfigManager):
10
+ """
11
+ Class to store the sandbox configurations.
12
+
13
+ Parameters
14
+ ----------
15
+ server_name : str
16
+ Name of the server.
17
+ server_port : int
18
+ Port of the server.
19
+ ui_port : int
20
+ Port of the UI.
21
+ algorithm_store_port : int
22
+ Port of the algorithm store.
23
+ server_image : str | None
24
+ Image of the server.
25
+ store_image : str | None
26
+ Image of the algorithm store.
27
+ ui_image : str | None
28
+ Image of the UI.
29
+ extra_server_config : Path | None
30
+ Path to the extra server configuration file.
31
+ extra_store_config : Path | None
32
+ Path to the extra algorithm store configuration file.
33
+ context : str | None
34
+ Kubernetes context.
35
+ namespace : str | None
36
+ Kubernetes namespace.
37
+ k8s_node_name : str
38
+ Kubernetes node name.
39
+ custom_data_dir : Path | None
40
+ Path to the custom data directory. Useful on WSL because of mount issues for
41
+ default directories.
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ server_name: str,
47
+ server_port: int,
48
+ ui_port: int,
49
+ algorithm_store_port: int,
50
+ server_image: str | None,
51
+ store_image: str | None,
52
+ ui_image: str | None,
53
+ extra_server_config: Path | None,
54
+ extra_store_config: Path | None,
55
+ extra_auth_config: Path | None,
56
+ context: str,
57
+ namespace: str,
58
+ k8s_node_name: str,
59
+ custom_data_dir: Path | None = None,
60
+ ) -> None:
61
+ super().__init__(server_name, custom_data_dir)
62
+
63
+ self.server_port = server_port
64
+ self.ui_port = ui_port
65
+ self.algorithm_store_port = algorithm_store_port
66
+ self.server_image = server_image
67
+ self.store_image = store_image
68
+ self.ui_image = ui_image
69
+ self.extra_server_config = extra_server_config
70
+ self.extra_store_config = extra_store_config
71
+ self.extra_auth_config = extra_auth_config
72
+ self.context = context
73
+ self.namespace = namespace
74
+
75
+ self.server_config_file = None
76
+ self.store_config_file = None
77
+ self.auth_config_file = None
78
+ self.k8s_node_name = k8s_node_name
79
+
80
+ def generate_server_configs(self) -> None:
81
+ """Generates the demo network."""
82
+
83
+ self._create_auth_config()
84
+
85
+ self._create_vserver_config()
86
+
87
+ self._create_algo_store_config()
88
+
89
+ def __server_config_return_func(self, extra_config: dict, data_dir: Path) -> dict:
90
+ """
91
+ Return a dict with server configuration values to be used in creating the
92
+ config file.
93
+
94
+ Parameters
95
+ ----------
96
+ extra_config : dict
97
+ Extra configuration (parsed from YAML) to be added to the server
98
+ configuration.
99
+ data_dir : Path
100
+ Path to the data directory.
101
+
102
+ Returns
103
+ -------
104
+ dict
105
+ Dictionary with server configuration values.
106
+ """
107
+ store_service = (
108
+ f"vantage6-{self.server_name}-store-user-algorithm-store-store-service"
109
+ )
110
+ store_address = (
111
+ f"http://{store_service}.{self.namespace}.svc.cluster.local:"
112
+ f"{Ports.DEV_ALGO_STORE}"
113
+ )
114
+ config = {
115
+ "server": {
116
+ "baseUrl": f"{HTTP_LOCALHOST}:{self.server_port}",
117
+ # TODO: v5+ set to latest v5 image
118
+ # TODO make this configurable
119
+ "image": (
120
+ self.server_image
121
+ or "harbor2.vantage6.ai/infrastructure/server:5.0.0a37"
122
+ ),
123
+ "algorithm_stores": [
124
+ {
125
+ "name": "Local store",
126
+ "url": store_address,
127
+ "api_path": "/store",
128
+ }
129
+ ],
130
+ "logging": {
131
+ "level": "DEBUG",
132
+ },
133
+ "jwt": {
134
+ "secret": "development-constant-secret!",
135
+ },
136
+ "dev": {
137
+ "host_uri": (
138
+ "host.docker.internal"
139
+ if self.k8s_node_name == "docker-desktop"
140
+ else "172.17.0.1"
141
+ ),
142
+ "store_address": store_address,
143
+ },
144
+ "keycloakUrl": (
145
+ f"http://vantage6-{self.server_name}-auth-user-auth-keycloak."
146
+ f"{self.namespace}.svc.cluster.local"
147
+ ),
148
+ },
149
+ "rabbitmq": {},
150
+ "database": {
151
+ "volumePath": str(data_dir),
152
+ "k8sNodeName": self.k8s_node_name,
153
+ },
154
+ "ui": {
155
+ "port": self.ui_port,
156
+ # TODO: v5+ set to latest v5 image
157
+ # TODO: make this configurable
158
+ "image": (
159
+ self.ui_image or "harbor2.vantage6.ai/infrastructure/ui:5.0.0a37"
160
+ ),
161
+ },
162
+ }
163
+
164
+ # merge the extra config with the server config
165
+ if extra_config is not None:
166
+ config.update(extra_config)
167
+
168
+ return config
169
+
170
+ def _create_vserver_config(self) -> None:
171
+ """Creates server configuration file (YAML)."""
172
+
173
+ data_dir = self._create_and_get_data_dir(instance_type=InstanceType.SERVER)
174
+
175
+ extra_config = self._read_extra_config_file(self.extra_server_config)
176
+ if self.ui_image is not None:
177
+ ui_config = extra_config.get("ui", {}) if extra_config is not None else {}
178
+ ui_config["image"] = self.ui_image
179
+ extra_config["ui"] = ui_config
180
+
181
+ # Create the server config file
182
+ self.server_config_file = new(
183
+ config_producing_func=self.__server_config_return_func,
184
+ config_producing_func_args=(extra_config, data_dir),
185
+ name=self.server_name,
186
+ system_folders=False,
187
+ namespace=self.namespace,
188
+ context=self.context,
189
+ type_=InstanceType.SERVER,
190
+ is_sandbox=True,
191
+ )
192
+
193
+ def _create_algo_store_config(self) -> None:
194
+ """Create algorithm store configuration file (YAML)."""
195
+
196
+ extra_config = self._read_extra_config_file(self.extra_store_config)
197
+
198
+ data_dir = self._create_and_get_data_dir(InstanceType.ALGORITHM_STORE)
199
+
200
+ self.store_config_file = new(
201
+ config_producing_func=self.__algo_store_config_return_func,
202
+ config_producing_func_args=(extra_config, data_dir),
203
+ name=f"{self.server_name}-store",
204
+ system_folders=False,
205
+ namespace=self.namespace,
206
+ context=self.context,
207
+ type_=InstanceType.ALGORITHM_STORE,
208
+ is_sandbox=True,
209
+ )
210
+
211
+ def __algo_store_config_return_func(
212
+ self, extra_config: dict, data_dir: Path
213
+ ) -> dict:
214
+ """
215
+ Return a dict with algorithm store configuration values to be used in creating
216
+ the config file.
217
+
218
+ Returns
219
+ -------
220
+ dict
221
+ Dictionary with algorithm store configuration values.
222
+ """
223
+ config = {
224
+ "store": {
225
+ "internal": {
226
+ "port": self.algorithm_store_port,
227
+ },
228
+ "logging": {
229
+ "level": "DEBUG",
230
+ },
231
+ "vantage6ServerUri": f"{HTTP_LOCALHOST}:{self.server_port}",
232
+ "image": (
233
+ self.store_image
234
+ or "harbor2.vantage6.ai/infrastructure/algorithm-store:5.0.0a37"
235
+ ),
236
+ "keycloakUrl": (
237
+ f"http://vantage6-{self.server_name}-auth-user-auth-keycloak."
238
+ f"{self.namespace}.svc.cluster.local"
239
+ ),
240
+ "policies": {
241
+ "allowLocalhost": True,
242
+ "assignReviewOwnAlgorithm": True,
243
+ },
244
+ "dev": {
245
+ "host_uri": (
246
+ "host.docker.internal"
247
+ if self.k8s_node_name == "docker-desktop"
248
+ else "172.17.0.1"
249
+ ),
250
+ "disable_review": True,
251
+ "review_own_algorithm": True,
252
+ },
253
+ },
254
+ "database": {
255
+ "volumePath": str(data_dir),
256
+ "k8sNodeName": self.k8s_node_name,
257
+ },
258
+ }
259
+
260
+ # merge the extra config with the algorithm store config
261
+ if extra_config is not None:
262
+ config.update(extra_config)
263
+
264
+ return config
265
+
266
+ def _create_auth_config(self) -> None:
267
+ """Create auth configuration file (YAML)."""
268
+ self.auth_config_file = new(
269
+ config_producing_func=self.__auth_config_return_func,
270
+ config_producing_func_args=(self.extra_auth_config,),
271
+ name=f"{self.server_name}-auth",
272
+ system_folders=False,
273
+ namespace=self.namespace,
274
+ context=self.context,
275
+ type_=InstanceType.AUTH,
276
+ is_sandbox=True,
277
+ )
278
+
279
+ def __auth_config_return_func(self, extra_config: dict) -> dict:
280
+ """
281
+ Return a dict with auth configuration values to be used in creating the
282
+ config file.
283
+ """
284
+
285
+ config = {
286
+ "keycloak": {
287
+ "production": False,
288
+ "no_password_update_required": True,
289
+ "redirectUris": [
290
+ f"{HTTP_LOCALHOST}:7600",
291
+ f"{HTTP_LOCALHOST}:7681",
292
+ ],
293
+ },
294
+ }
295
+
296
+ # merge the extra config with the auth config
297
+ if extra_config is not None:
298
+ config.update(extra_config)
299
+
300
+ return config
@@ -0,0 +1,311 @@
1
+ from dataclasses import dataclass
2
+ from importlib import resources as impresources
3
+ from pathlib import Path
4
+
5
+ import pandas as pd
6
+ from colorama import Fore, Style
7
+
8
+ from vantage6.common import error, info
9
+ from vantage6.common.globals import InstanceType
10
+
11
+ import vantage6.cli.sandbox.data as node_datafiles_dir
12
+ from vantage6.cli.common.new import new
13
+ from vantage6.cli.context.node import NodeContext
14
+ from vantage6.cli.globals import (
15
+ DefaultDatasets,
16
+ )
17
+ from vantage6.cli.sandbox.config.base import BaseSandboxConfigManager
18
+ from vantage6.cli.sandbox.populate.helpers.utils import replace_wsl_path
19
+
20
+
21
+ @dataclass
22
+ class NodeDataset:
23
+ label: str
24
+ path: Path
25
+
26
+
27
+ class NodeSandboxConfigManager(BaseSandboxConfigManager):
28
+ """
29
+ Class to store the node sandbox configurations.
30
+
31
+ Parameters
32
+ ----------
33
+ server_name : str
34
+ Name of the server.
35
+ api_keys : list[str]
36
+ List of API keys.
37
+ node_names : list[str]
38
+ List of node names.
39
+ server_port : int
40
+ Port of the server.
41
+ node_image : str | None
42
+ Image of the node.
43
+ extra_node_config : Path | None
44
+ Path to the extra node configuration file.
45
+ extra_dataset : NodeDataset | None
46
+ List of tuples with the label and path to the dataset file.
47
+ context : str
48
+ Kubernetes context.
49
+ namespace : str
50
+ Kubernetes namespace.
51
+ k8s_node_name : str
52
+ Kubernetes node name.
53
+ custom_data_dir : Path | None
54
+ Path to the custom data directory. Useful on WSL because of mount issues for
55
+ default directories.
56
+ """
57
+
58
+ def __init__(
59
+ self,
60
+ server_name: str,
61
+ api_keys: list[str],
62
+ node_names: list[str],
63
+ server_port: int,
64
+ node_image: str | None,
65
+ extra_node_config: Path | None,
66
+ extra_dataset: NodeDataset | None,
67
+ context: str,
68
+ namespace: str,
69
+ k8s_node_name: str,
70
+ custom_data_dir: Path | None,
71
+ ) -> None:
72
+ super().__init__(server_name, custom_data_dir)
73
+ self.api_keys = api_keys
74
+ self.node_names = node_names
75
+ self.num_nodes = len(api_keys)
76
+ self.server_port = server_port
77
+ self.node_image = node_image
78
+ self.extra_node_config = extra_node_config
79
+ if extra_dataset:
80
+ self.node_datasets = [extra_dataset]
81
+ else:
82
+ self.node_datasets = []
83
+ self.context = context
84
+ self.namespace = namespace
85
+ self.k8s_node_name = k8s_node_name
86
+
87
+ self.node_configs = []
88
+ self.node_config_files = []
89
+ self.node_config_names = []
90
+ self.extra_config = None
91
+
92
+ def generate_node_configs(self) -> None:
93
+ """
94
+ Generates ``num_nodes`` node configuration files.
95
+ """
96
+ node_data_files = []
97
+ self.extra_config = self._read_extra_config_file(self.extra_node_config)
98
+
99
+ data_directory = impresources.files(node_datafiles_dir)
100
+
101
+ # Add default datasets to the list of dataset provided
102
+ for default_dataset in DefaultDatasets:
103
+ # note that the label is the name of the dataset with the underscores
104
+ # replace with hyphens, to make it valid for k8s
105
+ self.node_datasets.append(
106
+ NodeDataset(
107
+ label=default_dataset.name.lower().replace("_", "-"),
108
+ path=data_directory / default_dataset.value,
109
+ )
110
+ )
111
+
112
+ # Check for duplicate dataset labels
113
+ seen_labels = set()
114
+ duplicates = [
115
+ label
116
+ for label in [dataset.label for dataset in self.node_datasets]
117
+ if (label in seen_labels or seen_labels.add(label))
118
+ ]
119
+
120
+ if len(duplicates) > 0:
121
+ error(
122
+ f"Duplicate dataset labels found: {duplicates}. "
123
+ f"Please make sure all dataset labels are unique."
124
+ )
125
+ exit(1)
126
+
127
+ # create the data files for the nodes and get the path and label for each
128
+ # dataset
129
+ for dataset in self.node_datasets:
130
+ node_data_files.append(self._create_node_data_files(dataset))
131
+
132
+ for idx, api_key in enumerate(self.api_keys):
133
+ config = {
134
+ "org_id": idx + 1,
135
+ "api_key": api_key,
136
+ "node_name": self.node_names[idx],
137
+ }
138
+ config_file = self._create_node_config_file(
139
+ config,
140
+ [files[idx] for files in node_data_files],
141
+ )
142
+ self.node_configs.append(config)
143
+ self.node_config_files.append(config_file)
144
+ info(
145
+ f"Created {Fore.GREEN}{len(self.node_config_files)}{Style.RESET_ALL} node "
146
+ f"configuration(s), attaching them to {Fore.GREEN}{self.server_name}"
147
+ f"{Style.RESET_ALL}."
148
+ )
149
+
150
+ def _create_node_data_files(
151
+ self, node_dataset: NodeDataset
152
+ ) -> list[tuple[str, Path]]:
153
+ """
154
+ Create data files for nodes.
155
+
156
+ Parameters
157
+ ----------
158
+ node_dataset : NodeDataset
159
+ Tuple with the label and path to the dataset file.
160
+
161
+ Returns
162
+ -------
163
+ list[tuple[str, Path]]
164
+ List of tuples with the label and path to the dataset file.
165
+ """
166
+ info(
167
+ f"Creating data files using dataset '{node_dataset.label}' for "
168
+ f"{self.num_nodes} nodes"
169
+ )
170
+ data_files = []
171
+ full_df = pd.read_csv(node_dataset.path)
172
+ length_df = len(full_df)
173
+ for i in range(self.num_nodes):
174
+ node_name = f"{self.server_name}_node_{i + 1}"
175
+ path_to_dev_dir = self._create_and_get_data_dir(
176
+ InstanceType.NODE, is_data_folder=False
177
+ )
178
+
179
+ # Split the data over the nodes
180
+ start = i * length_df // self.num_nodes
181
+ end = (i + 1) * length_df // self.num_nodes
182
+ data = full_df[start:end]
183
+ data_file = (
184
+ replace_wsl_path(path_to_dev_dir, to_mnt_wsl=True)
185
+ / f"df_{node_dataset.label}_{node_name}.csv"
186
+ )
187
+
188
+ # write data to file
189
+ data.to_csv(data_file, index=False)
190
+ data_files.append(
191
+ (node_dataset.label, replace_wsl_path(data_file, to_mnt_wsl=False))
192
+ )
193
+ return data_files
194
+
195
+ def _create_node_config_file(
196
+ self, config: dict, datasets: list[tuple[str, Path]]
197
+ ) -> Path:
198
+ """
199
+ Create a node configuration file (YAML).
200
+
201
+ Parameters
202
+ ----------
203
+ config : dict
204
+ Configuration dictionary.
205
+ datasets : list[tuple[str, Path]]
206
+ List of tuples with the label and path to the dataset file.
207
+
208
+ Returns
209
+ -------
210
+ Path
211
+ Path to the node configuration file.
212
+ """
213
+ node_name = config["node_name"]
214
+ config_name = f"{self.server_name}-{node_name}"
215
+
216
+ path_to_data_dir = self._create_and_get_data_dir(
217
+ InstanceType.NODE, is_data_folder=True, node_name=node_name
218
+ )
219
+
220
+ # delete old node config if it exists
221
+ NodeContext.remove_config_file_if_exists(
222
+ InstanceType.NODE, config_name, False, is_sandbox=True
223
+ )
224
+
225
+ # create new node config
226
+ node_config = new(
227
+ config_producing_func=self.__node_config_return_func,
228
+ config_producing_func_args=(
229
+ config,
230
+ self.extra_config,
231
+ datasets,
232
+ path_to_data_dir,
233
+ ),
234
+ name=config_name,
235
+ system_folders=False,
236
+ namespace=self.namespace,
237
+ context=self.context,
238
+ type_=InstanceType.NODE,
239
+ is_sandbox=True,
240
+ )
241
+
242
+ self.node_config_names.append(config_name)
243
+
244
+ return node_config
245
+
246
+ def __node_config_return_func(
247
+ self,
248
+ node_specific_config: dict,
249
+ extra_config: dict,
250
+ datasets: list[tuple[str, Path]],
251
+ path_to_data_dir: Path,
252
+ ) -> dict:
253
+ """
254
+ Return a dict with node configuration values to be used in creating the
255
+ config file.
256
+ """
257
+ config = {
258
+ "node": {
259
+ "proxyPort": 7676 + int(node_specific_config["org_id"]),
260
+ "apiKey": node_specific_config["api_key"],
261
+ "name": node_specific_config["node_name"],
262
+ "image": (
263
+ self.node_image
264
+ # TODO v5+ update
265
+ or "harbor2.vantage6.ai/infrastructure/node:5.0.0a37"
266
+ ),
267
+ "logging": {
268
+ "level": "DEBUG",
269
+ "file": f"{node_specific_config['node_name']}.log",
270
+ },
271
+ "keycloakUrl": (
272
+ f"http://vantage6-{self.server_name}-auth-user-auth-keycloak."
273
+ f"{self.namespace}.svc.cluster.local"
274
+ ),
275
+ "persistence": {
276
+ "tasks": {
277
+ "hostPath": str(path_to_data_dir),
278
+ "size": "1Gi",
279
+ },
280
+ "database": {
281
+ "size": "1Gi",
282
+ },
283
+ },
284
+ "k8sNodeName": self.k8s_node_name,
285
+ "databases": {
286
+ "fileBased": [
287
+ {
288
+ "name": dataset[0],
289
+ "uri": dataset[1],
290
+ "type": "csv",
291
+ "volumePath": Path(dataset[1]).parent,
292
+ "originalName": dataset[0],
293
+ }
294
+ for dataset in [datasets[0]]
295
+ ]
296
+ },
297
+ "server": {
298
+ "url": (
299
+ f"http://vantage6-{self.server_name}-user-server-"
300
+ f"vantage6-server-service.{self.namespace}.svc.cluster.local"
301
+ ),
302
+ "port": self.server_port,
303
+ },
304
+ },
305
+ }
306
+
307
+ # merge the extra config with the node config
308
+ if extra_config is not None:
309
+ config.update(extra_config)
310
+
311
+ return config