vantage6 5.0.0a37__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.
- vantage6/cli/algostore/attach.py +28 -3
- vantage6/cli/algostore/list.py +2 -2
- vantage6/cli/algostore/start.py +11 -3
- vantage6/cli/algostore/version.py +62 -0
- vantage6/cli/auth/attach.py +1 -1
- vantage6/cli/auth/list.py +2 -2
- vantage6/cli/auth/remove.py +58 -0
- vantage6/cli/auth/start.py +12 -8
- vantage6/cli/cli.py +2 -0
- vantage6/cli/common/attach.py +114 -0
- vantage6/cli/common/decorator.py +5 -3
- vantage6/cli/common/list.py +68 -0
- vantage6/cli/common/remove.py +18 -0
- vantage6/cli/common/stop.py +3 -9
- vantage6/cli/common/utils.py +44 -76
- vantage6/cli/common/version.py +82 -0
- vantage6/cli/context/__init__.py +3 -0
- vantage6/cli/context/algorithm_store.py +2 -2
- vantage6/cli/node/attach.py +27 -3
- vantage6/cli/node/list.py +3 -44
- vantage6/cli/node/start.py +11 -3
- vantage6/cli/node/stop.py +13 -15
- vantage6/cli/node/version.py +96 -33
- vantage6/cli/sandbox/config/base.py +10 -2
- vantage6/cli/sandbox/config/core.py +3 -3
- vantage6/cli/sandbox/config/node.py +2 -5
- vantage6/cli/sandbox/remove.py +17 -35
- vantage6/cli/sandbox/start.py +8 -0
- vantage6/cli/sandbox/stop.py +1 -1
- vantage6/cli/server/attach.py +28 -3
- vantage6/cli/server/list.py +2 -2
- vantage6/cli/server/start.py +11 -3
- vantage6/cli/server/version.py +31 -18
- vantage6/cli/template/algo_store_config.j2 +3 -0
- vantage6/cli/template/node_config.j2 +2 -0
- vantage6/cli/use/context.py +8 -1
- vantage6/cli/use/namespace.py +10 -7
- vantage6/cli/utils_kubernetes.py +270 -0
- {vantage6-5.0.0a37.dist-info → vantage6-5.0.0a38.dist-info}/METADATA +3 -3
- {vantage6-5.0.0a37.dist-info → vantage6-5.0.0a38.dist-info}/RECORD +43 -38
- /vantage6/cli/node/{task_cleanup/__init__.py → common/task_cleanup.py} +0 -0
- {vantage6-5.0.0a37.dist-info → vantage6-5.0.0a38.dist-info}/WHEEL +0 -0
- {vantage6-5.0.0a37.dist-info → vantage6-5.0.0a38.dist-info}/entry_points.txt +0 -0
vantage6/cli/common/utils.py
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import subprocess
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from subprocess import Popen
|
|
5
4
|
from typing import Iterable
|
|
6
5
|
|
|
7
|
-
import click
|
|
8
6
|
import docker
|
|
9
7
|
import questionary as q
|
|
10
|
-
from colorama import Fore, Style
|
|
11
8
|
|
|
12
|
-
from vantage6.common import error
|
|
13
|
-
from vantage6.common.globals import
|
|
9
|
+
from vantage6.common import error
|
|
10
|
+
from vantage6.common.globals import (
|
|
11
|
+
APPNAME,
|
|
12
|
+
SANDBOX_SUFFIX,
|
|
13
|
+
STRING_ENCODING,
|
|
14
|
+
InstanceType,
|
|
15
|
+
)
|
|
14
16
|
|
|
15
17
|
from vantage6.cli.config import CliConfig
|
|
16
|
-
from vantage6.cli.context import select_context_class
|
|
17
18
|
from vantage6.cli.globals import CLICommandName
|
|
18
19
|
from vantage6.cli.utils import validate_input_cmd_args
|
|
19
20
|
|
|
@@ -251,60 +252,6 @@ def get_running_servers(
|
|
|
251
252
|
return [server.name for server in running_servers]
|
|
252
253
|
|
|
253
254
|
|
|
254
|
-
def get_server_configuration_list(instance_type: InstanceType) -> None:
|
|
255
|
-
"""
|
|
256
|
-
Print list of available server configurations.
|
|
257
|
-
|
|
258
|
-
Parameters
|
|
259
|
-
----------
|
|
260
|
-
instance_type : InstanceType
|
|
261
|
-
The type of instance to get the configurations for
|
|
262
|
-
"""
|
|
263
|
-
ctx_class = select_context_class(instance_type)
|
|
264
|
-
|
|
265
|
-
running_server_names = find_running_service_names(instance_type)
|
|
266
|
-
header = "\nName" + (21 * " ") + "Status" + (10 * " ") + "System/User"
|
|
267
|
-
|
|
268
|
-
click.echo(header)
|
|
269
|
-
click.echo("-" * len(header))
|
|
270
|
-
|
|
271
|
-
running = Fore.GREEN + "Running" + Style.RESET_ALL
|
|
272
|
-
stopped = Fore.RED + "Not running" + Style.RESET_ALL
|
|
273
|
-
|
|
274
|
-
# system folders
|
|
275
|
-
configs, failed_imports_system = ctx_class.available_configurations(
|
|
276
|
-
system_folders=True
|
|
277
|
-
)
|
|
278
|
-
for config in configs:
|
|
279
|
-
status = (
|
|
280
|
-
running
|
|
281
|
-
if f"{APPNAME}-{config.name}-system-{instance_type.value}"
|
|
282
|
-
in running_server_names
|
|
283
|
-
else stopped
|
|
284
|
-
)
|
|
285
|
-
click.echo(f"{config.name:25}{status:25} System ")
|
|
286
|
-
|
|
287
|
-
# user folders
|
|
288
|
-
configs, failed_imports_user = ctx_class.available_configurations(
|
|
289
|
-
system_folders=False
|
|
290
|
-
)
|
|
291
|
-
for config in configs:
|
|
292
|
-
status = (
|
|
293
|
-
running
|
|
294
|
-
if f"{APPNAME}-{config.name}-user-{instance_type.value}"
|
|
295
|
-
in running_server_names
|
|
296
|
-
else stopped
|
|
297
|
-
)
|
|
298
|
-
click.echo(f"{config.name:25}{status:25} User ")
|
|
299
|
-
|
|
300
|
-
click.echo("-" * 85)
|
|
301
|
-
if len(failed_imports_system) + len(failed_imports_user):
|
|
302
|
-
warning(
|
|
303
|
-
f"{Fore.RED}Failed imports: "
|
|
304
|
-
f"{len(failed_imports_system) + len(failed_imports_user)}{Style.RESET_ALL}"
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
|
|
308
255
|
def print_log_worker(logs_stream: Iterable[bytes]) -> None:
|
|
309
256
|
"""
|
|
310
257
|
Print the logs from the logs stream.
|
|
@@ -354,20 +301,6 @@ def get_config_name_from_service_name(service_name: str) -> str:
|
|
|
354
301
|
return "-".join(service_name.split("-")[1:-2])
|
|
355
302
|
|
|
356
303
|
|
|
357
|
-
def attach_logs(*labels: list[str]) -> None:
|
|
358
|
-
"""
|
|
359
|
-
Attach to the logs of the given labels.
|
|
360
|
-
|
|
361
|
-
Parameters
|
|
362
|
-
----------
|
|
363
|
-
labels : list[str]
|
|
364
|
-
The labels to attach to
|
|
365
|
-
"""
|
|
366
|
-
command = ["kubectl", "logs", "--follow", "--selector", ",".join(labels)]
|
|
367
|
-
process = Popen(command, stdout=None, stderr=None)
|
|
368
|
-
process.wait()
|
|
369
|
-
|
|
370
|
-
|
|
371
304
|
def get_main_cli_command_name(instance_type: InstanceType) -> str:
|
|
372
305
|
"""
|
|
373
306
|
Get the main CLI command name for a given instance type.
|
|
@@ -419,7 +352,9 @@ def check_running(
|
|
|
419
352
|
return helm_release_name in running_services
|
|
420
353
|
|
|
421
354
|
|
|
422
|
-
def get_config_name_from_helm_release_name(
|
|
355
|
+
def get_config_name_from_helm_release_name(
|
|
356
|
+
helm_release_name: str, is_store: bool = False
|
|
357
|
+
) -> str:
|
|
423
358
|
"""
|
|
424
359
|
Get the config name from a helm release name.
|
|
425
360
|
|
|
@@ -427,6 +362,8 @@ def get_config_name_from_helm_release_name(helm_release_name: str) -> str:
|
|
|
427
362
|
----------
|
|
428
363
|
helm_release_name : str
|
|
429
364
|
The name of the Helm release
|
|
365
|
+
is_store : bool, optional
|
|
366
|
+
Whether the instance is a store or not. By default False.
|
|
430
367
|
|
|
431
368
|
Returns
|
|
432
369
|
-------
|
|
@@ -436,4 +373,35 @@ def get_config_name_from_helm_release_name(helm_release_name: str) -> str:
|
|
|
436
373
|
# helm release name is structured as:
|
|
437
374
|
# f"{APPNAME}-{name}-{scope}-{instance_type}"
|
|
438
375
|
# we want to get the name from the service name
|
|
439
|
-
|
|
376
|
+
if is_store:
|
|
377
|
+
# for store, the instance type is `algorithm-store` which contains an additional
|
|
378
|
+
# hyphen
|
|
379
|
+
return "-".join(helm_release_name.split("-")[1:-3])
|
|
380
|
+
else:
|
|
381
|
+
return "-".join(helm_release_name.split("-")[1:-2])
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def extract_name_and_is_sandbox(name: str | None, is_sandbox: bool) -> tuple[str, bool]:
|
|
385
|
+
"""
|
|
386
|
+
Extract the name and is_sandbox from the name.
|
|
387
|
+
|
|
388
|
+
Note that the name may be None: this occurs before when this function is called
|
|
389
|
+
before the user has selected a name. This scenario is fine because when the user
|
|
390
|
+
selects a name interactively, the name never ends with the .sandbox suffix.
|
|
391
|
+
|
|
392
|
+
Parameters
|
|
393
|
+
----------
|
|
394
|
+
name : str | None
|
|
395
|
+
The name of the instance
|
|
396
|
+
is_sandbox : bool
|
|
397
|
+
Whether the instance is a sandbox instance
|
|
398
|
+
|
|
399
|
+
Returns
|
|
400
|
+
-------
|
|
401
|
+
tuple[str, bool]
|
|
402
|
+
The name and is_sandbox
|
|
403
|
+
"""
|
|
404
|
+
if name and name.endswith(SANDBOX_SUFFIX):
|
|
405
|
+
return name[: -len(SANDBOX_SUFFIX)], True
|
|
406
|
+
else:
|
|
407
|
+
return name, is_sandbox
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from vantage6.common import error
|
|
2
|
+
from vantage6.common.globals import InstanceType
|
|
3
|
+
|
|
4
|
+
from vantage6.cli.common.utils import (
|
|
5
|
+
find_running_service_names,
|
|
6
|
+
get_config_name_from_helm_release_name,
|
|
7
|
+
select_context_and_namespace,
|
|
8
|
+
select_running_service,
|
|
9
|
+
)
|
|
10
|
+
from vantage6.cli.context import get_context
|
|
11
|
+
from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
|
|
12
|
+
from vantage6.cli.context.node import NodeContext
|
|
13
|
+
from vantage6.cli.context.server import ServerContext
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_and_select_ctx(
|
|
17
|
+
instance_type: InstanceType,
|
|
18
|
+
name: str,
|
|
19
|
+
system_folders: bool,
|
|
20
|
+
context: str,
|
|
21
|
+
namespace: str,
|
|
22
|
+
is_sandbox: bool,
|
|
23
|
+
) -> ServerContext | NodeContext | AlgorithmStoreContext:
|
|
24
|
+
"""
|
|
25
|
+
Get and select the context for the given instance type.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
instance_type : InstanceType
|
|
30
|
+
The type of instance to get the context for
|
|
31
|
+
name : str
|
|
32
|
+
The name of the instance
|
|
33
|
+
system_folders : bool
|
|
34
|
+
Whether to use system folders or not
|
|
35
|
+
context : str
|
|
36
|
+
The Kubernetes context to use
|
|
37
|
+
namespace : str
|
|
38
|
+
The Kubernetes namespace to use
|
|
39
|
+
is_sandbox : bool
|
|
40
|
+
Whether the configuration is a sandbox configuration
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
ServerContext | NodeContext | AlgorithmStoreContext
|
|
45
|
+
The context for the given instance type
|
|
46
|
+
"""
|
|
47
|
+
context, namespace = select_context_and_namespace(
|
|
48
|
+
context=context,
|
|
49
|
+
namespace=namespace,
|
|
50
|
+
)
|
|
51
|
+
running_services = find_running_service_names(
|
|
52
|
+
instance_type=instance_type,
|
|
53
|
+
only_system_folders=False,
|
|
54
|
+
only_user_folders=False,
|
|
55
|
+
context=context,
|
|
56
|
+
namespace=namespace,
|
|
57
|
+
sandbox=is_sandbox,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if not running_services:
|
|
61
|
+
error(f"No running {instance_type.value}s found.")
|
|
62
|
+
exit(1)
|
|
63
|
+
|
|
64
|
+
if not name:
|
|
65
|
+
helm_name = select_running_service(running_services, instance_type)
|
|
66
|
+
|
|
67
|
+
service_name = get_config_name_from_helm_release_name(
|
|
68
|
+
helm_name, is_store=(instance_type == InstanceType.ALGORITHM_STORE)
|
|
69
|
+
)
|
|
70
|
+
ctx = get_context(
|
|
71
|
+
instance_type, service_name, system_folders, is_sandbox=is_sandbox
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
else:
|
|
75
|
+
ctx = get_context(instance_type, name, system_folders, is_sandbox=is_sandbox)
|
|
76
|
+
helm_name = ctx.helm_release_name
|
|
77
|
+
service_name = ctx.name
|
|
78
|
+
|
|
79
|
+
if helm_name not in running_services:
|
|
80
|
+
error(f"The {instance_type.value} {service_name} is not running.")
|
|
81
|
+
exit(1)
|
|
82
|
+
return ctx
|
vantage6/cli/context/__init__.py
CHANGED
|
@@ -13,6 +13,7 @@ from colorama import Fore, Style
|
|
|
13
13
|
from vantage6.common import error
|
|
14
14
|
from vantage6.common.globals import InstanceType
|
|
15
15
|
|
|
16
|
+
from vantage6.cli.common.utils import extract_name_and_is_sandbox
|
|
16
17
|
from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
|
|
17
18
|
from vantage6.cli.context.auth import AuthContext
|
|
18
19
|
from vantage6.cli.context.node import NodeContext
|
|
@@ -74,6 +75,8 @@ def get_context(
|
|
|
74
75
|
AppContext
|
|
75
76
|
Specialized subclass context of AppContext for the given instance type
|
|
76
77
|
"""
|
|
78
|
+
name, is_sandbox = extract_name_and_is_sandbox(name, is_sandbox)
|
|
79
|
+
|
|
77
80
|
ctx_class = select_context_class(type_)
|
|
78
81
|
if not ctx_class.config_exists(name, system_folders, is_sandbox=is_sandbox):
|
|
79
82
|
scope = "system" if system_folders else "user"
|
|
@@ -117,7 +117,7 @@ class AlgorithmStoreContext(BaseServerContext):
|
|
|
117
117
|
|
|
118
118
|
@classmethod
|
|
119
119
|
def available_configurations(
|
|
120
|
-
cls, system_folders: bool = S_FOL
|
|
120
|
+
cls, system_folders: bool = S_FOL, is_sandbox: bool = False
|
|
121
121
|
) -> tuple[list, list]:
|
|
122
122
|
"""
|
|
123
123
|
Find all available server configurations in the default folders.
|
|
@@ -134,5 +134,5 @@ class AlgorithmStoreContext(BaseServerContext):
|
|
|
134
134
|
list contains invalid configuration files.
|
|
135
135
|
"""
|
|
136
136
|
return super().available_configurations(
|
|
137
|
-
InstanceType.ALGORITHM_STORE, system_folders
|
|
137
|
+
InstanceType.ALGORITHM_STORE, system_folders, is_sandbox
|
|
138
138
|
)
|
vantage6/cli/node/attach.py
CHANGED
|
@@ -2,13 +2,37 @@ import click
|
|
|
2
2
|
|
|
3
3
|
from vantage6.common import info
|
|
4
4
|
|
|
5
|
-
from vantage6.cli.common.
|
|
5
|
+
from vantage6.cli.common.attach import attach_logs
|
|
6
|
+
from vantage6.cli.context import InstanceType
|
|
7
|
+
from vantage6.cli.globals import InfraComponentName
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
@click.command()
|
|
9
|
-
|
|
11
|
+
@click.option("-n", "--name", default=None, help="Name of the configuration")
|
|
12
|
+
@click.option("--system", "system_folders", flag_value=True, help="Use system folders")
|
|
13
|
+
@click.option("--user", "system_folders", flag_value=False, help="Use user folders")
|
|
14
|
+
@click.option("--context", default=None, help="Kubernetes context to use")
|
|
15
|
+
@click.option("--namespace", default=None, help="Kubernetes namespace to use")
|
|
16
|
+
@click.option(
|
|
17
|
+
"--sandbox", "is_sandbox", flag_value=True, help="Attach to a sandbox environment"
|
|
18
|
+
)
|
|
19
|
+
def cli_node_attach(
|
|
20
|
+
name: str | None,
|
|
21
|
+
system_folders: bool,
|
|
22
|
+
context: str,
|
|
23
|
+
namespace: str,
|
|
24
|
+
is_sandbox: bool,
|
|
25
|
+
) -> None:
|
|
10
26
|
"""
|
|
11
27
|
Show the node logs in the current console.
|
|
12
28
|
"""
|
|
13
29
|
info("Attaching to node logs...")
|
|
14
|
-
attach_logs(
|
|
30
|
+
attach_logs(
|
|
31
|
+
name,
|
|
32
|
+
instance_type=InstanceType.NODE,
|
|
33
|
+
infra_component=InfraComponentName.NODE,
|
|
34
|
+
system_folders=system_folders,
|
|
35
|
+
context=context,
|
|
36
|
+
namespace=namespace,
|
|
37
|
+
is_sandbox=is_sandbox,
|
|
38
|
+
)
|
vantage6/cli/node/list.py
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import click
|
|
2
|
-
import docker
|
|
3
|
-
from colorama import Fore, Style
|
|
4
2
|
|
|
5
|
-
from vantage6.common import
|
|
6
|
-
from vantage6.common.docker.addons import check_docker_running
|
|
7
|
-
from vantage6.common.globals import APPNAME
|
|
3
|
+
from vantage6.common.globals import InstanceType
|
|
8
4
|
|
|
9
|
-
from vantage6.cli.
|
|
10
|
-
from vantage6.cli.node.common import find_running_node_names
|
|
5
|
+
from vantage6.cli.common.list import get_configuration_list
|
|
11
6
|
|
|
12
7
|
|
|
13
8
|
@click.command()
|
|
@@ -18,40 +13,4 @@ def cli_node_list() -> None:
|
|
|
18
13
|
Note that this command cannot find node configuration files in custom
|
|
19
14
|
directories.
|
|
20
15
|
"""
|
|
21
|
-
|
|
22
|
-
check_docker_running()
|
|
23
|
-
client = docker.from_env()
|
|
24
|
-
|
|
25
|
-
running_node_names = find_running_node_names(client)
|
|
26
|
-
|
|
27
|
-
header = "\nName" + (21 * " ") + "Status" + (10 * " ") + "System/User"
|
|
28
|
-
|
|
29
|
-
click.echo(header)
|
|
30
|
-
click.echo("-" * len(header))
|
|
31
|
-
|
|
32
|
-
running = Fore.GREEN + "Running" + Style.RESET_ALL
|
|
33
|
-
stopped = Fore.RED + "Not running" + Style.RESET_ALL
|
|
34
|
-
|
|
35
|
-
# system folders
|
|
36
|
-
configs, f1 = NodeContext.available_configurations(system_folders=True)
|
|
37
|
-
for config in configs:
|
|
38
|
-
status = (
|
|
39
|
-
running
|
|
40
|
-
if f"{APPNAME}-{config.name}-system" in running_node_names
|
|
41
|
-
else stopped
|
|
42
|
-
)
|
|
43
|
-
click.echo(f"{config.name:25}{status:25}System ")
|
|
44
|
-
|
|
45
|
-
# user folders
|
|
46
|
-
configs, f2 = NodeContext.available_configurations(system_folders=False)
|
|
47
|
-
for config in configs:
|
|
48
|
-
status = (
|
|
49
|
-
running
|
|
50
|
-
if f"{APPNAME}-{config.name}-user" in running_node_names
|
|
51
|
-
else stopped
|
|
52
|
-
)
|
|
53
|
-
click.echo(f"{config.name:25}{status:25}User ")
|
|
54
|
-
|
|
55
|
-
click.echo("-" * 53)
|
|
56
|
-
if len(f1) + len(f2):
|
|
57
|
-
warning(f"{Fore.RED}Failed imports: {len(f1) + len(f2)}{Style.RESET_ALL}")
|
|
16
|
+
get_configuration_list(InstanceType.NODE)
|
vantage6/cli/node/start.py
CHANGED
|
@@ -3,6 +3,7 @@ import click
|
|
|
3
3
|
from vantage6.common import info
|
|
4
4
|
from vantage6.common.globals import InstanceType
|
|
5
5
|
|
|
6
|
+
from vantage6.cli.common.attach import attach_logs
|
|
6
7
|
from vantage6.cli.common.decorator import click_insert_context
|
|
7
8
|
from vantage6.cli.common.start import (
|
|
8
9
|
helm_install,
|
|
@@ -10,12 +11,11 @@ from vantage6.cli.common.start import (
|
|
|
10
11
|
start_port_forward,
|
|
11
12
|
)
|
|
12
13
|
from vantage6.cli.common.utils import (
|
|
13
|
-
attach_logs,
|
|
14
14
|
create_directory_if_not_exists,
|
|
15
15
|
select_context_and_namespace,
|
|
16
16
|
)
|
|
17
17
|
from vantage6.cli.context.node import NodeContext
|
|
18
|
-
from vantage6.cli.globals import ChartName
|
|
18
|
+
from vantage6.cli.globals import ChartName, InfraComponentName
|
|
19
19
|
|
|
20
20
|
from vantage6.node.globals import DEFAULT_PROXY_SERVER_PORT
|
|
21
21
|
|
|
@@ -123,4 +123,12 @@ def cli_node_start(
|
|
|
123
123
|
)
|
|
124
124
|
|
|
125
125
|
if attach:
|
|
126
|
-
attach_logs(
|
|
126
|
+
attach_logs(
|
|
127
|
+
name,
|
|
128
|
+
instance_type=InstanceType.NODE,
|
|
129
|
+
infra_component=InfraComponentName.NODE,
|
|
130
|
+
system_folders=system_folders,
|
|
131
|
+
context=context,
|
|
132
|
+
namespace=namespace,
|
|
133
|
+
is_sandbox=ctx.is_sandbox,
|
|
134
|
+
)
|
vantage6/cli/node/stop.py
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import click
|
|
2
|
-
from kubernetes import client as k8s_client
|
|
2
|
+
from kubernetes import client as k8s_client
|
|
3
3
|
from kubernetes.client import ApiException
|
|
4
|
-
from kubernetes.config.config_exception import ConfigException
|
|
5
4
|
|
|
6
5
|
from vantage6.common import error, info, warning
|
|
7
6
|
from vantage6.common.globals import APPNAME, InstanceType
|
|
8
7
|
|
|
9
8
|
from vantage6.cli.common.stop import execute_stop, helm_uninstall, stop_port_forward
|
|
10
|
-
from vantage6.cli.common.utils import
|
|
9
|
+
from vantage6.cli.common.utils import (
|
|
10
|
+
extract_name_and_is_sandbox,
|
|
11
|
+
get_config_name_from_helm_release_name,
|
|
12
|
+
)
|
|
11
13
|
from vantage6.cli.context import get_context
|
|
12
14
|
from vantage6.cli.context.node import NodeContext
|
|
13
15
|
from vantage6.cli.globals import (
|
|
14
16
|
DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL,
|
|
15
17
|
InfraComponentName,
|
|
16
18
|
)
|
|
17
|
-
from vantage6.cli.node.task_cleanup import delete_job_related_pods
|
|
19
|
+
from vantage6.cli.node.common.task_cleanup import delete_job_related_pods
|
|
20
|
+
from vantage6.cli.utils_kubernetes import create_kubernetes_apis_with_ssl_handling
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
@click.command()
|
|
@@ -50,6 +53,7 @@ def cli_node_stop(
|
|
|
50
53
|
"""
|
|
51
54
|
Stop one or all running nodes.
|
|
52
55
|
"""
|
|
56
|
+
name, is_sandbox = extract_name_and_is_sandbox(name, is_sandbox)
|
|
53
57
|
execute_stop(
|
|
54
58
|
stop_function=_stop_node,
|
|
55
59
|
stop_function_args={"system_folders": system_folders, "is_sandbox": is_sandbox},
|
|
@@ -142,18 +146,12 @@ def cleanup_task_jobs(
|
|
|
142
146
|
error("Either all_nodes or node_ctx must be given to cleanup task jobs")
|
|
143
147
|
return False
|
|
144
148
|
|
|
145
|
-
# Load Kubernetes configuration
|
|
149
|
+
# Load Kubernetes configuration with SSL handling
|
|
146
150
|
try:
|
|
147
|
-
|
|
148
|
-
except
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
except ConfigException as exc:
|
|
152
|
-
error(f"Failed to load Kubernetes configuration: {exc}")
|
|
153
|
-
return False
|
|
154
|
-
|
|
155
|
-
core_api = k8s_client.CoreV1Api()
|
|
156
|
-
batch_api = k8s_client.BatchV1Api()
|
|
151
|
+
core_api, batch_api = create_kubernetes_apis_with_ssl_handling()
|
|
152
|
+
except RuntimeError as exc:
|
|
153
|
+
error(f"Failed to load Kubernetes configuration: {exc}")
|
|
154
|
+
return False
|
|
157
155
|
|
|
158
156
|
jobs = _get_jobs(namespace, batch_api)
|
|
159
157
|
|
vantage6/cli/node/version.py
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import click
|
|
2
|
-
import
|
|
3
|
-
|
|
2
|
+
from kubernetes import config as k8s_config
|
|
3
|
+
from kubernetes.config.config_exception import ConfigException
|
|
4
|
+
from kubernetes.stream import stream
|
|
4
5
|
|
|
5
|
-
from vantage6.common import error
|
|
6
|
-
from vantage6.common.
|
|
7
|
-
from vantage6.common.globals import APPNAME
|
|
6
|
+
from vantage6.common import error, info
|
|
7
|
+
from vantage6.common.globals import APPNAME, InstanceType
|
|
8
8
|
|
|
9
9
|
from vantage6.cli import __version__
|
|
10
|
+
from vantage6.cli.common.utils import select_context_and_namespace
|
|
11
|
+
from vantage6.cli.common.version import get_and_select_ctx
|
|
10
12
|
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
11
|
-
from vantage6.cli.
|
|
13
|
+
from vantage6.cli.utils_kubernetes import get_core_api_with_ssl_handling
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
@click.command()
|
|
@@ -27,36 +29,97 @@ from vantage6.cli.node.common import find_running_node_names
|
|
|
27
29
|
help="Search for configuration in user folders rather than "
|
|
28
30
|
"system folders. This is the default",
|
|
29
31
|
)
|
|
30
|
-
|
|
32
|
+
@click.option("--context", default=None, help="Kubernetes context to use")
|
|
33
|
+
@click.option("--namespace", default=None, help="Kubernetes namespace to use")
|
|
34
|
+
@click.option(
|
|
35
|
+
"--sandbox", "is_sandbox", flag_value=True, help="Is this a sandbox environment?"
|
|
36
|
+
)
|
|
37
|
+
def cli_node_version(
|
|
38
|
+
name: str, system_folders: bool, context: str, namespace: str, is_sandbox: bool
|
|
39
|
+
) -> None:
|
|
31
40
|
"""
|
|
32
41
|
Returns current version of a vantage6 node.
|
|
33
42
|
"""
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
context, namespace = select_context_and_namespace(
|
|
44
|
+
context=context,
|
|
45
|
+
namespace=namespace,
|
|
46
|
+
)
|
|
47
|
+
ctx = get_and_select_ctx(
|
|
48
|
+
InstanceType.NODE, name, system_folders, context, namespace, is_sandbox
|
|
49
|
+
)
|
|
50
|
+
version = _get_node_version_from_k8s(ctx.helm_release_name, namespace, context)
|
|
51
|
+
info("")
|
|
52
|
+
info(f"Node version: {version}")
|
|
53
|
+
info(f"CLI version: {__version__}")
|
|
36
54
|
|
|
37
|
-
running_node_names = find_running_node_names(client)
|
|
38
55
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
def _get_node_version_from_k8s(
|
|
57
|
+
helm_release: str,
|
|
58
|
+
namespace: str,
|
|
59
|
+
context: str,
|
|
60
|
+
) -> str:
|
|
61
|
+
"""
|
|
62
|
+
Runs 'vnode-local version' in the node pod belonging to the Helm release.
|
|
63
|
+
"""
|
|
64
|
+
pod = _get_pod_name_for_helm_release(helm_release, namespace, context)
|
|
65
|
+
output = _exec_pod_command(
|
|
66
|
+
pod_name=pod,
|
|
67
|
+
namespace=namespace,
|
|
68
|
+
command=["vnode-local", "version"],
|
|
69
|
+
)
|
|
70
|
+
return output.strip()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _get_pod_name_for_helm_release(
|
|
74
|
+
helm_release: str,
|
|
75
|
+
namespace: str,
|
|
76
|
+
context: str,
|
|
77
|
+
) -> str:
|
|
78
|
+
"""
|
|
79
|
+
Returns the first pod name for a given Helm release in a namespace.
|
|
80
|
+
Looks up pods using the standard Helm label 'app.kubernetes.io/instance'.
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
# Load kubeconfig (context optional). Falls back to in-cluster if not available.
|
|
46
84
|
try:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
85
|
+
k8s_config.load_kube_config(context=context) # desktop/dev
|
|
86
|
+
except ConfigException:
|
|
87
|
+
k8s_config.load_incluster_config() # in-cluster
|
|
88
|
+
except ConfigException as exc:
|
|
89
|
+
raise RuntimeError(f"Failed to load Kubernetes config: {exc}") from exc
|
|
90
|
+
|
|
91
|
+
core = get_core_api_with_ssl_handling()
|
|
92
|
+
selector = f"app={APPNAME}-node,release={helm_release}"
|
|
93
|
+
pods = core.list_namespaced_pod(namespace=namespace, label_selector=selector).items
|
|
94
|
+
if not pods:
|
|
95
|
+
error(f"No pods found for Helm release '{helm_release}' in ns '{namespace}'")
|
|
96
|
+
exit(1)
|
|
97
|
+
# Prefer a Ready pod
|
|
98
|
+
for p in pods:
|
|
99
|
+
for cond in p.status.conditions or []:
|
|
100
|
+
if cond.type == "Ready" and cond.status == "True":
|
|
101
|
+
return p.metadata.name
|
|
102
|
+
# Fallback to first pod
|
|
103
|
+
return pods[0].metadata.name
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _exec_pod_command(
|
|
107
|
+
pod_name: str,
|
|
108
|
+
namespace: str,
|
|
109
|
+
command: list[str],
|
|
110
|
+
) -> str:
|
|
111
|
+
"""
|
|
112
|
+
Executes a command inside the specified pod (and optional container) and returns stdout.
|
|
113
|
+
"""
|
|
114
|
+
core = get_core_api_with_ssl_handling()
|
|
115
|
+
resp = stream(
|
|
116
|
+
core.connect_get_namespaced_pod_exec,
|
|
117
|
+
pod_name,
|
|
118
|
+
namespace,
|
|
119
|
+
command=command,
|
|
120
|
+
stderr=True,
|
|
121
|
+
stdin=False,
|
|
122
|
+
stdout=True,
|
|
123
|
+
tty=False,
|
|
124
|
+
)
|
|
125
|
+
return resp
|
|
@@ -49,7 +49,10 @@ class BaseSandboxConfigManager:
|
|
|
49
49
|
return {}
|
|
50
50
|
|
|
51
51
|
def _create_and_get_data_dir(
|
|
52
|
-
self,
|
|
52
|
+
self,
|
|
53
|
+
instance_type: InstanceType,
|
|
54
|
+
is_data_folder: bool = False,
|
|
55
|
+
node_name: str | None = None,
|
|
53
56
|
) -> Path:
|
|
54
57
|
"""
|
|
55
58
|
Create and get the data directory.
|
|
@@ -61,6 +64,8 @@ class BaseSandboxConfigManager:
|
|
|
61
64
|
is_data_folder: bool
|
|
62
65
|
Whether or not to create the data folder or a config folder. This is only
|
|
63
66
|
used for node databases. Default is False.
|
|
67
|
+
node_name: str | None
|
|
68
|
+
Name of the node. Only used if is_data_folder is True.
|
|
64
69
|
|
|
65
70
|
Returns
|
|
66
71
|
-------
|
|
@@ -83,7 +88,10 @@ class BaseSandboxConfigManager:
|
|
|
83
88
|
data_dir = main_data_dir / self.server_name / "store"
|
|
84
89
|
elif instance_type == InstanceType.NODE:
|
|
85
90
|
if is_data_folder:
|
|
86
|
-
|
|
91
|
+
if node_name:
|
|
92
|
+
last_subfolder = f"data_{node_name}"
|
|
93
|
+
else:
|
|
94
|
+
last_subfolder = "data"
|
|
87
95
|
else:
|
|
88
96
|
last_subfolder = "node"
|
|
89
97
|
data_dir = main_data_dir / self.server_name / last_subfolder
|
|
@@ -118,7 +118,7 @@ class CoreSandboxConfigManager(BaseSandboxConfigManager):
|
|
|
118
118
|
# TODO make this configurable
|
|
119
119
|
"image": (
|
|
120
120
|
self.server_image
|
|
121
|
-
or "harbor2.vantage6.ai/infrastructure/server:5.0.
|
|
121
|
+
or "harbor2.vantage6.ai/infrastructure/server:5.0.0a37"
|
|
122
122
|
),
|
|
123
123
|
"algorithm_stores": [
|
|
124
124
|
{
|
|
@@ -156,7 +156,7 @@ class CoreSandboxConfigManager(BaseSandboxConfigManager):
|
|
|
156
156
|
# TODO: v5+ set to latest v5 image
|
|
157
157
|
# TODO: make this configurable
|
|
158
158
|
"image": (
|
|
159
|
-
self.ui_image or "harbor2.vantage6.ai/infrastructure/ui:5.0.
|
|
159
|
+
self.ui_image or "harbor2.vantage6.ai/infrastructure/ui:5.0.0a37"
|
|
160
160
|
),
|
|
161
161
|
},
|
|
162
162
|
}
|
|
@@ -231,7 +231,7 @@ class CoreSandboxConfigManager(BaseSandboxConfigManager):
|
|
|
231
231
|
"vantage6ServerUri": f"{HTTP_LOCALHOST}:{self.server_port}",
|
|
232
232
|
"image": (
|
|
233
233
|
self.store_image
|
|
234
|
-
or "harbor2.vantage6.ai/infrastructure/algorithm-store:5.0.
|
|
234
|
+
or "harbor2.vantage6.ai/infrastructure/algorithm-store:5.0.0a37"
|
|
235
235
|
),
|
|
236
236
|
"keycloakUrl": (
|
|
237
237
|
f"http://vantage6-{self.server_name}-auth-user-auth-keycloak."
|