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.
- vantage6/cli/algorithm/generate_algorithm_json.py +9 -10
- vantage6/cli/algorithm/update.py +1 -1
- vantage6/cli/algostore/attach.py +1 -0
- vantage6/cli/algostore/files.py +3 -2
- vantage6/cli/algostore/list.py +0 -3
- vantage6/cli/algostore/new.py +3 -2
- vantage6/cli/algostore/start.py +14 -3
- vantage6/cli/algostore/stop.py +3 -0
- vantage6/cli/auth/attach.py +60 -0
- vantage6/cli/auth/files.py +16 -0
- vantage6/cli/auth/list.py +13 -0
- vantage6/cli/auth/new.py +81 -0
- vantage6/cli/auth/remove.py +31 -0
- vantage6/cli/auth/start.py +94 -0
- vantage6/cli/auth/stop.py +67 -0
- vantage6/cli/cli.py +56 -5
- vantage6/cli/common/decorator.py +24 -5
- vantage6/cli/common/new.py +27 -7
- vantage6/cli/common/start.py +49 -41
- vantage6/cli/common/stop.py +23 -5
- vantage6/cli/common/utils.py +25 -0
- vantage6/cli/config.py +10 -2
- vantage6/cli/{configuration_wizard.py → configuration_create.py} +28 -15
- vantage6/cli/configuration_manager.py +97 -17
- vantage6/cli/context/__init__.py +10 -5
- vantage6/cli/context/algorithm_store.py +11 -5
- vantage6/cli/context/auth.py +125 -0
- vantage6/cli/context/base_server.py +0 -4
- vantage6/cli/context/node.py +25 -8
- vantage6/cli/context/server.py +18 -6
- vantage6/cli/dev/clean.py +28 -0
- vantage6/cli/dev/common.py +34 -0
- vantage6/cli/dev/rebuild.py +39 -0
- vantage6/cli/dev/start.py +36 -0
- vantage6/cli/dev/stop.py +23 -0
- vantage6/cli/globals.py +5 -1
- vantage6/cli/node/common/__init__.py +26 -10
- vantage6/cli/node/list.py +5 -4
- vantage6/cli/node/new.py +13 -6
- vantage6/cli/node/set_api_key.py +1 -1
- vantage6/cli/node/start.py +19 -4
- vantage6/cli/node/stop.py +153 -7
- vantage6/cli/node/task_cleanup/__init__.py +153 -0
- vantage6/cli/node/version.py +5 -4
- vantage6/cli/prometheus/monitoring_manager.py +5 -3
- vantage6/cli/sandbox/config/base.py +101 -0
- vantage6/cli/sandbox/config/core.py +300 -0
- vantage6/cli/sandbox/config/node.py +314 -0
- vantage6/cli/sandbox/data/olympic_athletes_2016.csv +2425 -0
- vantage6/cli/sandbox/new.py +207 -0
- vantage6/cli/sandbox/populate/__init__.py +173 -0
- vantage6/cli/sandbox/populate/helpers/connect_store.py +203 -0
- vantage6/cli/sandbox/populate/helpers/delete_fixtures.py +67 -0
- vantage6/cli/sandbox/populate/helpers/load_fixtures.py +476 -0
- vantage6/cli/sandbox/populate/helpers/utils.py +35 -0
- vantage6/cli/sandbox/remove.py +173 -0
- vantage6/cli/sandbox/start.py +341 -0
- vantage6/cli/sandbox/stop.py +106 -0
- vantage6/cli/server/attach.py +1 -0
- vantage6/cli/server/common/__init__.py +6 -33
- vantage6/cli/server/import_.py +137 -119
- vantage6/cli/server/new.py +22 -7
- vantage6/cli/server/start.py +10 -1
- vantage6/cli/server/stop.py +2 -0
- vantage6/cli/template/auth_config.j2 +253 -0
- vantage6/cli/template/node_config.j2 +8 -8
- vantage6/cli/template/node_config_nonk8s.j2 +33 -0
- vantage6/cli/template/server_config.j2 +10 -7
- vantage6/cli/test/common/diagnostic_runner.py +5 -3
- vantage6/cli/use/namespace.py +2 -1
- vantage6/cli/utils.py +33 -1
- {vantage6-5.0.0a35.dist-info → vantage6-5.0.0a37.dist-info}/METADATA +4 -4
- vantage6-5.0.0a37.dist-info/RECORD +97 -0
- vantage6/cli/dev/create.py +0 -693
- vantage6/cli/dev/remove.py +0 -112
- vantage6/cli/rabbitmq/__init__.py +0 -0
- vantage6/cli/rabbitmq/definitions.py +0 -26
- vantage6/cli/rabbitmq/queue_manager.py +0 -218
- vantage6/cli/rabbitmq/rabbitmq.config +0 -8
- vantage6/cli/server/shell.py +0 -54
- vantage6-5.0.0a35.dist-info/RECORD +0 -75
- /vantage6/cli/{dev → sandbox}/data/km_dataset.csv +0 -0
- {vantage6-5.0.0a35.dist-info → vantage6-5.0.0a37.dist-info}/WHEEL +0 -0
- {vantage6-5.0.0a35.dist-info → vantage6-5.0.0a37.dist-info}/entry_points.txt +0 -0
vantage6/cli/server/import_.py
CHANGED
|
@@ -1,26 +1,19 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from threading import Thread
|
|
3
|
-
|
|
4
1
|
import click
|
|
5
|
-
import
|
|
6
|
-
|
|
2
|
+
import requests
|
|
3
|
+
import yaml
|
|
7
4
|
|
|
8
|
-
from vantage6.common import
|
|
9
|
-
from vantage6.common.docker.addons import check_docker_running, pull_image
|
|
5
|
+
from vantage6.common import error, info
|
|
10
6
|
from vantage6.common.globals import (
|
|
11
|
-
APPNAME,
|
|
12
|
-
DEFAULT_DOCKER_REGISTRY,
|
|
13
|
-
DEFAULT_SERVER_IMAGE,
|
|
14
7
|
InstanceType,
|
|
15
8
|
)
|
|
16
9
|
|
|
10
|
+
from vantage6.client import UserClient
|
|
11
|
+
|
|
12
|
+
from vantage6.cli import __version__
|
|
17
13
|
from vantage6.cli.common.decorator import click_insert_context
|
|
18
|
-
from vantage6.cli.common.utils import print_log_worker
|
|
19
14
|
from vantage6.cli.context.server import ServerContext
|
|
20
|
-
from vantage6.cli.utils import check_config_name_allowed
|
|
21
15
|
|
|
22
16
|
|
|
23
|
-
# TODO this method has a lot of duplicated code from `start`
|
|
24
17
|
@click.command()
|
|
25
18
|
@click.argument("file", type=click.Path(exists=True))
|
|
26
19
|
@click.option(
|
|
@@ -29,121 +22,146 @@ from vantage6.cli.utils import check_config_name_allowed
|
|
|
29
22
|
default=False,
|
|
30
23
|
help="Drop all existing data before importing",
|
|
31
24
|
)
|
|
32
|
-
@click.option("-i", "--image", default=None, help="Node Docker image to use")
|
|
33
|
-
@click.option(
|
|
34
|
-
"--mount-src",
|
|
35
|
-
default="",
|
|
36
|
-
help="Override vantage6 source code in container with the source code in this path",
|
|
37
|
-
)
|
|
38
|
-
@click.option(
|
|
39
|
-
"--keep/--auto-remove",
|
|
40
|
-
default=False,
|
|
41
|
-
help="Keep image after finishing. Useful for debugging",
|
|
42
|
-
)
|
|
43
|
-
@click.option("--wait", default=False, help="Wait for the import to finish")
|
|
44
25
|
@click_insert_context(type_=InstanceType.SERVER)
|
|
45
|
-
def cli_server_import(
|
|
46
|
-
ctx: ServerContext,
|
|
47
|
-
file: str,
|
|
48
|
-
drop_all: bool,
|
|
49
|
-
image: str | None,
|
|
50
|
-
mount_src: str,
|
|
51
|
-
keep: bool,
|
|
52
|
-
wait: bool,
|
|
53
|
-
) -> None:
|
|
26
|
+
def cli_server_import(ctx: ServerContext, file: str, drop_all: bool) -> None:
|
|
54
27
|
"""
|
|
55
|
-
Import vantage6 resources into a server instance.
|
|
28
|
+
Import vantage6 resources into a server instance from a yaml FILE.
|
|
56
29
|
|
|
57
|
-
This allows you to create organizations, collaborations, users, tasks, etc
|
|
58
|
-
|
|
30
|
+
This allows you to create organizations, collaborations, users, tasks, etc. from a
|
|
31
|
+
yaml FILE. This method expects the server configuration file to be located on the
|
|
32
|
+
same machine as this method is invoked from.
|
|
59
33
|
|
|
60
|
-
|
|
61
|
-
|
|
34
|
+
This import assigns the root role to all users, which contains all permissions. So
|
|
35
|
+
use this with caution.
|
|
36
|
+
|
|
37
|
+
The FILE argument should be a path to a yaml file containing the vantage6 formatted
|
|
38
|
+
data to import.
|
|
62
39
|
"""
|
|
63
|
-
|
|
64
|
-
|
|
40
|
+
info("Validating server version: ")
|
|
41
|
+
info(f"{ctx.config['server']['baseUrl']}{ctx.config['server']['apiPath']}/version")
|
|
42
|
+
response = requests.get(
|
|
43
|
+
f"{ctx.config['server']['baseUrl']}{ctx.config['server']['apiPath']}/version"
|
|
44
|
+
)
|
|
45
|
+
if response.status_code != 200:
|
|
46
|
+
error("Unable to get server version")
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
body = response.json()
|
|
50
|
+
if "version" not in body:
|
|
51
|
+
error("Server gave a valid response but did not include the version")
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
# Compare it to this package version
|
|
55
|
+
server_version = body["version"]
|
|
56
|
+
if server_version != __version__:
|
|
57
|
+
error(
|
|
58
|
+
f"You are using CLI version {__version__} but the server is running "
|
|
59
|
+
f"version {server_version}. Please use the same version of the CLI and "
|
|
60
|
+
"server."
|
|
61
|
+
)
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
info("Loading and validating import file")
|
|
65
|
+
with open(file, "r") as f:
|
|
66
|
+
import_data = yaml.safe_load(f)
|
|
67
|
+
# TODO: validate import file
|
|
68
|
+
|
|
69
|
+
client = UserClient(
|
|
70
|
+
server_url=f"{ctx.config['server']['baseUrl']}{ctx.config['server']['apiPath']}",
|
|
71
|
+
auth_url=ctx.config["ui"]["keycloakPublicUrl"],
|
|
72
|
+
auth_realm=ctx.config["ui"]["keycloakRealm"],
|
|
73
|
+
auth_client=ctx.config["ui"]["keycloakClient"],
|
|
74
|
+
log_level="info",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
info("Authenticate using admin credentials (opens browser for login)")
|
|
78
|
+
client.authenticate()
|
|
65
79
|
|
|
66
|
-
|
|
67
|
-
info("Finding Docker daemon.")
|
|
68
|
-
docker_client = docker.from_env()
|
|
80
|
+
# TODO: validate that the user has the correct permissions to import data
|
|
69
81
|
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
if drop_all:
|
|
83
|
+
info("Dropping all existing data")
|
|
84
|
+
_drop_all(client)
|
|
72
85
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
info("Collecting root role and rule")
|
|
87
|
+
root_role_id = client.role.list(name="Root", include_root=True)["data"][0]["id"]
|
|
88
|
+
|
|
89
|
+
info("Importing organizations")
|
|
90
|
+
organizations = []
|
|
91
|
+
for organization in import_data["organizations"]:
|
|
92
|
+
org = client.organization.create(
|
|
93
|
+
name=organization["name"],
|
|
94
|
+
address1=organization["address1"] or "",
|
|
95
|
+
address2=organization["address2"] or "",
|
|
96
|
+
zipcode=organization["zipcode"] or "",
|
|
97
|
+
country=organization["country"] or "",
|
|
98
|
+
domain=organization["domain"] or "",
|
|
77
99
|
)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
db_path = ctx.data_dir / url.database
|
|
104
|
-
|
|
105
|
-
basename = os.path.basename(db_path)
|
|
106
|
-
dirname = os.path.dirname(db_path)
|
|
107
|
-
os.makedirs(dirname, exist_ok=True)
|
|
108
|
-
|
|
109
|
-
# we're mounting the entire folder that contains the database
|
|
110
|
-
mounts.append(docker.types.Mount("/mnt/database/", dirname, type="bind"))
|
|
111
|
-
|
|
112
|
-
environment_vars = {
|
|
113
|
-
# ServerGlobals.DB_URI_ENV_VAR.value: f"sqlite:////mnt/database/{basename}"
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
else:
|
|
117
|
-
warning(
|
|
118
|
-
f"Database could not be transferred, make sure {url.host} "
|
|
119
|
-
"is reachable from the Docker container"
|
|
100
|
+
organizations.append(org)
|
|
101
|
+
|
|
102
|
+
info(f"Importing users for organization {org['name']}")
|
|
103
|
+
for user in organization.get("users", []):
|
|
104
|
+
client.user.create(
|
|
105
|
+
username=user["username"],
|
|
106
|
+
password=user["password"],
|
|
107
|
+
organization=org["id"],
|
|
108
|
+
roles=[root_role_id],
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
info("Importing collaborations")
|
|
112
|
+
all_nodes = []
|
|
113
|
+
for collaboration in import_data["collaborations"]:
|
|
114
|
+
# Collecting organization ids
|
|
115
|
+
organization_ids = []
|
|
116
|
+
for participant in collaboration["participants"]:
|
|
117
|
+
for org in organizations:
|
|
118
|
+
if org["name"] == participant["name"]:
|
|
119
|
+
organization_ids.append(org["id"])
|
|
120
|
+
|
|
121
|
+
col = client.collaboration.create(
|
|
122
|
+
name=collaboration["name"],
|
|
123
|
+
organizations=organization_ids,
|
|
124
|
+
encrypted=collaboration.get("encrypted", False),
|
|
120
125
|
)
|
|
121
|
-
info("Consider using the docker-compose method to start a server")
|
|
122
|
-
|
|
123
|
-
drop_all_ = "--drop-all" if drop_all else ""
|
|
124
|
-
cmd = f"vserver-local import -c /mnt/config.yaml {drop_all_} /mnt/import.yaml"
|
|
125
|
-
|
|
126
|
-
info(cmd)
|
|
127
|
-
|
|
128
|
-
info("Run Docker container")
|
|
129
|
-
container = docker_client.containers.run(
|
|
130
|
-
image,
|
|
131
|
-
command=cmd,
|
|
132
|
-
mounts=mounts,
|
|
133
|
-
detach=True,
|
|
134
|
-
labels={
|
|
135
|
-
f"{APPNAME}-type": InstanceType.SERVER.value,
|
|
136
|
-
"name": ctx.config_file_name,
|
|
137
|
-
},
|
|
138
|
-
environment=environment_vars,
|
|
139
|
-
auto_remove=not keep,
|
|
140
|
-
tty=True,
|
|
141
|
-
)
|
|
142
|
-
logs = container.logs(stream=True, stdout=True)
|
|
143
|
-
Thread(target=print_log_worker, args=(logs,), daemon=False).start()
|
|
144
126
|
|
|
145
|
-
|
|
127
|
+
info("Registering nodes for collaboration")
|
|
128
|
+
for participant in collaboration["participants"]:
|
|
129
|
+
for org in organizations:
|
|
130
|
+
if org["name"] == participant["name"]:
|
|
131
|
+
node = client.node.create(
|
|
132
|
+
name=f"{collaboration['name']}-{org['name'].replace(' ', '-')}-node",
|
|
133
|
+
organization=org["id"],
|
|
134
|
+
collaboration=col["id"],
|
|
135
|
+
)
|
|
136
|
+
all_nodes.append(node)
|
|
146
137
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
138
|
+
return all_nodes
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _drop_all(client: UserClient) -> None:
|
|
142
|
+
"""
|
|
143
|
+
Drop all existing data from the server.
|
|
144
|
+
"""
|
|
145
|
+
while nodes := client.node.list()["data"]:
|
|
146
|
+
for node in nodes:
|
|
147
|
+
info(f"Deleting node {node['name']}")
|
|
148
|
+
client.node.delete(node["id"])
|
|
149
|
+
|
|
150
|
+
while collaborations := client.collaboration.list(scope="global")["data"]:
|
|
151
|
+
for collaboration in collaborations:
|
|
152
|
+
info(f"Deleting collaboration {collaboration['name']}")
|
|
153
|
+
client.collaboration.delete(collaboration["id"], delete_dependents=True)
|
|
154
|
+
|
|
155
|
+
# TODO: For some reason, the `delete_dependents` parameter is not working for users,
|
|
156
|
+
# so we delete them here first.
|
|
157
|
+
while users := [u for u in client.user.list()["data"] if u["username"] != "admin"]:
|
|
158
|
+
for user in users:
|
|
159
|
+
info(f"Deleting user {user['username']}")
|
|
160
|
+
client.user.delete(user["id"])
|
|
161
|
+
|
|
162
|
+
while orgs := [
|
|
163
|
+
o for o in client.organization.list()["data"] if o["name"] != "root"
|
|
164
|
+
]:
|
|
165
|
+
for org in orgs:
|
|
166
|
+
info(f"Deleting organization {org['name']}")
|
|
167
|
+
client.organization.delete(org["id"], delete_dependents=True)
|
vantage6/cli/server/new.py
CHANGED
|
@@ -9,7 +9,7 @@ from vantage6.common.globals import (
|
|
|
9
9
|
|
|
10
10
|
from vantage6.cli.common.new import new
|
|
11
11
|
from vantage6.cli.config import CliConfig
|
|
12
|
-
from vantage6.cli.
|
|
12
|
+
from vantage6.cli.configuration_create import add_common_server_config
|
|
13
13
|
from vantage6.cli.globals import DEFAULT_SERVER_SYSTEM_FOLDERS
|
|
14
14
|
|
|
15
15
|
|
|
@@ -45,8 +45,20 @@ def cli_server_new(
|
|
|
45
45
|
"""
|
|
46
46
|
Create a new server configuration.
|
|
47
47
|
"""
|
|
48
|
+
# info(
|
|
49
|
+
# "Vantage6 uses keycloak for authentication. Please configure a keycloak "
|
|
50
|
+
# "server here unless you have one running externally."
|
|
51
|
+
# )
|
|
52
|
+
# configure_keycloak = q.confirm(
|
|
53
|
+
# "Do you want to configure a keycloak server?",
|
|
54
|
+
# default=True,
|
|
55
|
+
# ).unsafe_ask()
|
|
56
|
+
# if configure_keycloak:
|
|
57
|
+
# print("awefawef")
|
|
58
|
+
|
|
48
59
|
new(
|
|
49
|
-
|
|
60
|
+
config_producing_func=server_configuration_questionaire,
|
|
61
|
+
config_producing_func_args=(name,),
|
|
50
62
|
name=name,
|
|
51
63
|
system_folders=system_folders,
|
|
52
64
|
namespace=namespace,
|
|
@@ -69,10 +81,6 @@ def server_configuration_questionaire(instance_name: str) -> dict[str, Any]:
|
|
|
69
81
|
dict[str, Any]
|
|
70
82
|
dictionary with Helm values for the server configuration
|
|
71
83
|
"""
|
|
72
|
-
# Get active kube namespace
|
|
73
|
-
cli_config = CliConfig()
|
|
74
|
-
kube_namespace = cli_config.get_last_namespace()
|
|
75
|
-
|
|
76
84
|
# Initialize config with basic structure
|
|
77
85
|
config = {"server": {}, "database": {}, "ui": {}, "rabbitmq": {}}
|
|
78
86
|
|
|
@@ -85,7 +93,8 @@ def server_configuration_questionaire(instance_name: str) -> dict[str, Any]:
|
|
|
85
93
|
}
|
|
86
94
|
config["server"]["dev"] = {
|
|
87
95
|
"host_uri": "host.docker.internal",
|
|
88
|
-
|
|
96
|
+
# TODO v5+ adapt to name space and service name etc, check from sandbox
|
|
97
|
+
"store_address": "http://vantage6-store-store.service.default.svc.cluster.local",
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
# TODO v5+ these should be removed, latest should usually be used so question is
|
|
@@ -102,7 +111,13 @@ def server_configuration_questionaire(instance_name: str) -> dict[str, Any]:
|
|
|
102
111
|
default="harbor2.vantage6.ai/infrastructure/ui:latest",
|
|
103
112
|
).unsafe_ask()
|
|
104
113
|
|
|
114
|
+
# TODO v5+ we need to add a question to ask which algorithm stores are allowed, to
|
|
115
|
+
# set the CSP headers in the UI. This is not done now because it becomes easier when
|
|
116
|
+
# store and keycloak service can also be setup in the `v6 server new` command.
|
|
117
|
+
|
|
105
118
|
# === Keycloak settings ===
|
|
119
|
+
cli_config = CliConfig()
|
|
120
|
+
kube_namespace = cli_config.get_last_namespace()
|
|
106
121
|
keycloak_url = f"http://vantage6-auth-keycloak.{kube_namespace}.svc.cluster.local"
|
|
107
122
|
config["server"]["keycloakUrl"] = keycloak_url
|
|
108
123
|
|
vantage6/cli/server/start.py
CHANGED
|
@@ -12,6 +12,7 @@ from vantage6.cli.common.start import (
|
|
|
12
12
|
from vantage6.cli.common.utils import (
|
|
13
13
|
attach_logs,
|
|
14
14
|
create_directory_if_not_exists,
|
|
15
|
+
select_context_and_namespace,
|
|
15
16
|
)
|
|
16
17
|
from vantage6.cli.context.server import ServerContext
|
|
17
18
|
from vantage6.cli.globals import ChartName
|
|
@@ -32,6 +33,7 @@ from vantage6.cli.globals import ChartName
|
|
|
32
33
|
default=False,
|
|
33
34
|
help="Print server logs to the console after start",
|
|
34
35
|
)
|
|
36
|
+
@click.option("--local-chart-dir", default=None, help="Local chart directory to use")
|
|
35
37
|
@click_insert_context(
|
|
36
38
|
type_=InstanceType.SERVER, include_name=True, include_system_folders=True
|
|
37
39
|
)
|
|
@@ -45,13 +47,18 @@ def cli_server_start(
|
|
|
45
47
|
port: int,
|
|
46
48
|
ui_port: int,
|
|
47
49
|
attach: bool,
|
|
50
|
+
local_chart_dir: str | None,
|
|
48
51
|
) -> None:
|
|
49
52
|
"""
|
|
50
53
|
Start the server.
|
|
51
54
|
"""
|
|
52
55
|
info("Starting server...")
|
|
56
|
+
prestart_checks(ctx, InstanceType.SERVER, name, system_folders)
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
context, namespace = select_context_and_namespace(
|
|
59
|
+
context=context,
|
|
60
|
+
namespace=namespace,
|
|
61
|
+
)
|
|
55
62
|
|
|
56
63
|
create_directory_if_not_exists(ctx.log_dir)
|
|
57
64
|
|
|
@@ -61,11 +68,13 @@ def cli_server_start(
|
|
|
61
68
|
values_file=ctx.config_file,
|
|
62
69
|
context=context,
|
|
63
70
|
namespace=namespace,
|
|
71
|
+
local_chart_dir=local_chart_dir,
|
|
64
72
|
)
|
|
65
73
|
|
|
66
74
|
# port forward for server
|
|
67
75
|
info("Port forwarding for server")
|
|
68
76
|
start_port_forward(
|
|
77
|
+
# TODO: make this dynamic
|
|
69
78
|
service_name=f"{ctx.helm_release_name}-vantage6-server-service",
|
|
70
79
|
service_port=ctx.config["server"].get("port", Ports.DEV_SERVER.value),
|
|
71
80
|
port=port or ctx.config["server"].get("port", Ports.DEV_SERVER.value),
|
vantage6/cli/server/stop.py
CHANGED
|
@@ -32,6 +32,7 @@ def cli_server_stop(
|
|
|
32
32
|
namespace: str,
|
|
33
33
|
system_folders: bool,
|
|
34
34
|
all_servers: bool,
|
|
35
|
+
is_sandbox: bool = False,
|
|
35
36
|
):
|
|
36
37
|
"""
|
|
37
38
|
Stop an running server.
|
|
@@ -45,6 +46,7 @@ def cli_server_stop(
|
|
|
45
46
|
namespace=namespace,
|
|
46
47
|
context=context,
|
|
47
48
|
system_folders=system_folders,
|
|
49
|
+
is_sandbox=is_sandbox,
|
|
48
50
|
)
|
|
49
51
|
|
|
50
52
|
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# for more options on the deployment of this chart, see:
|
|
2
|
+
# https://artifacthub.io/packages/helm/bitnami/keycloak
|
|
3
|
+
keycloak:
|
|
4
|
+
|
|
5
|
+
# for development, use a local PostgreSQL instance.
|
|
6
|
+
{% if keycloak.production %}
|
|
7
|
+
postgresql:
|
|
8
|
+
enabled: false
|
|
9
|
+
|
|
10
|
+
# TODO v5+ set these variables from the CLI
|
|
11
|
+
externalDatabase:
|
|
12
|
+
host: "sql.example.vantage6.ai"
|
|
13
|
+
port: 5432
|
|
14
|
+
username: my-username
|
|
15
|
+
password: my-secret-password
|
|
16
|
+
database: my-keycloak-database
|
|
17
|
+
schema: public
|
|
18
|
+
existingSecretHostKey: my-secret-contains-the-host
|
|
19
|
+
existingSecretPortKey: my-secret-contains-the-port
|
|
20
|
+
existingSecretUsernameKey: my-secret-contains-the-username
|
|
21
|
+
existingSecretPasswordKey: my-secret-contains-the-password
|
|
22
|
+
existingSecretDatabaseKey: my-secret-contains-the-database
|
|
23
|
+
|
|
24
|
+
# TODO v5+ set secrets in CLI
|
|
25
|
+
auth:
|
|
26
|
+
# Set the username and password for the Keycloak admin. This user is created when
|
|
27
|
+
# the service is initialized.
|
|
28
|
+
adminUser: {{ keycloak.adminUser | default('admin') }}
|
|
29
|
+
existingSecret: secret-containing-admin-password
|
|
30
|
+
passwordSecretKey: key-to-admin-password-in-secret
|
|
31
|
+
# For a development environment, you can set the admin user and password directly.
|
|
32
|
+
# adminPassword: admin
|
|
33
|
+
|
|
34
|
+
# for production, TLS should be enabled for internal Keycloak communication
|
|
35
|
+
# TODO v5+ we should test if this works when we have CLI commands (#1923)
|
|
36
|
+
production: true
|
|
37
|
+
tls:
|
|
38
|
+
enabled: true
|
|
39
|
+
autoGenerated: true
|
|
40
|
+
{% else %}
|
|
41
|
+
postgresql:
|
|
42
|
+
enabled: true
|
|
43
|
+
auth:
|
|
44
|
+
postgresPassword: postgres
|
|
45
|
+
password: keycloak
|
|
46
|
+
database: keycloak
|
|
47
|
+
|
|
48
|
+
# for production, use an external PostgreSQL instance. This requires setting up config
|
|
49
|
+
# as follows. Be sure to set postgres.enabled to false just above here.
|
|
50
|
+
# externalDatabase:
|
|
51
|
+
# host: "sql.example.vantage6.ai"
|
|
52
|
+
# port: 5432
|
|
53
|
+
# username: my-username
|
|
54
|
+
# password: my-secret-password
|
|
55
|
+
# database: my-keycloak-database
|
|
56
|
+
# schema: public
|
|
57
|
+
# # or alternatively, use secrets for all of the above formatted as:
|
|
58
|
+
# existingSecretHostKey: my-secret-contains-the-host
|
|
59
|
+
# existingSecretPortKey: my-secret-contains-the-port
|
|
60
|
+
# existingSecretUsernameKey: my-secret-contains-the-username
|
|
61
|
+
# existingSecretPasswordKey: my-secret-contains-the-password
|
|
62
|
+
# existingSecretDatabaseKey: my-secret-contains-the-database
|
|
63
|
+
|
|
64
|
+
auth:
|
|
65
|
+
# for development environment, set a dummy password for the admin user.
|
|
66
|
+
adminUser: admin
|
|
67
|
+
adminPassword: admin
|
|
68
|
+
# for production, the password should be stored in a secret. Below you should then
|
|
69
|
+
# give the name of the secret and the key to where the password is within the
|
|
70
|
+
# secret.
|
|
71
|
+
# existingSecret: secret-containing-admin-password
|
|
72
|
+
# passwordSecretKey: key-to-admin-password-in-secret
|
|
73
|
+
|
|
74
|
+
# if you want to switch to production, you should set the following settings to true.
|
|
75
|
+
production: false
|
|
76
|
+
tls:
|
|
77
|
+
enabled: false
|
|
78
|
+
autoGenerated: false
|
|
79
|
+
{% endif %}
|
|
80
|
+
|
|
81
|
+
# ensure that the auth pod has enough resources to run. The default values are enough
|
|
82
|
+
# in most cases, but for a larger environment, you might need to increase the limits.
|
|
83
|
+
resources:
|
|
84
|
+
limits:
|
|
85
|
+
memory: 2Gi
|
|
86
|
+
cpu: 1000m
|
|
87
|
+
requests:
|
|
88
|
+
memory: 1Gi
|
|
89
|
+
cpu: 500m
|
|
90
|
+
|
|
91
|
+
# The following configuration is run via the CLI when the Keycloak service is
|
|
92
|
+
# initialized. It creates a number of users, roles and secrets that are required for
|
|
93
|
+
# vantage6 to work properly.
|
|
94
|
+
keycloakConfigCli:
|
|
95
|
+
enabled: true
|
|
96
|
+
configuration:
|
|
97
|
+
# Keycloak realm configuration. For all options, see
|
|
98
|
+
# https://www.keycloak.org/docs-api/latest/rest-api/index.html#RealmRepresentation
|
|
99
|
+
realm:
|
|
100
|
+
# Keycloak realm name
|
|
101
|
+
realm: {{ keycloak.realm | default('vantage6') }}
|
|
102
|
+
enabled: true
|
|
103
|
+
|
|
104
|
+
# access token lifespan in seconds
|
|
105
|
+
accessTokenLifespan: {{ keycloak.accessTokenLifespan | default(300) }}
|
|
106
|
+
|
|
107
|
+
# sso session idle timeout in seconds. This is the time before the refresh token
|
|
108
|
+
# expires. With default settings, this value controls the time before the
|
|
109
|
+
# refresh token expires. Note that if setting this to >3600, you also need to
|
|
110
|
+
# set ssoSessionMaxLifespan and/or clientSessionIdleTimeout and/or
|
|
111
|
+
# clientSessionMaxLifespan to higher values to effectively lengthen the session.
|
|
112
|
+
ssoSessionIdleTimeout: {{ keycloak.ssoSessionIdleTimeout | default(1800) }}
|
|
113
|
+
|
|
114
|
+
# password policy configuration. If you prefer not to have a password policy,
|
|
115
|
+
# you can set this to an empty string.
|
|
116
|
+
{% if keycloak.production %}
|
|
117
|
+
passwordPolicy: "length(8) and upperCase(1) and lowerCase(1) and digits(1) and specialChars(1)"
|
|
118
|
+
{% else %}
|
|
119
|
+
passwordPolicy: ""
|
|
120
|
+
{% endif %}
|
|
121
|
+
|
|
122
|
+
# do not allow users to edit their username - this would lead to problems with
|
|
123
|
+
# syncing the user between keycloak and vantage6 server/store. This setting
|
|
124
|
+
# should always be set to false.
|
|
125
|
+
editUsernameAllowed: false
|
|
126
|
+
|
|
127
|
+
{% if keycloak.production %}
|
|
128
|
+
# required actions for users. By setting defaultAction to true for configuring
|
|
129
|
+
# OTP, the user will be prompted to configure OTP (for two-factor
|
|
130
|
+
# authentication) on first login.
|
|
131
|
+
requiredActions:
|
|
132
|
+
- alias: CONFIGURE_TOTP
|
|
133
|
+
name: Configure OTP
|
|
134
|
+
providerId: CONFIGURE_TOTP
|
|
135
|
+
enabled: true
|
|
136
|
+
defaultAction: true
|
|
137
|
+
priority: 10
|
|
138
|
+
{% else %}
|
|
139
|
+
# If you want to require users to use two-factor authentication on first login,
|
|
140
|
+
# enable the settings below.
|
|
141
|
+
# requiredActions:
|
|
142
|
+
# - alias: CONFIGURE_TOTP
|
|
143
|
+
# name: Configure OTP
|
|
144
|
+
# providerId: CONFIGURE_TOTP
|
|
145
|
+
# enabled: true
|
|
146
|
+
# defaultAction: true
|
|
147
|
+
# priority: 10
|
|
148
|
+
{% endif %}
|
|
149
|
+
|
|
150
|
+
# users to be created in the realm. This initializes the realm with a default
|
|
151
|
+
# admin user. It also initializes the service account for the backend admin
|
|
152
|
+
# client to give it the necessary permissions to manage the realm.
|
|
153
|
+
# TODO v5+ configure secrets where necessary
|
|
154
|
+
users:
|
|
155
|
+
# create the vantage6 admin user. The name of this user should also be present
|
|
156
|
+
# in the vantage6 server and store configuration - it is the user that will be
|
|
157
|
+
# assigned admin permissions on initial startup.
|
|
158
|
+
- username: {{ keycloak.adminUser | default('admin') }}
|
|
159
|
+
enabled: true
|
|
160
|
+
{% if not keycloak.production %}
|
|
161
|
+
email: admin@vantage6.org
|
|
162
|
+
firstName: Admin
|
|
163
|
+
lastName: Admin
|
|
164
|
+
{% endif %}
|
|
165
|
+
credentials:
|
|
166
|
+
- type: password
|
|
167
|
+
{% if keycloak.production %}
|
|
168
|
+
value: {{ keycloak.adminPassword | default('Admin123!') }}
|
|
169
|
+
{% else %}
|
|
170
|
+
value: {{ keycloak.adminPassword | default('admin') }}
|
|
171
|
+
{% endif %}
|
|
172
|
+
requiredActions:
|
|
173
|
+
{% if keycloak.production %}
|
|
174
|
+
# this requires all users to update their password on first login and
|
|
175
|
+
# configure two-factor authentication
|
|
176
|
+
- CONFIGURE_TOTP
|
|
177
|
+
- UPDATE_PASSWORD
|
|
178
|
+
{% elif keycloak.no_password_update_required%}
|
|
179
|
+
# enable configure OTP only if you want to use two-factor authentication
|
|
180
|
+
# - CONFIGURE_TOTP
|
|
181
|
+
# enable password update if you want every user to have to change their
|
|
182
|
+
# password on first login
|
|
183
|
+
# - UPDATE_PASSWORD
|
|
184
|
+
{% else %}
|
|
185
|
+
# enable configure OTP only if you want to use two-factor authentication
|
|
186
|
+
# - CONFIGURE_TOTP
|
|
187
|
+
# this requires all users to update their password on first login
|
|
188
|
+
- UPDATE_PASSWORD
|
|
189
|
+
{% endif %}
|
|
190
|
+
# create a service account user for the backend admin client. The
|
|
191
|
+
# serviceAccountClientId should match the value set in the client section
|
|
192
|
+
# below. The vantage6 server and store will use this user to create new
|
|
193
|
+
# accounts for users and nodes in keycloak - that is why it gets assigned some
|
|
194
|
+
# realm-management permissions.
|
|
195
|
+
- username: service-account-backend-admin-client
|
|
196
|
+
enabled: true
|
|
197
|
+
serviceAccountClientId: backend-admin-client
|
|
198
|
+
clientRoles:
|
|
199
|
+
realm-management:
|
|
200
|
+
- view-users
|
|
201
|
+
- manage-users
|
|
202
|
+
- view-clients
|
|
203
|
+
- manage-clients
|
|
204
|
+
- create-client
|
|
205
|
+
|
|
206
|
+
# clients to be created in the realm. This initializes the realm with a default
|
|
207
|
+
# public client and a backend admin client. The public client is used by users
|
|
208
|
+
# to authenticate in the browser. Either the UI or the Python client will
|
|
209
|
+
# redirect to this client.
|
|
210
|
+
clients:
|
|
211
|
+
- clientId: public_client
|
|
212
|
+
publicClient: true
|
|
213
|
+
# redirect URIs are the URIs that keycloak is allowed to redirect to after
|
|
214
|
+
# authentication. This should be set to the UI URL, and to the Keyloak
|
|
215
|
+
# service on port 7681. The latter is needed for authentication from outside
|
|
216
|
+
# the browser - if e.g. the Python client authenticates, it will open a
|
|
217
|
+
# browser window to authenticate that redirects to the Keycloak service on
|
|
218
|
+
# port 7681.
|
|
219
|
+
{% if keycloak.redirectUris %}
|
|
220
|
+
redirectUris:
|
|
221
|
+
{% for uri in keycloak.redirectUris %}
|
|
222
|
+
- "{{ uri }}/*"
|
|
223
|
+
{% endfor %}
|
|
224
|
+
{% else %}
|
|
225
|
+
redirectUris:
|
|
226
|
+
# allow logging in via a local UI
|
|
227
|
+
- "http://localhost:7600/*"
|
|
228
|
+
# allow logging in via the Python client (which spins up a local server
|
|
229
|
+
# on port 7681)
|
|
230
|
+
- "http://localhost:7681/*"
|
|
231
|
+
{% endif %}
|
|
232
|
+
# By setting webOrigins to "+", we allow the same origins as redirectUris.
|
|
233
|
+
webOrigins:
|
|
234
|
+
- "+"
|
|
235
|
+
# The public client is only for users, not for nodes. Therefore, map a
|
|
236
|
+
# constant claim to indicate the that the client is a user.
|
|
237
|
+
protocolMappers:
|
|
238
|
+
- name: vantage6_client_type
|
|
239
|
+
protocol: openid-connect
|
|
240
|
+
protocolMapper: oidc-hardcoded-claim-mapper
|
|
241
|
+
consentRequired: false
|
|
242
|
+
config:
|
|
243
|
+
claim.name: vantage6_client_type
|
|
244
|
+
claim.value: user
|
|
245
|
+
access.token.claim: true
|
|
246
|
+
# create a client that will allow the backend to manage users and clients in
|
|
247
|
+
# keycloak.
|
|
248
|
+
- clientId: backend-admin-client
|
|
249
|
+
publicClient: false
|
|
250
|
+
# TODO v5+ configure secrets where necessary
|
|
251
|
+
secret: myadminclientsecret
|
|
252
|
+
serviceAccountsEnabled: true
|
|
253
|
+
standardFlowEnabled: false
|