vantage6 5.0.0a22__py3-none-any.whl → 5.0.0a29__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of vantage6 might be problematic. Click here for more details.
- tests_cli/test_client_script.py +23 -0
- tests_cli/test_server_cli.py +7 -6
- tests_cli/test_wizard.py +7 -7
- vantage6/cli/__build__ +1 -1
- vantage6/cli/algorithm/generate_algorithm_json.py +531 -0
- vantage6/cli/algostore/list.py +2 -1
- vantage6/cli/algostore/start.py +6 -6
- vantage6/cli/algostore/stop.py +3 -2
- vantage6/cli/cli.py +25 -0
- vantage6/cli/common/decorator.py +3 -1
- vantage6/cli/common/start.py +221 -12
- vantage6/cli/common/stop.py +90 -0
- vantage6/cli/common/utils.py +15 -20
- vantage6/cli/config.py +260 -0
- vantage6/cli/configuration_manager.py +8 -14
- vantage6/cli/configuration_wizard.py +66 -111
- vantage6/cli/context/__init__.py +2 -1
- vantage6/cli/context/algorithm_store.py +10 -7
- vantage6/cli/context/node.py +38 -54
- vantage6/cli/context/server.py +36 -5
- vantage6/cli/dev/create.py +88 -29
- vantage6/cli/dev/data/km_dataset.csv +2401 -0
- vantage6/cli/dev/remove.py +99 -98
- vantage6/cli/globals.py +24 -4
- vantage6/cli/node/common/__init__.py +6 -5
- vantage6/cli/node/new.py +4 -3
- vantage6/cli/node/remove.py +4 -2
- vantage6/cli/node/start.py +33 -42
- vantage6/cli/prometheus/monitoring_manager.py +146 -0
- vantage6/cli/prometheus/prometheus.yml +5 -0
- vantage6/cli/server/files.py +4 -2
- vantage6/cli/server/import_.py +7 -7
- vantage6/cli/server/list.py +2 -1
- vantage6/cli/server/new.py +25 -6
- vantage6/cli/server/shell.py +5 -4
- vantage6/cli/server/start.py +44 -213
- vantage6/cli/server/stop.py +36 -105
- vantage6/cli/server/version.py +5 -4
- vantage6/cli/template/algo_store_config.j2 +0 -1
- vantage6/cli/template/node_config.j2 +3 -1
- vantage6/cli/template/server_import_config.j2 +0 -2
- vantage6/cli/test/algo_test_scripts/algo_test_arguments.py +29 -0
- vantage6/cli/test/algo_test_scripts/algo_test_script.py +92 -0
- vantage6/cli/test/client_script.py +151 -0
- vantage6/cli/test/common/diagnostic_runner.py +2 -2
- vantage6/cli/test/feature_tester.py +5 -2
- vantage6/cli/use/context.py +46 -0
- vantage6/cli/use/namespace.py +55 -0
- vantage6/cli/utils.py +70 -4
- {vantage6-5.0.0a22.dist-info → vantage6-5.0.0a29.dist-info}/METADATA +15 -11
- vantage6-5.0.0a29.dist-info/RECORD +84 -0
- {vantage6-5.0.0a22.dist-info → vantage6-5.0.0a29.dist-info}/WHEEL +1 -1
- vantage6-5.0.0a22.dist-info/RECORD +0 -72
- {vantage6-5.0.0a22.dist-info → vantage6-5.0.0a29.dist-info}/entry_points.txt +0 -0
- {vantage6-5.0.0a22.dist-info → vantage6-5.0.0a29.dist-info}/top_level.txt +0 -0
vantage6/cli/dev/remove.py
CHANGED
|
@@ -1,111 +1,112 @@
|
|
|
1
|
-
import subprocess
|
|
2
|
-
import itertools
|
|
3
|
-
from shutil import rmtree
|
|
4
|
-
from pathlib import Path
|
|
1
|
+
# import subprocess
|
|
2
|
+
# import itertools
|
|
3
|
+
# from shutil import rmtree
|
|
4
|
+
# from pathlib import Path
|
|
5
5
|
|
|
6
|
-
import click
|
|
7
|
-
import docker
|
|
8
|
-
from colorama import Fore, Style
|
|
6
|
+
# import click
|
|
7
|
+
# import docker
|
|
8
|
+
# from colorama import Fore, Style
|
|
9
9
|
|
|
10
|
-
from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
|
|
11
|
-
from vantage6.common import info, error
|
|
12
|
-
from vantage6.common.globals import APPNAME
|
|
13
|
-
from vantage6.cli.context.server import ServerContext
|
|
14
|
-
from vantage6.cli.context.node import NodeContext
|
|
15
|
-
from vantage6.cli.server.remove import cli_server_remove
|
|
16
|
-
from vantage6.cli.utils import remove_file
|
|
17
|
-
from vantage6.common.globals import InstanceType
|
|
18
|
-
from vantage6.cli.dev.utils import get_dev_server_context
|
|
10
|
+
# from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
|
|
11
|
+
# from vantage6.common import info, error
|
|
12
|
+
# from vantage6.common.globals import APPNAME
|
|
13
|
+
# from vantage6.cli.context.server import ServerContext
|
|
14
|
+
# from vantage6.cli.context.node import NodeContext
|
|
15
|
+
# from vantage6.cli.server.remove import cli_server_remove
|
|
16
|
+
# from vantage6.cli.utils import remove_file
|
|
17
|
+
# from vantage6.common.globals import InstanceType
|
|
19
18
|
|
|
19
|
+
# # from vantage6.cli.dev.utils import get_dev_server_context
|
|
20
20
|
|
|
21
|
-
@click.command()
|
|
22
|
-
@click.option("-n", "--name", default=None, help="Name of the configuration.")
|
|
23
|
-
@click.option(
|
|
24
|
-
"-c",
|
|
25
|
-
"--config",
|
|
26
|
-
default=None,
|
|
27
|
-
help="Path to configuration-file; overrides --name",
|
|
28
|
-
)
|
|
29
|
-
@click.pass_context
|
|
30
|
-
def remove_demo_network(
|
|
31
|
-
click_ctx: click.Context, name: str | None, config: str | None
|
|
32
|
-
) -> None:
|
|
33
|
-
"""Remove all related demo network files and folders.
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
# @click.command()
|
|
23
|
+
# @click.option("-n", "--name", default=None, help="Name of the configuration.")
|
|
24
|
+
# @click.option(
|
|
25
|
+
# "-c",
|
|
26
|
+
# "--config",
|
|
27
|
+
# default=None,
|
|
28
|
+
# help="Path to configuration-file; overrides --name",
|
|
29
|
+
# )
|
|
30
|
+
# @click.pass_context
|
|
31
|
+
# def remove_demo_network(
|
|
32
|
+
# click_ctx: click.Context, name: str | None, config: str | None
|
|
33
|
+
# ) -> None:
|
|
34
|
+
# """Remove all related demo network files and folders.
|
|
39
35
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
)
|
|
45
|
-
running_server_names = [server.name for server in running_servers]
|
|
46
|
-
container_name = f"{APPNAME}-{name}-user-{InstanceType.SERVER.value}"
|
|
47
|
-
if container_name in running_server_names:
|
|
48
|
-
error(
|
|
49
|
-
f"Server {Fore.RED}{name}{Style.RESET_ALL} is still running! First stop "
|
|
50
|
-
"the network with 'v6 dev stop-demo-network'."
|
|
51
|
-
)
|
|
52
|
-
return
|
|
36
|
+
# Select a server configuration to remove that server and the nodes attached
|
|
37
|
+
# to it.
|
|
38
|
+
# """
|
|
39
|
+
# ctx = get_dev_server_context(config, name)
|
|
53
40
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
41
|
+
# # check that the server is not running
|
|
42
|
+
# client = docker.from_env()
|
|
43
|
+
# running_servers = client.containers.list(
|
|
44
|
+
# filters={"label": f"{APPNAME}-type={InstanceType.SERVER}"}
|
|
45
|
+
# )
|
|
46
|
+
# running_server_names = [server.name for server in running_servers]
|
|
47
|
+
# container_name = f"{APPNAME}-{name}-user-{InstanceType.SERVER}"
|
|
48
|
+
# if container_name in running_server_names:
|
|
49
|
+
# error(
|
|
50
|
+
# f"Server {Fore.RED}{name}{Style.RESET_ALL} is still running! First stop "
|
|
51
|
+
# "the network with 'v6 dev stop-demo-network'."
|
|
52
|
+
# )
|
|
53
|
+
# return
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
import_config_to_del = Path(server_configs["dev"]) / f"{ctx.name}.yaml"
|
|
65
|
-
remove_file(import_config_to_del, "import_configuration")
|
|
55
|
+
# # remove the server
|
|
56
|
+
# for handler in itertools.chain(ctx.log.handlers, ctx.log.root.handlers):
|
|
57
|
+
# handler.close()
|
|
58
|
+
# click_ctx.invoke(cli_server_remove, ctx=ctx, force=True)
|
|
66
59
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
# # removing the server import config
|
|
61
|
+
# info("Deleting demo import config file")
|
|
62
|
+
# server_configs = ServerContext.instance_folders(
|
|
63
|
+
# InstanceType.SERVER, ctx.name, system_folders=False
|
|
64
|
+
# )
|
|
65
|
+
# import_config_to_del = Path(server_configs["dev"]) / f"{ctx.name}.yaml"
|
|
66
|
+
# remove_file(import_config_to_del, "import_configuration")
|
|
74
67
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
68
|
+
# # also remove the server folder
|
|
69
|
+
# server_configs = ServerContext.instance_folders(
|
|
70
|
+
# InstanceType.SERVER, ctx.name, system_folders=False
|
|
71
|
+
# )
|
|
72
|
+
# server_folder = server_configs["data"]
|
|
73
|
+
# if server_folder.is_dir():
|
|
74
|
+
# rmtree(server_folder)
|
|
82
75
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
f"{ctx.name}_store",
|
|
91
|
-
"--force",
|
|
92
|
-
"--user",
|
|
93
|
-
]
|
|
94
|
-
)
|
|
76
|
+
# # remove the store folder
|
|
77
|
+
# store_configs = AlgorithmStoreContext.instance_folders(
|
|
78
|
+
# InstanceType.ALGORITHM_STORE, f"{ctx.name}_store", system_folders=False
|
|
79
|
+
# )
|
|
80
|
+
# store_folder = store_configs["data"]
|
|
81
|
+
# if store_folder.is_dir():
|
|
82
|
+
# rmtree(store_folder)
|
|
95
83
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
84
|
+
# # remove the store config file
|
|
85
|
+
# subprocess.run(
|
|
86
|
+
# [
|
|
87
|
+
# "v6",
|
|
88
|
+
# "algorithm-store",
|
|
89
|
+
# "remove",
|
|
90
|
+
# "-n",
|
|
91
|
+
# f"{ctx.name}_store",
|
|
92
|
+
# "--force",
|
|
93
|
+
# "--user",
|
|
94
|
+
# ]
|
|
95
|
+
# )
|
|
108
96
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
97
|
+
# # remove the nodes
|
|
98
|
+
# configs, _ = NodeContext.available_configurations(system_folders=False)
|
|
99
|
+
# node_names = [
|
|
100
|
+
# config.name for config in configs if config.name.startswith(f"{ctx.name}_node_")
|
|
101
|
+
# ]
|
|
102
|
+
# for name in node_names:
|
|
103
|
+
# node_ctx = NodeContext(name, False)
|
|
104
|
+
# for handler in itertools.chain(
|
|
105
|
+
# node_ctx.log.handlers, node_ctx.log.root.handlers
|
|
106
|
+
# ):
|
|
107
|
+
# handler.close()
|
|
108
|
+
# subprocess.run(["v6", "node", "remove", "-n", name, "--user", "--force"])
|
|
109
|
+
|
|
110
|
+
# # remove data files attached to the network
|
|
111
|
+
# data_dirs_nodes = NodeContext.instance_folders("node", "", False)["dev"]
|
|
112
|
+
# rmtree(Path(data_dirs_nodes / ctx.name))
|
vantage6/cli/globals.py
CHANGED
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
This module contains global variables that are used throughout the CLI.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from enum import Enum
|
|
6
5
|
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from vantage6.common.enum import StrEnumBase
|
|
7
8
|
from vantage6.common.globals import APPNAME
|
|
8
9
|
|
|
10
|
+
#
|
|
11
|
+
# CLI SETTINGS
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
DEFAULT_CLI_CONFIG_FOLDER = Path.home() / ".vantage6"
|
|
15
|
+
DEFAULT_CLI_CONFIG_FILE = DEFAULT_CLI_CONFIG_FOLDER / "config.yaml"
|
|
16
|
+
|
|
9
17
|
#
|
|
10
18
|
# SERVER SETTINGS
|
|
11
19
|
#
|
|
@@ -44,22 +52,34 @@ DIAGNOSTICS_IMAGE = "harbor2.vantage6.ai/algorithms/diagnostic"
|
|
|
44
52
|
# Address of community algorithm store
|
|
45
53
|
COMMUNITY_STORE = "https://store.cotopaxi.vantage6.ai/api"
|
|
46
54
|
|
|
55
|
+
DEFAULT_PROMETHEUS_IMAGE = "prom/prometheus"
|
|
56
|
+
PROMETHEUS_CONFIG = "prometheus.yml"
|
|
57
|
+
PROMETHEUS_DIR = "prometheus"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# datasets included in the nodes of the dev network
|
|
61
|
+
class DefaultDatasets(StrEnumBase):
|
|
62
|
+
"""Enum containing default datasets"""
|
|
63
|
+
|
|
64
|
+
OLYMPIC_ATHLETES = "olympic_athletes_2016.csv"
|
|
65
|
+
KAPLAN_MEIER_TEST = "km_dataset.csv"
|
|
66
|
+
|
|
47
67
|
|
|
48
|
-
class ServerType(
|
|
68
|
+
class ServerType(StrEnumBase):
|
|
49
69
|
"""Enum containing server types"""
|
|
50
70
|
|
|
51
71
|
V6SERVER = "server"
|
|
52
72
|
ALGORITHM_STORE = "algorithm-store"
|
|
53
73
|
|
|
54
74
|
|
|
55
|
-
class ServerGlobals(
|
|
75
|
+
class ServerGlobals(StrEnumBase):
|
|
56
76
|
"""Enum containing server environment variables"""
|
|
57
77
|
|
|
58
78
|
DB_URI_ENV_VAR = "VANTAGE6_DB_URI"
|
|
59
79
|
CONFIG_NAME_ENV_VAR = "VANTAGE6_CONFIG_NAME"
|
|
60
80
|
|
|
61
81
|
|
|
62
|
-
class AlgoStoreGlobals(
|
|
82
|
+
class AlgoStoreGlobals(StrEnumBase):
|
|
63
83
|
"""Enum containing algorithm store environment variables"""
|
|
64
84
|
|
|
65
85
|
DB_URI_ENV_VAR = "VANTAGE6_ALGO_STORE_DB_URI"
|
|
@@ -3,15 +3,17 @@ Common functions that are used in node CLI commands
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
+
|
|
6
7
|
import docker
|
|
7
8
|
from colorama import Fore, Style
|
|
8
9
|
|
|
9
|
-
from vantage6.common import error, info
|
|
10
|
+
from vantage6.common import debug, error, info
|
|
10
11
|
from vantage6.common.globals import APPNAME, InstanceType, RequiredNodeEnvVars
|
|
12
|
+
|
|
11
13
|
from vantage6.client import UserClient
|
|
12
14
|
|
|
13
|
-
from vantage6.cli.context.node import NodeContext
|
|
14
15
|
from vantage6.cli.configuration_wizard import select_configuration_questionaire
|
|
16
|
+
from vantage6.cli.context.node import NodeContext
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
def create_client(ctx: NodeContext) -> UserClient:
|
|
@@ -86,8 +88,7 @@ def select_node(name: str, system_folders: bool) -> tuple[str, str]:
|
|
|
86
88
|
# raise error if config could not be found
|
|
87
89
|
if not NodeContext.config_exists(name, system_folders):
|
|
88
90
|
error(
|
|
89
|
-
f"The configuration {Fore.RED}{name}{Style.RESET_ALL} could "
|
|
90
|
-
f"not be found."
|
|
91
|
+
f"The configuration {Fore.RED}{name}{Style.RESET_ALL} could not be found."
|
|
91
92
|
)
|
|
92
93
|
exit(1)
|
|
93
94
|
return name
|
|
@@ -108,6 +109,6 @@ def find_running_node_names(client: docker.DockerClient) -> list[str]:
|
|
|
108
109
|
List of names of running nodes
|
|
109
110
|
"""
|
|
110
111
|
running_nodes = client.containers.list(
|
|
111
|
-
filters={"label": f"{APPNAME}-type={InstanceType.NODE
|
|
112
|
+
filters={"label": f"{APPNAME}-type={InstanceType.NODE}"}
|
|
112
113
|
)
|
|
113
114
|
return [node.name for node in running_nodes]
|
vantage6/cli/node/new.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import click
|
|
2
2
|
from colorama import Fore, Style
|
|
3
3
|
|
|
4
|
-
from vantage6.common import error, info
|
|
4
|
+
from vantage6.common import ensure_config_dir_writable, error, info
|
|
5
|
+
from vantage6.common.globals import InstanceType
|
|
6
|
+
|
|
7
|
+
from vantage6.cli.configuration_wizard import configuration_wizard
|
|
5
8
|
from vantage6.cli.context.node import NodeContext
|
|
6
9
|
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
7
|
-
from vantage6.cli.configuration_wizard import configuration_wizard
|
|
8
10
|
from vantage6.cli.utils import check_config_name_allowed, prompt_config_name
|
|
9
|
-
from vantage6.common.globals import InstanceType
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@click.command()
|
vantage6/cli/node/remove.py
CHANGED
|
@@ -14,14 +14,16 @@ from vantage6.common import (
|
|
|
14
14
|
)
|
|
15
15
|
from vantage6.common.globals import APPNAME
|
|
16
16
|
|
|
17
|
-
from vantage6.common.globals import VPN_CONFIG_FILE
|
|
18
|
-
|
|
19
17
|
|
|
20
18
|
from vantage6.cli.context.node import NodeContext
|
|
21
19
|
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
22
20
|
from vantage6.cli.utils import check_if_docker_daemon_is_running, remove_file
|
|
23
21
|
from vantage6.cli.node.common import select_node, find_running_node_names
|
|
24
22
|
|
|
23
|
+
# TODO v5+ remove this - just a dummy to prevent import issues from v4 CLI
|
|
24
|
+
# from vantage6.common.globals import VPN_CONFIG_FILE
|
|
25
|
+
VPN_CONFIG_FILE = "vpn.conf"
|
|
26
|
+
|
|
25
27
|
|
|
26
28
|
@click.command()
|
|
27
29
|
@click.option("-n", "--name", default=None, help="Configuration name")
|
vantage6/cli/node/start.py
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
import time
|
|
1
3
|
from pathlib import Path
|
|
2
4
|
from threading import Thread
|
|
3
|
-
import time
|
|
4
|
-
import os.path
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
7
|
import docker
|
|
8
|
-
|
|
9
8
|
from colorama import Fore, Style
|
|
10
9
|
|
|
11
|
-
from vantage6.
|
|
12
|
-
from vantage6.common import
|
|
10
|
+
from vantage6.common import debug, error, info, warning
|
|
11
|
+
from vantage6.common.dataclass import TaskDB
|
|
12
|
+
from vantage6.common.docker.addons import (
|
|
13
|
+
check_docker_running,
|
|
14
|
+
remove_container_if_exists,
|
|
15
|
+
)
|
|
13
16
|
from vantage6.common.globals import (
|
|
14
17
|
APPNAME,
|
|
15
18
|
DEFAULT_DOCKER_REGISTRY,
|
|
@@ -17,17 +20,14 @@ from vantage6.common.globals import (
|
|
|
17
20
|
DEFAULT_NODE_IMAGE_WO_TAG,
|
|
18
21
|
InstanceType,
|
|
19
22
|
)
|
|
20
|
-
from vantage6.common.docker.addons import (
|
|
21
|
-
remove_container_if_exists,
|
|
22
|
-
check_docker_running,
|
|
23
|
-
)
|
|
24
23
|
|
|
24
|
+
from vantage6.cli import __version__
|
|
25
25
|
from vantage6.cli.common.decorator import click_insert_context
|
|
26
|
-
from vantage6.cli.
|
|
26
|
+
from vantage6.cli.common.start import pull_infra_image
|
|
27
27
|
from vantage6.cli.common.utils import print_log_worker
|
|
28
|
+
from vantage6.cli.context.node import NodeContext
|
|
28
29
|
from vantage6.cli.node.common import create_client
|
|
29
30
|
from vantage6.cli.utils import check_config_name_allowed
|
|
30
|
-
from vantage6.cli import __version__
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@click.command()
|
|
@@ -40,18 +40,17 @@ from vantage6.cli import __version__
|
|
|
40
40
|
@click.option(
|
|
41
41
|
"--force-db-mount",
|
|
42
42
|
is_flag=True,
|
|
43
|
-
help="Always mount node databases; skip the check if they are
|
|
43
|
+
help="Always mount node databases; skip the check if they are existing files.",
|
|
44
44
|
)
|
|
45
45
|
@click.option(
|
|
46
46
|
"--attach/--detach",
|
|
47
47
|
default=False,
|
|
48
|
-
help="Show node logs on the current console after starting the
|
|
48
|
+
help="Show node logs on the current console after starting the node",
|
|
49
49
|
)
|
|
50
50
|
@click.option(
|
|
51
51
|
"--mount-src",
|
|
52
52
|
default="",
|
|
53
|
-
help="Override vantage6 source code in container with the source"
|
|
54
|
-
" code in this path",
|
|
53
|
+
help="Override vantage6 source code in container with the source code in this path",
|
|
55
54
|
)
|
|
56
55
|
@click_insert_context(InstanceType.NODE, include_name=True, include_system_folders=True)
|
|
57
56
|
def cli_node_start(
|
|
@@ -78,7 +77,7 @@ def cli_node_start(
|
|
|
78
77
|
|
|
79
78
|
# check that this node is not already running
|
|
80
79
|
running_nodes = docker_client.containers.list(
|
|
81
|
-
filters={"label": f"{APPNAME}-type={InstanceType.NODE
|
|
80
|
+
filters={"label": f"{APPNAME}-type={InstanceType.NODE}"}
|
|
82
81
|
)
|
|
83
82
|
|
|
84
83
|
suffix = "system" if system_folders else "user"
|
|
@@ -116,9 +115,7 @@ def cli_node_start(
|
|
|
116
115
|
f":{major_minor}"
|
|
117
116
|
)
|
|
118
117
|
except Exception:
|
|
119
|
-
warning(
|
|
120
|
-
"Could not determine server version. Using default " "node image"
|
|
121
|
-
)
|
|
118
|
+
warning("Could not determine server version. Using default node image")
|
|
122
119
|
|
|
123
120
|
if major_minor and not __version__.startswith(major_minor):
|
|
124
121
|
warning(
|
|
@@ -213,29 +210,25 @@ def cli_node_start(
|
|
|
213
210
|
|
|
214
211
|
# only mount the DB if it is a file
|
|
215
212
|
info("Setting up databases")
|
|
216
|
-
|
|
217
|
-
for
|
|
213
|
+
dbs = [TaskDB.from_dict(db) for db in ctx.databases]
|
|
214
|
+
for db in dbs:
|
|
218
215
|
# check that label contains only valid characters
|
|
219
|
-
if not label.isidentifier():
|
|
216
|
+
if not db.label.isidentifier():
|
|
220
217
|
error(
|
|
221
|
-
f"Database label {Fore.RED}{label}{Style.RESET_ALL} contains"
|
|
218
|
+
f"Database label {Fore.RED}{db.label}{Style.RESET_ALL} contains"
|
|
222
219
|
" invalid characters. Only letters, numbers, and underscores"
|
|
223
220
|
" are allowed, and it cannot start with a number."
|
|
224
221
|
)
|
|
225
222
|
exit(1)
|
|
226
223
|
|
|
227
|
-
db_config = get_database_config(ctx.databases, label)
|
|
228
|
-
uri = db_config["uri"]
|
|
229
|
-
db_type = db_config["type"]
|
|
230
|
-
|
|
231
224
|
info(
|
|
232
|
-
f" Processing {Fore.GREEN}{
|
|
233
|
-
f"{Fore.GREEN}{label}:{uri}{Style.RESET_ALL}"
|
|
225
|
+
f" Processing {Fore.GREEN}{db.type}{Style.RESET_ALL} database "
|
|
226
|
+
f"{Fore.GREEN}{db.label}:{db.uri}{Style.RESET_ALL}"
|
|
234
227
|
)
|
|
235
|
-
label_capitals = label.upper()
|
|
228
|
+
label_capitals = db.label.upper()
|
|
236
229
|
|
|
237
230
|
try:
|
|
238
|
-
db_file_exists = Path(uri).exists()
|
|
231
|
+
db_file_exists = Path(db.uri).exists()
|
|
239
232
|
except Exception:
|
|
240
233
|
# If the database uri cannot be parsed, it is definitely not a
|
|
241
234
|
# file. In case of http servers or sql servers, checking the path
|
|
@@ -243,22 +236,22 @@ def cli_node_start(
|
|
|
243
236
|
# we catch all exceptions here.
|
|
244
237
|
db_file_exists = False
|
|
245
238
|
|
|
246
|
-
if
|
|
239
|
+
if db.type.is_file_based() and not db_file_exists:
|
|
247
240
|
error(
|
|
248
|
-
f"Database {Fore.RED}{uri}{Style.RESET_ALL} not found. Databases of "
|
|
249
|
-
f"type '{
|
|
250
|
-
"your node configuration file."
|
|
241
|
+
f"Database {Fore.RED}{db.uri}{Style.RESET_ALL} not found. Databases of "
|
|
242
|
+
f"type '{db.type}' must be present on the harddrive. Please "
|
|
243
|
+
"update your node configuration file."
|
|
251
244
|
)
|
|
252
245
|
exit(1)
|
|
253
246
|
|
|
254
247
|
if not db_file_exists and not force_db_mount:
|
|
255
248
|
debug(" - non file-based database added")
|
|
256
|
-
env[f"{label_capitals}_DATABASE_URI"] = uri
|
|
249
|
+
env[f"{label_capitals}_DATABASE_URI"] = db.uri
|
|
257
250
|
else:
|
|
258
251
|
debug(" - file-based database added")
|
|
259
|
-
suffix = Path(uri).suffix
|
|
260
|
-
env[f"{label_capitals}_DATABASE_URI"] = f"{label}{suffix}"
|
|
261
|
-
mounts.append((f"/mnt/{label}{suffix}", str(uri)))
|
|
252
|
+
suffix = Path(db.uri).suffix
|
|
253
|
+
env[f"{label_capitals}_DATABASE_URI"] = f"{db.label}{suffix}"
|
|
254
|
+
mounts.append((f"/mnt/{db.label}{suffix}", str(db.uri)))
|
|
262
255
|
|
|
263
256
|
system_folders_option = "--system" if system_folders else "--user"
|
|
264
257
|
cmd = (
|
|
@@ -286,9 +279,7 @@ def cli_node_start(
|
|
|
286
279
|
# we won't accept overwrites of existing env vars
|
|
287
280
|
env_overwrites = extra_env.keys() & env.keys()
|
|
288
281
|
if env_overwrites:
|
|
289
|
-
error(
|
|
290
|
-
"Cannot overwrite existing node environment variables: " f"{env_overwrites}"
|
|
291
|
-
)
|
|
282
|
+
error(f"Cannot overwrite existing node environment variables: {env_overwrites}")
|
|
292
283
|
exit(1)
|
|
293
284
|
env.update(extra_env)
|
|
294
285
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import yaml
|
|
2
|
+
import docker
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from vantage6.common import info, error
|
|
6
|
+
from vantage6.common.docker.network_manager import NetworkManager
|
|
7
|
+
from vantage6.common.globals import DEFAULT_PROMETHEUS_EXPORTER_PORT
|
|
8
|
+
from vantage6.cli.context.server import ServerContext
|
|
9
|
+
from vantage6.cli.globals import (
|
|
10
|
+
DEFAULT_PROMETHEUS_IMAGE,
|
|
11
|
+
PROMETHEUS_CONFIG,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PrometheusServer:
|
|
16
|
+
"""
|
|
17
|
+
Manages the Prometheus Docker container
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self, ctx: ServerContext, network_mgr: NetworkManager, image: str = None
|
|
22
|
+
):
|
|
23
|
+
"""
|
|
24
|
+
Initialize the PrometheusServer instance.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
ctx : ServerContext
|
|
29
|
+
The server context containing configuration and paths.
|
|
30
|
+
network_mgr : NetworkManager
|
|
31
|
+
The network manager responsible for managing Docker networks.
|
|
32
|
+
image : str, optional
|
|
33
|
+
The Docker image to use for the Prometheus container. If not provided,
|
|
34
|
+
the default Prometheus image will be used.
|
|
35
|
+
"""
|
|
36
|
+
self.ctx = ctx
|
|
37
|
+
self.network_mgr = network_mgr
|
|
38
|
+
self.docker = docker.from_env()
|
|
39
|
+
self.image = image if image else DEFAULT_PROMETHEUS_IMAGE
|
|
40
|
+
self.config_file = Path(__file__).parent / PROMETHEUS_CONFIG
|
|
41
|
+
self.data_dir = self.ctx.prometheus_dir
|
|
42
|
+
|
|
43
|
+
def start(self):
|
|
44
|
+
"""
|
|
45
|
+
Start a Docker container running Prometheus
|
|
46
|
+
"""
|
|
47
|
+
self._prepare_config()
|
|
48
|
+
|
|
49
|
+
volumes = {
|
|
50
|
+
str(self.config_file): {
|
|
51
|
+
"bind": "/etc/prometheus/prometheus.yml",
|
|
52
|
+
"mode": "ro",
|
|
53
|
+
},
|
|
54
|
+
str(self.data_dir): {"bind": "/prometheus", "mode": "rw"},
|
|
55
|
+
}
|
|
56
|
+
ports = {"9090/tcp": 9090}
|
|
57
|
+
|
|
58
|
+
if self._is_container_running():
|
|
59
|
+
info("Prometheus is already running!")
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
self.docker.containers.run(
|
|
63
|
+
name=self.ctx.prometheus_container_name,
|
|
64
|
+
image=self.image,
|
|
65
|
+
volumes=volumes,
|
|
66
|
+
ports=ports,
|
|
67
|
+
detach=True,
|
|
68
|
+
restart_policy={"Name": "unless-stopped"},
|
|
69
|
+
network=self.network_mgr.network_name,
|
|
70
|
+
)
|
|
71
|
+
info("Prometheus container started successfully!")
|
|
72
|
+
|
|
73
|
+
def _prepare_config(self):
|
|
74
|
+
"""
|
|
75
|
+
Prepare the Prometheus configuration and data directories
|
|
76
|
+
"""
|
|
77
|
+
if not self.config_file.exists():
|
|
78
|
+
error(f"Prometheus configuration file {self.config_file} not found!")
|
|
79
|
+
raise FileNotFoundError(f"{self.config_file} not found!")
|
|
80
|
+
|
|
81
|
+
if not self.data_dir.exists():
|
|
82
|
+
self.data_dir.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
|
|
84
|
+
self._update_prometheus_config()
|
|
85
|
+
|
|
86
|
+
def _update_prometheus_config(self):
|
|
87
|
+
"""
|
|
88
|
+
Update the Prometheus configuration file with the server address.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
prometheus_exporter_port = self.ctx.config.get("prometheus", {}).get(
|
|
93
|
+
"exporter_port", DEFAULT_PROMETHEUS_EXPORTER_PORT
|
|
94
|
+
)
|
|
95
|
+
server_hostname = self.ctx.prometheus_container_name
|
|
96
|
+
server_address = f"{server_hostname}:{prometheus_exporter_port}"
|
|
97
|
+
|
|
98
|
+
info(
|
|
99
|
+
f"Using Docker container hostname '{server_hostname}' for Prometheus "
|
|
100
|
+
"target. Ensure Prometheus is in the same Docker network to resolve "
|
|
101
|
+
"this address."
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
with open(self.config_file, "r") as f:
|
|
105
|
+
config = yaml.safe_load(f)
|
|
106
|
+
|
|
107
|
+
job_name = "vantage6_server_metrics"
|
|
108
|
+
job_exists = any(
|
|
109
|
+
job.get("job_name") == job_name
|
|
110
|
+
for job in config.get("scrape_configs", [])
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if not job_exists:
|
|
114
|
+
new_job = {
|
|
115
|
+
"job_name": job_name,
|
|
116
|
+
"static_configs": [{"targets": [server_address]}],
|
|
117
|
+
}
|
|
118
|
+
config.setdefault("scrape_configs", []).append(new_job)
|
|
119
|
+
else:
|
|
120
|
+
for job in config["scrape_configs"]:
|
|
121
|
+
if job.get("job_name") == job_name:
|
|
122
|
+
job["static_configs"] = [{"targets": [server_address]}]
|
|
123
|
+
|
|
124
|
+
with open(self.config_file, "w") as f:
|
|
125
|
+
yaml.dump(config, f)
|
|
126
|
+
|
|
127
|
+
info(f"Prometheus configuration updated with target: {server_address}")
|
|
128
|
+
|
|
129
|
+
except Exception as e:
|
|
130
|
+
error(f"Failed to update Prometheus configuration: {e}")
|
|
131
|
+
raise
|
|
132
|
+
|
|
133
|
+
def _is_container_running(self) -> bool:
|
|
134
|
+
"""
|
|
135
|
+
Check if a Prometheus container is already running.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
bool
|
|
140
|
+
True if the Prometheus container is running, False otherwise.
|
|
141
|
+
"""
|
|
142
|
+
try:
|
|
143
|
+
container = self.docker.containers.get(self.ctx.prometheus_container_name)
|
|
144
|
+
return container.status == "running"
|
|
145
|
+
except docker.errors.NotFound:
|
|
146
|
+
return False
|