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,207 @@
1
+ from pathlib import Path
2
+
3
+ import click
4
+ from colorama import Fore, Style
5
+
6
+ from vantage6.common import error
7
+ from vantage6.common.globals import Ports
8
+
9
+ from vantage6.cli.common.utils import select_context_and_namespace
10
+ from vantage6.cli.context.server import ServerContext
11
+ from vantage6.cli.sandbox.config.core import CoreSandboxConfigManager
12
+ from vantage6.cli.sandbox.start import execute_sandbox_start
13
+ from vantage6.cli.server.common import get_server_context
14
+ from vantage6.cli.utils import prompt_config_name
15
+
16
+
17
+ @click.command()
18
+ @click.option(
19
+ "-n", "--name", default=None, type=str, help="Name for your development setup"
20
+ )
21
+ @click.option(
22
+ "--num-nodes",
23
+ type=int,
24
+ default=3,
25
+ help="Generate this number of nodes in the development network",
26
+ )
27
+ @click.option(
28
+ "-p",
29
+ "--server-port",
30
+ type=int,
31
+ default=Ports.DEV_SERVER.value,
32
+ help=f"Port to run the server on. Default is {Ports.DEV_SERVER}.",
33
+ )
34
+ @click.option(
35
+ "--ui-port",
36
+ type=int,
37
+ default=Ports.DEV_UI.value,
38
+ help=f"Port to run the UI on. Default is {Ports.DEV_UI}.",
39
+ )
40
+ @click.option(
41
+ "--algorithm-store-port",
42
+ type=int,
43
+ default=Ports.DEV_ALGO_STORE.value,
44
+ help=f"Port to run the algorithm store on. Default is {Ports.DEV_ALGO_STORE}.",
45
+ )
46
+ @click.option(
47
+ "--server-image",
48
+ type=str,
49
+ default=None,
50
+ help="Server docker image to use when setting up resources for "
51
+ "the development server",
52
+ )
53
+ @click.option(
54
+ "--ui-image",
55
+ type=str,
56
+ default=None,
57
+ help="UI docker image to specify in configuration files. Will be used on startup of"
58
+ " the network",
59
+ )
60
+ @click.option(
61
+ "--store-image",
62
+ type=str,
63
+ default=None,
64
+ help="Algorithm store docker image to use when setting up resources for "
65
+ "the development algorithm store",
66
+ )
67
+ @click.option(
68
+ "--node-image",
69
+ type=str,
70
+ default=None,
71
+ help="Node docker image to use when setting up resources for the development node",
72
+ )
73
+ @click.option(
74
+ "--extra-server-config",
75
+ type=click.Path(exists=True),
76
+ default=None,
77
+ help="YAML File with additional server "
78
+ "configuration. This will be appended to the server "
79
+ "configuration file",
80
+ )
81
+ @click.option(
82
+ "--extra-node-config",
83
+ type=click.Path("rb"),
84
+ default=None,
85
+ help="YAML File with additional node configuration. This will be"
86
+ " appended to each of the node configuration files",
87
+ )
88
+ @click.option(
89
+ "--extra-store-config",
90
+ type=click.Path("rb"),
91
+ default=None,
92
+ help="YAML File with additional algorithm store configuration. This will be"
93
+ " appended to the algorithm store configuration file",
94
+ )
95
+ @click.option(
96
+ "--extra-auth-config",
97
+ type=click.Path("rb"),
98
+ default=None,
99
+ help="YAML File with additional auth configuration. This will be"
100
+ " appended to the auth configuration file",
101
+ )
102
+ @click.option(
103
+ "--add-dataset",
104
+ type=(str, click.Path()),
105
+ default=None,
106
+ multiple=True,
107
+ help="Add a dataset to the nodes. The first argument is the label of the database, "
108
+ "the second is the path to the dataset file.",
109
+ )
110
+ @click.option("--context", default=None, help="Kubernetes context to use")
111
+ @click.option("--namespace", default=None, help="Kubernetes namespace to use")
112
+ @click.option(
113
+ "--k8s-node-name", default="docker-desktop", help="Kubernetes node name to use"
114
+ )
115
+ @click.option(
116
+ "--data-dir",
117
+ type=click.Path(exists=True),
118
+ default=None,
119
+ help="Path to a custom data directory to use. This option is especially useful "
120
+ "on WSL because of mount issues for default directories",
121
+ )
122
+ @click.option(
123
+ "--local-chart-dir",
124
+ type=click.Path(exists=True),
125
+ default=None,
126
+ help="Local chart repository to use.",
127
+ )
128
+ @click.pass_context
129
+ def cli_new_sandbox(
130
+ click_ctx: click.Context,
131
+ name: str,
132
+ num_nodes: int,
133
+ server_port: int,
134
+ ui_port: int,
135
+ algorithm_store_port: int,
136
+ server_image: str | None,
137
+ ui_image: str | None,
138
+ store_image: str | None,
139
+ node_image: str | None,
140
+ extra_server_config: Path | None,
141
+ extra_node_config: Path | None,
142
+ extra_store_config: Path | None,
143
+ extra_auth_config: Path | None,
144
+ add_dataset: tuple[str, Path] | None,
145
+ context: str | None,
146
+ namespace: str | None,
147
+ k8s_node_name: str,
148
+ data_dir: str | None,
149
+ local_chart_dir: Path | None,
150
+ ) -> None:
151
+ """
152
+ Create a sandbox environment.
153
+ """
154
+
155
+ # Prompt for the k8s namespace and context
156
+ context, namespace = select_context_and_namespace(
157
+ context=context,
158
+ namespace=namespace,
159
+ )
160
+
161
+ if data_dir is not None:
162
+ data_dir = Path(data_dir)
163
+ if not data_dir.exists():
164
+ error(f"Data directory {data_dir} does not exist!")
165
+ exit(1)
166
+
167
+ server_name = prompt_config_name(name)
168
+ if ServerContext.config_exists(server_name, False, is_sandbox=True):
169
+ error(f"Configuration {Fore.RED}{server_name}{Style.RESET_ALL} already exists!")
170
+ exit(1)
171
+
172
+ sb_config_manager = CoreSandboxConfigManager(
173
+ server_name=server_name,
174
+ server_port=server_port,
175
+ ui_port=ui_port,
176
+ algorithm_store_port=algorithm_store_port,
177
+ server_image=server_image,
178
+ ui_image=ui_image,
179
+ store_image=store_image,
180
+ extra_server_config=extra_server_config,
181
+ extra_store_config=extra_store_config,
182
+ extra_auth_config=extra_auth_config,
183
+ context=context,
184
+ namespace=namespace,
185
+ k8s_node_name=k8s_node_name,
186
+ custom_data_dir=data_dir,
187
+ )
188
+
189
+ sb_config_manager.generate_server_configs()
190
+
191
+ ctx = get_server_context(server_name, False, ServerContext, is_sandbox=True)
192
+
193
+ execute_sandbox_start(
194
+ click_ctx=click_ctx,
195
+ ctx=ctx,
196
+ server_name=server_name,
197
+ context=context,
198
+ namespace=namespace,
199
+ num_nodes=num_nodes,
200
+ initialize=True,
201
+ node_image=node_image,
202
+ k8s_node_name=k8s_node_name,
203
+ extra_node_config=extra_node_config,
204
+ add_dataset=add_dataset,
205
+ custom_data_dir=data_dir,
206
+ local_chart_dir=local_chart_dir,
207
+ )
@@ -0,0 +1,173 @@
1
+ """
2
+ Script to populate the server with basic fixtures.
3
+ """
4
+
5
+ import time
6
+ import traceback
7
+ from logging import info
8
+
9
+ from vantage6.common import error
10
+
11
+ from vantage6.client import Client
12
+ from vantage6.client.utils import LogLevel
13
+
14
+ from vantage6.cli.sandbox.populate.helpers.connect_store import connect_store
15
+ from vantage6.cli.sandbox.populate.helpers.delete_fixtures import delete_fixtures
16
+ from vantage6.cli.sandbox.populate.helpers.load_fixtures import create_fixtures
17
+ from vantage6.cli.sandbox.populate.helpers.utils import NodeConfigCreationDetails
18
+
19
+
20
+ def populate_server_dev(
21
+ server_url: str,
22
+ auth_url: str,
23
+ number_of_nodes: int,
24
+ node_config_creation_details: NodeConfigCreationDetails,
25
+ ) -> str | None:
26
+ """
27
+ Populate the server with basic fixtures.
28
+
29
+ Parameters
30
+ ----------
31
+ server_url : str
32
+ The URL of the server to connect to.
33
+ auth_url : str
34
+ The URL of the auth service to connect to.
35
+ number_of_nodes : int
36
+ The number of nodes to create.
37
+ node_config_creation_details : NodeConfigCreationDetails | None
38
+ The details of the node config creation. If None, the node configs will not be
39
+ created.
40
+ clear_dev_folders : bool
41
+ Whether to clear everything inthe dev directory before creating the new
42
+ resources.
43
+ create_node_configs: bool
44
+ Whether to create the node configs. Default is True.
45
+
46
+ Returns
47
+ -------
48
+ str | None
49
+ A report of the creation process, or None if an error occurred.
50
+
51
+ Raises
52
+ ------
53
+ Exception
54
+ If connection/authentication to the server fails.
55
+ """
56
+ client = _initalize_client(server_url, auth_url)
57
+
58
+ # Create new resources in the server
59
+ # Delete existing resources in the server first, before creating new ones.
60
+ try:
61
+ report_deletion = delete_fixtures(client)
62
+ report_creation = create_fixtures(
63
+ client,
64
+ number_of_nodes,
65
+ node_config_creation_details=node_config_creation_details,
66
+ clear_dev_folders=True,
67
+ )
68
+ report_store = connect_store(client)
69
+
70
+ return report_deletion + "\n" + report_creation + "\n" + report_store
71
+
72
+ except Exception:
73
+ error("=" * 80)
74
+ error("Failed to populate server")
75
+ error(traceback.format_exc())
76
+ error("=" * 80)
77
+
78
+
79
+ def populate_server_sandbox(
80
+ server_url: str,
81
+ auth_url: str,
82
+ number_of_nodes: int,
83
+ ) -> dict:
84
+ """
85
+ Populate sandbox server with basic resources.
86
+
87
+ Parameters
88
+ ----------
89
+ server_url : str
90
+ The URL of the server to connect to.
91
+ auth_url : str
92
+ The URL of the auth service to connect to.
93
+ number_of_nodes : int
94
+ The number of nodes to create.
95
+
96
+ Returns
97
+ -------
98
+ dict
99
+ A dictionary containing the report of the creation process.
100
+
101
+ Raises
102
+ ------
103
+ Exception
104
+ If connection/authentication to the server fails.
105
+ """
106
+ client = _initalize_client(server_url, auth_url)
107
+
108
+ try:
109
+ delete_fixtures(client)
110
+ report_creation = create_fixtures(
111
+ client,
112
+ number_of_nodes,
113
+ clear_dev_folders=False,
114
+ return_as_dict=True,
115
+ )
116
+ connect_store(client)
117
+ except Exception:
118
+ error("=" * 80)
119
+ error("Failed to populate server")
120
+ error(traceback.format_exc())
121
+ error("=" * 80)
122
+ exit(1)
123
+
124
+ # return the details of the created nodes so that config files can be created
125
+ return report_creation["nodes"]["created"]
126
+
127
+
128
+ def _initalize_client(server_url, auth_url) -> Client:
129
+ """
130
+ Initialize an authenticated client to the server.
131
+
132
+ The server may not be ready yet, so we retry until it is.
133
+
134
+ Parameters
135
+ ----------
136
+ server_url : str
137
+ The URL of the server to connect to.
138
+ auth_url : str
139
+ The URL of the auth service to connect to.
140
+
141
+ Returns
142
+ -------
143
+ Client
144
+ An authenticated client to the server.
145
+ """
146
+ client = Client(
147
+ server_url=server_url,
148
+ auth_url=auth_url,
149
+ log_level=LogLevel.ERROR,
150
+ )
151
+
152
+ info("Waiting for authentication...")
153
+ max_attempts = 120
154
+ attempt = 1
155
+
156
+ while attempt <= max_attempts:
157
+ try:
158
+ print(".", end="", flush=True)
159
+ client.authenticate()
160
+ info("Successfully authenticated with server!")
161
+ break
162
+ except Exception as e:
163
+ if attempt == max_attempts:
164
+ error(
165
+ f"Failed to authenticate after {max_attempts} attempts. "
166
+ "Server may not be online."
167
+ )
168
+ raise e
169
+
170
+ time.sleep(5)
171
+ attempt += 1
172
+
173
+ return client
@@ -0,0 +1,203 @@
1
+ """
2
+ Development script to connect the server to the local store.
3
+ """
4
+
5
+ import time
6
+ from http import HTTPStatus
7
+
8
+ import requests
9
+
10
+ from vantage6.common import error, info
11
+ from vantage6.common.enum import AlgorithmStepType
12
+
13
+ from vantage6.client import Client
14
+
15
+
16
+ def _wait_for_store_to_be_online(
17
+ local_store_url: str, local_store_api_path: str
18
+ ) -> None:
19
+ """
20
+ Wait for the store to be online.
21
+
22
+ Parameters
23
+ ---------
24
+ client: Client
25
+ The client to use to connect to the server.
26
+ local_store_url: str
27
+ The URL of the local store.
28
+ local_store_api_path: str
29
+ The API path of the local store.
30
+ """
31
+ info(
32
+ f"Waiting for store to be online at {local_store_url}{local_store_api_path}..."
33
+ )
34
+ max_retries = 100
35
+ wait_time = 3
36
+ ready = False
37
+ for _ in range(max_retries):
38
+ try:
39
+ result = requests.get(f"{local_store_url}{local_store_api_path}/version")
40
+ if result.status_code == HTTPStatus.OK:
41
+ ready = True
42
+ break
43
+ except Exception:
44
+ info(f"Store not ready yet, waiting {wait_time} seconds...")
45
+ time.sleep(wait_time)
46
+
47
+ if not ready:
48
+ error("Store did not become ready in time. Exiting...")
49
+ exit(1)
50
+ else:
51
+ info("Store is online!")
52
+
53
+
54
+ def connect_store(client: Client) -> str:
55
+ """
56
+ Connect the server to the local store.
57
+
58
+ Parameters
59
+ ---------
60
+ client: Client
61
+ The client to use to connect to the server.
62
+ dev_dir: Path
63
+ The directory to use to store the development data.
64
+ """
65
+
66
+ existing_stores = client.store.list().get("data", [])
67
+ summary = "=== Store Connection Summary ===\n"
68
+
69
+ # URL should be retrieved from the store, see issue:
70
+ # https://github.com/vantage6/vantage6/issues/1824
71
+ local_store_url = "http://localhost:7602"
72
+ local_store_api_path = "/store"
73
+ client.store.store_id = 1
74
+
75
+ _wait_for_store_to_be_online(local_store_url, local_store_api_path)
76
+
77
+ # note that the store is already coupled to the server in the sandbox/devspace
78
+ # config. To find the store, either check that it is a localhost URL or that it
79
+ # contains "svc.cluster.local" (which is for local k8s services)
80
+ try:
81
+ store = next(s for s in existing_stores if s["url"] == local_store_url)
82
+ client.store.set(store["id"])
83
+ except StopIteration:
84
+ error(
85
+ "Local algorithm store not found. Please register its resources manually."
86
+ )
87
+ return
88
+
89
+ # register also the other users in the local store
90
+ users_in_store = client.store.user.list()["data"]
91
+ all_users = client.user.list()["data"]
92
+ for user in all_users:
93
+ if user["keycloak_id"] not in [u["keycloak_id"] for u in users_in_store]:
94
+ summary += f"Registering user {user['username']} in local store\n"
95
+ client.store.user.register(username=user["username"], roles=[1])
96
+
97
+ # Remove existing algorithm
98
+ # This is broken, see issue: https://github.com/vantage6/vantage6/issues/1824
99
+ algorithms = client.algorithm.list(name="session basic example")["data"]
100
+ if len(algorithms) > 0:
101
+ summary += f"Removing existing algorithm {algorithms[0]['name']}\n"
102
+ client.algorithm.delete(id_=algorithms[0]["id"])
103
+
104
+ # Download the algorithm store from the github repo. This ensures that the data is
105
+ # always up to date.
106
+ try:
107
+ url = (
108
+ "https://raw.githubusercontent.com/vantage6/v6-session-basics/"
109
+ "main/algorithm_store.json"
110
+ )
111
+ response = requests.get(url, timeout=10)
112
+ response.raise_for_status()
113
+ algorithm_json = response.json()
114
+ function_metadata = algorithm_json["functions"]
115
+ except requests.exceptions.RequestException as e:
116
+ # Fallback to local file if download fails
117
+ print(f"Warning: Could not download algorithm store from GitHub: {e}")
118
+ print("Not putting the algorithm in the store.")
119
+ function_metadata = []
120
+
121
+ summary += "Creating Session Basics algorithm\n"
122
+ client.algorithm.create(
123
+ name="Session Basics",
124
+ description="A set of basic algorithms for a session management",
125
+ image="harbor2.vantage6.ai/algorithms/session-basics:latest",
126
+ vantage6_version="5.0.0",
127
+ code_url="https://github.com/vantage6-ai/v6-session-basics",
128
+ partitioning="horizontal",
129
+ functions=function_metadata or [],
130
+ )
131
+
132
+ # TODO: v5+ get this json data by downloading it from the github repo - that ensures
133
+ # that the data is always up to date.
134
+ summary += "Creating Network Diagnostics algorithm\n"
135
+ client.algorithm.create(
136
+ name="Network Diagnostics",
137
+ description=(
138
+ "Functions to diagnose network policies, that is, to what extent the "
139
+ "jobs running on a V6 Node could have access to the internal k8s network "
140
+ "or to the outside world."
141
+ ),
142
+ image="ghcr.io/hcadavid/v6-sessions-k8s-diagnostics:latest",
143
+ vantage6_version="5.0.0",
144
+ code_url="https://github.com/hcadavid/v6-sessions-k8s-diagnostics",
145
+ partitioning="horizontal",
146
+ functions=[
147
+ {
148
+ "name": "network_status",
149
+ "display_name": "Get the network diagnostics performed on a given node",
150
+ "standalone": True,
151
+ "description": "Get the network diagnostics performed on a given node",
152
+ "ui_visualizations": [],
153
+ "step_type": AlgorithmStepType.FEDERATED_COMPUTE.value,
154
+ "arguments": [
155
+ {
156
+ "has_default_value": True,
157
+ "name": "sleep_time",
158
+ "display_name": "Delay ",
159
+ "description": (
160
+ "Delay in seconds before finishing the the diagnostics "
161
+ "task (useful to keep the POD running and access it to "
162
+ "perform further tests) "
163
+ ),
164
+ "type": "integer",
165
+ "default_value": "1",
166
+ "is_frontend_only": False,
167
+ }
168
+ ],
169
+ "databases": [],
170
+ },
171
+ {
172
+ "name": "central_network_diagnostics",
173
+ "display_name": (
174
+ "Get the network diagnostics performed on all the nodes"
175
+ ),
176
+ "standalone": True,
177
+ "description": (
178
+ "Get the network diagnostics performed on all the nodes within a "
179
+ "collaboration"
180
+ ),
181
+ "ui_visualizations": [],
182
+ "step_type": AlgorithmStepType.CENTRAL_COMPUTE.value,
183
+ "arguments": [
184
+ {
185
+ "has_default_value": True,
186
+ "name": "sleep_time",
187
+ "display_name": "Delay ",
188
+ "description": (
189
+ "Delay in seconds before finishing the the diagnostics "
190
+ "task (useful to keep the PODs running on all the nodes "
191
+ "to access them and perform further inspections) "
192
+ ),
193
+ "type": "integer",
194
+ "default_value": "1",
195
+ "is_frontend_only": False,
196
+ }
197
+ ],
198
+ "databases": [],
199
+ },
200
+ ],
201
+ )
202
+
203
+ return summary
@@ -0,0 +1,67 @@
1
+ """
2
+ Development script to delete all entities from the server
3
+ """
4
+
5
+ from vantage6.client import Client
6
+
7
+
8
+ def delete_fixtures(client: Client) -> str:
9
+ """
10
+ Delete all entities from the server.
11
+
12
+ Arguments
13
+ ---------
14
+ client: Client
15
+ The client to use to delete the entities.
16
+ """
17
+
18
+ # Track deletion counts
19
+ deletion_counts = {}
20
+
21
+ # Delete sessions & dataframes
22
+ sessions = client.session.list(per_page=999)["data"]
23
+ for session in sessions:
24
+ client.session.delete(session["id"], delete_dependents=True)
25
+ deletion_counts["sessions"] = len(sessions)
26
+
27
+ # Delete tasks and nodes
28
+ for client_subclass_name in ("task", "node"):
29
+ client_subclass = getattr(client, client_subclass_name)
30
+ entities = client_subclass.list(per_page=999)["data"]
31
+ for entity in entities:
32
+ client_subclass.delete(entity["id"])
33
+ deletion_counts[f"{client_subclass_name}s"] = len(entities)
34
+
35
+ # Delete collaborations
36
+ collabs = client.collaboration.list(per_page=999, scope="global")["data"]
37
+ for collab in collabs:
38
+ client.collaboration.delete(collab["id"])
39
+ deletion_counts["collaborations"] = len(collabs)
40
+
41
+ # Delete users (excluding admin)
42
+ users = client.user.list(per_page=999)["data"]
43
+ deleted_users = 0
44
+ for user in users:
45
+ if user["username"] == "admin":
46
+ continue
47
+ client.user.delete(user["id"])
48
+ deleted_users += 1
49
+ deletion_counts["users"] = deleted_users
50
+
51
+ # Delete organizations (excluding the default organization with id 1)
52
+ orgs = client.organization.list(per_page=999)["data"]
53
+ deleted_orgs = 0
54
+ for org in orgs:
55
+ if org["id"] == 1:
56
+ continue
57
+ client.organization.delete(org["id"])
58
+ deleted_orgs += 1
59
+ deletion_counts["organizations"] = deleted_orgs
60
+
61
+ # Create summary string
62
+ summary = "=== Deletion Summary ===\n"
63
+ for entity_type, count in deletion_counts.items():
64
+ summary += f"Deleted {count} {entity_type}\n"
65
+ summary += "======================="
66
+ print(summary)
67
+ return summary