vantage6 5.0.0a35__py3-none-any.whl → 5.0.0a37__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 (84) hide show
  1. vantage6/cli/algorithm/generate_algorithm_json.py +9 -10
  2. vantage6/cli/algorithm/update.py +1 -1
  3. vantage6/cli/algostore/attach.py +1 -0
  4. vantage6/cli/algostore/files.py +3 -2
  5. vantage6/cli/algostore/list.py +0 -3
  6. vantage6/cli/algostore/new.py +3 -2
  7. vantage6/cli/algostore/start.py +14 -3
  8. vantage6/cli/algostore/stop.py +3 -0
  9. vantage6/cli/auth/attach.py +60 -0
  10. vantage6/cli/auth/files.py +16 -0
  11. vantage6/cli/auth/list.py +13 -0
  12. vantage6/cli/auth/new.py +81 -0
  13. vantage6/cli/auth/remove.py +31 -0
  14. vantage6/cli/auth/start.py +94 -0
  15. vantage6/cli/auth/stop.py +67 -0
  16. vantage6/cli/cli.py +56 -5
  17. vantage6/cli/common/decorator.py +24 -5
  18. vantage6/cli/common/new.py +27 -7
  19. vantage6/cli/common/start.py +49 -41
  20. vantage6/cli/common/stop.py +23 -5
  21. vantage6/cli/common/utils.py +25 -0
  22. vantage6/cli/config.py +10 -2
  23. vantage6/cli/{configuration_wizard.py → configuration_create.py} +28 -15
  24. vantage6/cli/configuration_manager.py +97 -17
  25. vantage6/cli/context/__init__.py +10 -5
  26. vantage6/cli/context/algorithm_store.py +11 -5
  27. vantage6/cli/context/auth.py +125 -0
  28. vantage6/cli/context/base_server.py +0 -4
  29. vantage6/cli/context/node.py +25 -8
  30. vantage6/cli/context/server.py +18 -6
  31. vantage6/cli/dev/clean.py +28 -0
  32. vantage6/cli/dev/common.py +34 -0
  33. vantage6/cli/dev/rebuild.py +39 -0
  34. vantage6/cli/dev/start.py +36 -0
  35. vantage6/cli/dev/stop.py +23 -0
  36. vantage6/cli/globals.py +5 -1
  37. vantage6/cli/node/common/__init__.py +26 -10
  38. vantage6/cli/node/list.py +5 -4
  39. vantage6/cli/node/new.py +13 -6
  40. vantage6/cli/node/set_api_key.py +1 -1
  41. vantage6/cli/node/start.py +19 -4
  42. vantage6/cli/node/stop.py +153 -7
  43. vantage6/cli/node/task_cleanup/__init__.py +153 -0
  44. vantage6/cli/node/version.py +5 -4
  45. vantage6/cli/prometheus/monitoring_manager.py +5 -3
  46. vantage6/cli/sandbox/config/base.py +101 -0
  47. vantage6/cli/sandbox/config/core.py +300 -0
  48. vantage6/cli/sandbox/config/node.py +314 -0
  49. vantage6/cli/sandbox/data/olympic_athletes_2016.csv +2425 -0
  50. vantage6/cli/sandbox/new.py +207 -0
  51. vantage6/cli/sandbox/populate/__init__.py +173 -0
  52. vantage6/cli/sandbox/populate/helpers/connect_store.py +203 -0
  53. vantage6/cli/sandbox/populate/helpers/delete_fixtures.py +67 -0
  54. vantage6/cli/sandbox/populate/helpers/load_fixtures.py +476 -0
  55. vantage6/cli/sandbox/populate/helpers/utils.py +35 -0
  56. vantage6/cli/sandbox/remove.py +173 -0
  57. vantage6/cli/sandbox/start.py +341 -0
  58. vantage6/cli/sandbox/stop.py +106 -0
  59. vantage6/cli/server/attach.py +1 -0
  60. vantage6/cli/server/common/__init__.py +6 -33
  61. vantage6/cli/server/import_.py +137 -119
  62. vantage6/cli/server/new.py +22 -7
  63. vantage6/cli/server/start.py +10 -1
  64. vantage6/cli/server/stop.py +2 -0
  65. vantage6/cli/template/auth_config.j2 +253 -0
  66. vantage6/cli/template/node_config.j2 +8 -8
  67. vantage6/cli/template/node_config_nonk8s.j2 +33 -0
  68. vantage6/cli/template/server_config.j2 +10 -7
  69. vantage6/cli/test/common/diagnostic_runner.py +5 -3
  70. vantage6/cli/use/namespace.py +2 -1
  71. vantage6/cli/utils.py +33 -1
  72. {vantage6-5.0.0a35.dist-info → vantage6-5.0.0a37.dist-info}/METADATA +4 -4
  73. vantage6-5.0.0a37.dist-info/RECORD +97 -0
  74. vantage6/cli/dev/create.py +0 -693
  75. vantage6/cli/dev/remove.py +0 -112
  76. vantage6/cli/rabbitmq/__init__.py +0 -0
  77. vantage6/cli/rabbitmq/definitions.py +0 -26
  78. vantage6/cli/rabbitmq/queue_manager.py +0 -218
  79. vantage6/cli/rabbitmq/rabbitmq.config +0 -8
  80. vantage6/cli/server/shell.py +0 -54
  81. vantage6-5.0.0a35.dist-info/RECORD +0 -75
  82. /vantage6/cli/{dev → sandbox}/data/km_dataset.csv +0 -0
  83. {vantage6-5.0.0a35.dist-info → vantage6-5.0.0a37.dist-info}/WHEEL +0 -0
  84. {vantage6-5.0.0a35.dist-info → vantage6-5.0.0a37.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,4 @@
1
+ from pathlib import Path
1
2
  from typing import Self
2
3
 
3
4
  from schema import And, Use
@@ -6,6 +7,7 @@ from vantage6.common.configuration_manager import Configuration, ConfigurationMa
6
7
 
7
8
  from vantage6.cli.globals import (
8
9
  ALGO_STORE_TEMPLATE_FILE,
10
+ AUTH_TEMPLATE_FILE,
9
11
  NODE_TEMPLATE_FILE,
10
12
  SERVER_TEMPLATE_FILE,
11
13
  )
@@ -47,6 +49,8 @@ class NodeConfiguration(Configuration):
47
49
  validators.
48
50
  """
49
51
 
52
+ # TODO perhaps we can remove these classes and do validation of the configuration
53
+ # file more easily with helm values.yaml checks.
50
54
  VALIDATORS = {
51
55
  # # TODO enable validators for node. To see if it works, use v6 node list
52
56
  # "node": {
@@ -65,6 +69,10 @@ class NodeConfiguration(Configuration):
65
69
  }
66
70
 
67
71
 
72
+ class AuthConfiguration(Configuration):
73
+ VALIDATORS = {}
74
+
75
+
68
76
  class TestConfiguration(Configuration):
69
77
  VALIDATORS = {}
70
78
 
@@ -79,18 +87,18 @@ class NodeConfigurationManager(ConfigurationManager):
79
87
  Name of the configuration file.
80
88
  """
81
89
 
82
- def __init__(self, name, *args, **kwargs) -> None:
83
- super().__init__(conf_class=NodeConfiguration, name=name)
90
+ def __init__(self, name: str, is_sandbox: bool = False, *args, **kwargs) -> None:
91
+ super().__init__(conf_class=NodeConfiguration, name=name, is_sandbox=is_sandbox)
84
92
 
85
93
  @classmethod
86
- def from_file(cls, path: str) -> Self:
94
+ def from_file(cls, path: Path | str, is_sandbox: bool = False) -> Self:
87
95
  """
88
96
  Create a new instance of the NodeConfigurationManager from a
89
97
  configuration file.
90
98
 
91
99
  Parameters
92
100
  ----------
93
- path : str
101
+ path : str | Path
94
102
  Path to the configuration file.
95
103
 
96
104
  Returns
@@ -98,7 +106,9 @@ class NodeConfigurationManager(ConfigurationManager):
98
106
  NodeConfigurationManager
99
107
  A new instance of the NodeConfigurationManager.
100
108
  """
101
- return super().from_file(path, conf_class=NodeConfiguration)
109
+ return super().from_file(
110
+ path, conf_class=NodeConfiguration, is_sandbox=is_sandbox
111
+ )
102
112
 
103
113
  def get_config_template(self) -> str:
104
114
  """
@@ -117,18 +127,20 @@ class ServerConfigurationManager(ConfigurationManager):
117
127
  Name of the configuration file.
118
128
  """
119
129
 
120
- def __init__(self, name, *args, **kwargs) -> None:
121
- super().__init__(conf_class=ServerConfiguration, name=name)
130
+ def __init__(self, name: str, is_sandbox: bool = False, *args, **kwargs) -> None:
131
+ super().__init__(
132
+ conf_class=ServerConfiguration, name=name, is_sandbox=is_sandbox
133
+ )
122
134
 
123
135
  @classmethod
124
- def from_file(cls, path) -> Self:
136
+ def from_file(cls, path: Path | str, is_sandbox: bool = False) -> Self:
125
137
  """
126
138
  Create a new instance of the ServerConfigurationManager from a
127
139
  configuration file.
128
140
 
129
141
  Parameters
130
142
  ----------
131
- path : str
143
+ path : str | Path
132
144
  Path to the configuration file.
133
145
 
134
146
  Returns
@@ -136,7 +148,9 @@ class ServerConfigurationManager(ConfigurationManager):
136
148
  ServerConfigurationManager
137
149
  A new instance of the ServerConfigurationManager.
138
150
  """
139
- return super().from_file(path, conf_class=ServerConfiguration)
151
+ return super().from_file(
152
+ path, conf_class=ServerConfiguration, is_sandbox=is_sandbox
153
+ )
140
154
 
141
155
  def get_config_template(self) -> str:
142
156
  """
@@ -160,18 +174,20 @@ class AlgorithmStoreConfigurationManager(ConfigurationManager):
160
174
  Name of the configuration file.
161
175
  """
162
176
 
163
- def __init__(self, name, *args, **kwargs) -> None:
164
- super().__init__(conf_class=AlgorithmStoreConfiguration, name=name)
177
+ def __init__(self, name: str, is_sandbox: bool = False, *args, **kwargs) -> None:
178
+ super().__init__(
179
+ conf_class=AlgorithmStoreConfiguration, name=name, is_sandbox=is_sandbox
180
+ )
165
181
 
166
182
  @classmethod
167
- def from_file(cls, path: str) -> Self:
183
+ def from_file(cls, path: Path | str, is_sandbox: bool = False) -> Self:
168
184
  """
169
185
  Create a new instance of the AlgorithmStoreConfigurationManager from a
170
186
  configuration file.
171
187
 
172
188
  Parameters
173
189
  ----------
174
- path : str
190
+ path : str | Path
175
191
  Path to the configuration file.
176
192
 
177
193
  Returns
@@ -179,7 +195,9 @@ class AlgorithmStoreConfigurationManager(ConfigurationManager):
179
195
  AlgorithmStoreConfigurationManager
180
196
  A new instance of the AlgorithmStoreConfigurationManager.
181
197
  """
182
- return super().from_file(path, conf_class=AlgorithmStoreConfiguration)
198
+ return super().from_file(
199
+ path, conf_class=AlgorithmStoreConfiguration, is_sandbox=is_sandbox
200
+ )
183
201
 
184
202
  def get_config_template(self) -> str:
185
203
  """
@@ -193,10 +211,72 @@ class AlgorithmStoreConfigurationManager(ConfigurationManager):
193
211
  return super()._get_config_template(ALGO_STORE_TEMPLATE_FILE)
194
212
 
195
213
 
214
+ class AuthConfigurationManager(ConfigurationManager):
215
+ """
216
+ Maintains the auth's configuration.
217
+
218
+ Parameters
219
+ ----------
220
+ name : str
221
+ Name of the configuration file.
222
+ is_sandbox : bool, optional
223
+ Whether the configuration is a sandbox configuration, by default False
224
+ """
225
+
226
+ def __init__(self, name, is_sandbox: bool = False, *args, **kwargs):
227
+ super().__init__(conf_class=AuthConfiguration, name=name, is_sandbox=is_sandbox)
228
+
229
+ @classmethod
230
+ def from_file(cls, path: Path | str, is_sandbox: bool = False) -> Self:
231
+ """
232
+ Create a new instance of the AuthConfigurationManager from a
233
+ configuration file.
234
+
235
+ Parameters
236
+ ----------
237
+ path : str | Path
238
+ Path to the configuration file.
239
+ is_sandbox : bool, optional
240
+ Whether the configuration is a sandbox configuration, by default False
241
+
242
+ Returns
243
+ -------
244
+ AuthConfigurationManager
245
+ A new instance of the AuthConfigurationManager.
246
+ """
247
+ return super().from_file(
248
+ path, conf_class=AuthConfiguration, is_sandbox=is_sandbox
249
+ )
250
+
251
+ def get_config_template(self) -> str:
252
+ """
253
+ Get the configuration template for the auth.
254
+ """
255
+ return super()._get_config_template(AUTH_TEMPLATE_FILE)
256
+
257
+
196
258
  class TestingConfigurationManager(ConfigurationManager):
197
259
  def __init__(self, name, *args, **kwargs):
198
260
  super().__init__(conf_class=TestConfiguration, name=name)
199
261
 
200
262
  @classmethod
201
- def from_file(cls, path):
202
- return super().from_file(path, conf_class=TestConfiguration)
263
+ def from_file(cls, path: Path | str, is_sandbox: bool = False) -> Self:
264
+ """
265
+ Create a new instance of the TestingConfigurationManager from a
266
+ configuration file.
267
+
268
+ Parameters
269
+ ----------
270
+ path : str | Path
271
+ Path to the configuration file.
272
+ is_sandbox : bool, optional
273
+ Whether the configuration is a sandbox configuration, by default False
274
+
275
+ Returns
276
+ -------
277
+ TestingConfigurationManager
278
+ A new instance of the TestingConfigurationManager.
279
+ """
280
+ return super().from_file(
281
+ path, conf_class=TestConfiguration, is_sandbox=is_sandbox
282
+ )
@@ -14,13 +14,14 @@ from vantage6.common import error
14
14
  from vantage6.common.globals import InstanceType
15
15
 
16
16
  from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
17
+ from vantage6.cli.context.auth import AuthContext
17
18
  from vantage6.cli.context.node import NodeContext
18
19
  from vantage6.cli.context.server import ServerContext
19
20
 
20
21
 
21
22
  def select_context_class(
22
23
  type_: InstanceType,
23
- ) -> ServerContext | NodeContext | AlgorithmStoreContext:
24
+ ) -> ServerContext | NodeContext | AlgorithmStoreContext | AuthContext:
24
25
  """
25
26
  Select the context class based on the type of instance.
26
27
 
@@ -31,7 +32,7 @@ def select_context_class(
31
32
 
32
33
  Returns
33
34
  -------
34
- ServerContext | NodeContext | AlgorithmStoreContext
35
+ ServerContext | NodeContext | AlgorithmStoreContext | AuthContext
35
36
  Specialized subclass of AppContext for the given instance type
36
37
 
37
38
  Raises
@@ -45,12 +46,14 @@ def select_context_class(
45
46
  return AlgorithmStoreContext
46
47
  elif type_ == InstanceType.NODE:
47
48
  return NodeContext
49
+ elif type_ == InstanceType.AUTH:
50
+ return AuthContext
48
51
  else:
49
52
  raise NotImplementedError
50
53
 
51
54
 
52
55
  def get_context(
53
- type_: InstanceType, name: str, system_folders: bool
56
+ type_: InstanceType, name: str, system_folders: bool, is_sandbox: bool = False
54
57
  ) -> ServerContext | NodeContext | AlgorithmStoreContext:
55
58
  """
56
59
  Load the server context from the configuration file.
@@ -63,6 +66,8 @@ def get_context(
63
66
  Name of the instance
64
67
  system_folders : bool
65
68
  Wether to use system folders or if False, the user folders
69
+ is_sandbox : bool
70
+ Whether the configuration is a sandbox configuration, by default False
66
71
 
67
72
  Returns
68
73
  -------
@@ -70,7 +75,7 @@ def get_context(
70
75
  Specialized subclass context of AppContext for the given instance type
71
76
  """
72
77
  ctx_class = select_context_class(type_)
73
- if not ctx_class.config_exists(name, system_folders):
78
+ if not ctx_class.config_exists(name, system_folders, is_sandbox=is_sandbox):
74
79
  scope = "system" if system_folders else "user"
75
80
  error(
76
81
  f"Configuration {Fore.RED}{name}{Style.RESET_ALL} does not "
@@ -83,6 +88,6 @@ def get_context(
83
88
  ctx_class.LOGGING_ENABLED = False
84
89
 
85
90
  # create server context, and initialize db
86
- ctx = ctx_class(name, system_folders=system_folders)
91
+ ctx = ctx_class(name, system_folders=system_folders, is_sandbox=is_sandbox)
87
92
 
88
93
  return ctx
@@ -26,11 +26,14 @@ class AlgorithmStoreContext(BaseServerContext):
26
26
 
27
27
  INST_CONFIG_MANAGER = AlgorithmStoreConfigurationManager
28
28
 
29
- def __init__(self, instance_name: str, system_folders: bool = S_FOL):
29
+ def __init__(
30
+ self, instance_name: str, system_folders: bool = S_FOL, is_sandbox: bool = False
31
+ ):
30
32
  super().__init__(
31
33
  InstanceType.ALGORITHM_STORE,
32
34
  instance_name,
33
35
  system_folders=system_folders,
36
+ is_sandbox=is_sandbox,
34
37
  )
35
38
  self.log.info("vantage6 version '%s'", __version__)
36
39
 
@@ -88,7 +91,9 @@ class AlgorithmStoreContext(BaseServerContext):
88
91
  )
89
92
 
90
93
  @classmethod
91
- def config_exists(cls, instance_name: str, system_folders: bool = S_FOL) -> bool:
94
+ def config_exists(
95
+ cls, instance_name: str, system_folders: bool = S_FOL, is_sandbox: bool = False
96
+ ) -> bool:
92
97
  """
93
98
  Check if a configuration file exists.
94
99
 
@@ -99,14 +104,15 @@ class AlgorithmStoreContext(BaseServerContext):
99
104
  of the configuration file.
100
105
  system_folders : bool, optional
101
106
  System wide or user configuration, by default S_FOL
102
-
107
+ is_sandbox : bool, optional
108
+ Whether the configuration is a sandbox configuration, by default False
103
109
  Returns
104
110
  -------
105
111
  bool
106
112
  Whether the configuration file exists or not
107
113
  """
108
- return super().config_exists(
109
- InstanceType.ALGORITHM_STORE, instance_name, system_folders
114
+ return super().base_config_exists(
115
+ InstanceType.ALGORITHM_STORE, instance_name, system_folders, is_sandbox
110
116
  )
111
117
 
112
118
  @classmethod
@@ -0,0 +1,125 @@
1
+ from __future__ import annotations
2
+
3
+ from vantage6.common.context import AppContext
4
+ from vantage6.common.globals import InstanceType
5
+
6
+ from vantage6.cli import __version__
7
+ from vantage6.cli.configuration_manager import AuthConfigurationManager
8
+ from vantage6.cli.globals import DEFAULT_SERVER_SYSTEM_FOLDERS as S_FOL
9
+
10
+
11
+ class AuthContext(AppContext):
12
+ """
13
+ Context class for the keycloak authentication server.
14
+
15
+ Parameters
16
+ ----------
17
+ instance_name : str
18
+ Name of the configuration instance, corresponds to the filename
19
+ of the configuration file.
20
+ system_folders : bool, optional
21
+ System wide or user configuration, by default S_FOL
22
+ is_sandbox : bool, optional
23
+ Whether the configuration is a sandbox configuration, by default False
24
+ """
25
+
26
+ # The auth configuration manager is aware of the structure of the auth
27
+ # configuration file and makes sure only valid configuration can be loaded.
28
+ INST_CONFIG_MANAGER = AuthConfigurationManager
29
+
30
+ def __init__(
31
+ self,
32
+ instance_name: str,
33
+ system_folders: bool = S_FOL,
34
+ is_sandbox: bool = False,
35
+ ):
36
+ super().__init__(
37
+ InstanceType.AUTH,
38
+ instance_name,
39
+ system_folders=system_folders,
40
+ is_sandbox=is_sandbox,
41
+ )
42
+ self.log.info("vantage6 version '%s'", __version__)
43
+
44
+ @classmethod
45
+ def from_external_config_file(
46
+ cls, path: str, system_folders: bool = S_FOL
47
+ ) -> AuthContext:
48
+ """
49
+ Create a server context from an external configuration file. External
50
+ means that the configuration file is not located in the default folders
51
+ but its location is specified by the user.
52
+
53
+ Parameters
54
+ ----------
55
+ path : str
56
+ Path of the configuration file
57
+ system_folders : bool, optional
58
+ System wide or user configuration, by default S_FOL
59
+
60
+ Returns
61
+ -------
62
+ ServerContext
63
+ Server context object
64
+ """
65
+ return super().from_external_config_file(
66
+ path,
67
+ InstanceType.AUTH,
68
+ system_folders,
69
+ )
70
+
71
+ @classmethod
72
+ def config_exists(
73
+ cls,
74
+ instance_name: str,
75
+ system_folders: bool = S_FOL,
76
+ is_sandbox: bool = False,
77
+ ) -> bool:
78
+ """
79
+ Check if a configuration file exists.
80
+
81
+ Parameters
82
+ ----------
83
+ instance_name : str
84
+ Name of the configuration instance, corresponds to the filename
85
+ of the configuration file.
86
+ system_folders : bool, optional
87
+ System wide or user configuration, by default S_FOL
88
+ is_sandbox : bool, optional
89
+ Whether the configuration is a sandbox configuration, by default False
90
+
91
+ Returns
92
+ -------
93
+ bool
94
+ Whether the configuration file exists or not
95
+ """
96
+ return super().base_config_exists(
97
+ InstanceType.AUTH,
98
+ instance_name,
99
+ system_folders=system_folders,
100
+ is_sandbox=is_sandbox,
101
+ )
102
+
103
+ @classmethod
104
+ def available_configurations(
105
+ cls, system_folders: bool = S_FOL, is_sandbox: bool = False
106
+ ) -> tuple[list, list]:
107
+ """
108
+ Find all available auth configurations in the default folders.
109
+
110
+ Parameters
111
+ ----------
112
+ system_folders : bool, optional
113
+ System wide or user configuration, by default S_FOL
114
+ is_sandbox : bool, optional
115
+ Whether the configuration is a sandbox configuration, by default False
116
+
117
+ Returns
118
+ -------
119
+ tuple[list, list]
120
+ The first list contains validated configuration files, the second
121
+ list contains invalid configuration files.
122
+ """
123
+ return super().available_configurations(
124
+ InstanceType.AUTH, system_folders, is_sandbox
125
+ )
@@ -1,9 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os.path
4
-
5
- from sqlalchemy.engine.url import make_url
6
-
7
3
  from vantage6.common.context import AppContext
8
4
 
9
5
  from vantage6.cli.globals import (
@@ -27,6 +27,8 @@ class NodeContext(AppContext):
27
27
  _description_, by default None
28
28
  in_container : bool, optional
29
29
  Whether the application is running inside a container, by default False
30
+ is_sandbox : bool, optional
31
+ Whether the configuration is a sandbox configuration, by default False
30
32
  """
31
33
 
32
34
  # The server configuration manager is aware of the structure of the server
@@ -41,6 +43,7 @@ class NodeContext(AppContext):
41
43
  print_log_header: bool = True,
42
44
  logger_prefix: str = "",
43
45
  in_container: bool = False,
46
+ is_sandbox: bool = False,
44
47
  ):
45
48
  super().__init__(
46
49
  InstanceType.NODE,
@@ -50,6 +53,7 @@ class NodeContext(AppContext):
50
53
  print_log_header=print_log_header,
51
54
  logger_prefix=logger_prefix,
52
55
  in_container=in_container,
56
+ is_sandbox=is_sandbox,
53
57
  )
54
58
  if print_log_header:
55
59
  self.log.info("vantage6 version '%s'", __version__)
@@ -57,7 +61,7 @@ class NodeContext(AppContext):
57
61
 
58
62
  @classmethod
59
63
  def from_external_config_file(
60
- cls, path: str, system_folders: bool = N_FOL
64
+ cls, path: str, system_folders: bool = N_FOL, is_sandbox: bool = False
61
65
  ) -> NodeContext:
62
66
  """
63
67
  Create a node context from an external configuration file. External
@@ -77,11 +81,16 @@ class NodeContext(AppContext):
77
81
  Node context object
78
82
  """
79
83
  return super().from_external_config_file(
80
- Path(path).resolve(), InstanceType.NODE, system_folders
84
+ Path(path).resolve(),
85
+ InstanceType.NODE,
86
+ system_folders,
87
+ is_sandbox=is_sandbox,
81
88
  )
82
89
 
83
90
  @classmethod
84
- def config_exists(cls, instance_name: str, system_folders: bool = N_FOL) -> bool:
91
+ def config_exists(
92
+ cls, instance_name: str, system_folders: bool = N_FOL, is_sandbox: bool = False
93
+ ) -> bool:
85
94
  """
86
95
  Check if a configuration file exists.
87
96
 
@@ -92,19 +101,23 @@ class NodeContext(AppContext):
92
101
  of the configuration file.
93
102
  system_folders : bool, optional
94
103
  System wide or user configuration, by default N_FOL
95
-
104
+ is_sandbox : bool, optional
105
+ Whether the configuration is a sandbox configuration, by default False
96
106
  Returns
97
107
  -------
98
108
  bool
99
109
  Whether the configuration file exists or not
100
110
  """
101
- return super().config_exists(
102
- InstanceType.NODE, instance_name, system_folders=system_folders
111
+ return super().base_config_exists(
112
+ InstanceType.NODE,
113
+ instance_name,
114
+ system_folders=system_folders,
115
+ is_sandbox=is_sandbox,
103
116
  )
104
117
 
105
118
  @classmethod
106
119
  def available_configurations(
107
- cls, system_folders: bool = N_FOL
120
+ cls, system_folders: bool = N_FOL, is_sandbox: bool = False
108
121
  ) -> tuple[list, list]:
109
122
  """
110
123
  Find all available server configurations in the default folders.
@@ -113,6 +126,8 @@ class NodeContext(AppContext):
113
126
  ----------
114
127
  system_folders : bool, optional
115
128
  System wide or user configuration, by default N_FOL
129
+ is_sandbox : bool, optional
130
+ Whether the configuration is a sandbox configuration, by default False
116
131
 
117
132
  Returns
118
133
  -------
@@ -120,7 +135,9 @@ class NodeContext(AppContext):
120
135
  The first list contains validated configuration files, the second
121
136
  list contains invalid configuration files.
122
137
  """
123
- return super().available_configurations(InstanceType.NODE, system_folders)
138
+ return super().available_configurations(
139
+ InstanceType.NODE, system_folders, is_sandbox
140
+ )
124
141
 
125
142
  @staticmethod
126
143
  def type_data_folder(system_folders: bool = N_FOL) -> Path:
@@ -36,12 +36,14 @@ class ServerContext(BaseServerContext):
36
36
  instance_name: str,
37
37
  system_folders: bool = S_FOL,
38
38
  in_container: bool = False,
39
+ is_sandbox: bool = False,
39
40
  ):
40
41
  super().__init__(
41
42
  InstanceType.SERVER,
42
43
  instance_name,
43
44
  system_folders=system_folders,
44
45
  in_container=in_container,
46
+ is_sandbox=is_sandbox,
45
47
  )
46
48
  self.log.info("vantage6 version '%s'", __version__)
47
49
 
@@ -123,7 +125,9 @@ class ServerContext(BaseServerContext):
123
125
  )
124
126
 
125
127
  @classmethod
126
- def config_exists(cls, instance_name: str, system_folders: bool = S_FOL) -> bool:
128
+ def config_exists(
129
+ cls, instance_name: str, system_folders: bool = S_FOL, is_sandbox: bool = False
130
+ ) -> bool:
127
131
  """
128
132
  Check if a configuration file exists.
129
133
 
@@ -134,19 +138,23 @@ class ServerContext(BaseServerContext):
134
138
  of the configuration file.
135
139
  system_folders : bool, optional
136
140
  System wide or user configuration, by default S_FOL
137
-
141
+ is_sandbox : bool, optional
142
+ Whether the configuration is a sandbox configuration, by default False
138
143
  Returns
139
144
  -------
140
145
  bool
141
146
  Whether the configuration file exists or not
142
147
  """
143
- return super().config_exists(
144
- InstanceType.SERVER, instance_name, system_folders=system_folders
148
+ return super().base_config_exists(
149
+ InstanceType.SERVER,
150
+ instance_name,
151
+ system_folders=system_folders,
152
+ is_sandbox=is_sandbox,
145
153
  )
146
154
 
147
155
  @classmethod
148
156
  def available_configurations(
149
- cls, system_folders: bool = S_FOL
157
+ cls, system_folders: bool = S_FOL, is_sandbox: bool = False
150
158
  ) -> tuple[list, list]:
151
159
  """
152
160
  Find all available server configurations in the default folders.
@@ -155,6 +163,8 @@ class ServerContext(BaseServerContext):
155
163
  ----------
156
164
  system_folders : bool, optional
157
165
  System wide or user configuration, by default S_FOL
166
+ is_sandbox : bool, optional
167
+ Whether the configuration is a sandbox configuration, by default False
158
168
 
159
169
  Returns
160
170
  -------
@@ -162,4 +172,6 @@ class ServerContext(BaseServerContext):
162
172
  The first list contains validated configuration files, the second
163
173
  list contains invalid configuration files.
164
174
  """
165
- return super().available_configurations(InstanceType.SERVER, system_folders)
175
+ return super().available_configurations(
176
+ InstanceType.SERVER, system_folders, is_sandbox
177
+ )
@@ -0,0 +1,28 @@
1
+ import subprocess
2
+ import sys
3
+
4
+ import click
5
+
6
+ from vantage6.common import error, info
7
+
8
+ from vantage6.cli.dev.common import check_devspace_installed
9
+
10
+
11
+ @click.command()
12
+ def cli_clean_dev_env():
13
+ """
14
+ Stops and cleans up the development environment.
15
+
16
+ Removes the kubernetes resources and local data (e.g. tasks data, database data).
17
+ This is useful when you want to start from scratch.
18
+ """
19
+ check_devspace_installed()
20
+
21
+ try:
22
+ info("🧹 Cleaning development environment with devspace...")
23
+ cmd = ["devspace", "run", "purge"]
24
+ subprocess.run(cmd, check=True, capture_output=False)
25
+ info("✅ Development environment cleaned successfully!")
26
+ except subprocess.CalledProcessError as e:
27
+ error(f"❌ Error cleaning development environment: {e}")
28
+ sys.exit(e.returncode)
@@ -0,0 +1,34 @@
1
+ import shutil
2
+ import subprocess
3
+ import sys
4
+
5
+ from vantage6.common import error
6
+
7
+
8
+ def check_devspace_installed() -> None:
9
+ """Check if devspace is installed. Exits if not."""
10
+ # Check if devspace command exists
11
+ if shutil.which("devspace") is None:
12
+ _message_devspace_not_installed()
13
+
14
+ try:
15
+ # Try to run devspace --version to verify it's working
16
+ result = subprocess.run(
17
+ ["devspace", "--version"], capture_output=True, text=True, timeout=10
18
+ )
19
+ if result.returncode != 0:
20
+ _message_devspace_not_installed()
21
+ except (
22
+ subprocess.TimeoutExpired,
23
+ subprocess.CalledProcessError,
24
+ FileNotFoundError,
25
+ ):
26
+ _message_devspace_not_installed()
27
+
28
+
29
+ def _message_devspace_not_installed() -> None:
30
+ error(
31
+ "❌ DevSpace command not found. Please ensure devspace is installed and in "
32
+ "your PATH."
33
+ )
34
+ sys.exit(1)