vantage6 5.0.0a0__py3-none-any.whl → 5.0.0a9__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_node_cli.py +36 -25
- tests_cli/test_server_cli.py +33 -12
- tests_cli/test_wizard.py +5 -5
- vantage6/cli/__build__ +1 -1
- vantage6/cli/__init__.py +1 -1
- vantage6/cli/algorithm/create.py +26 -8
- vantage6/cli/algorithm/update.py +5 -1
- vantage6/cli/algostore/attach.py +6 -25
- vantage6/cli/algostore/new.py +9 -3
- vantage6/cli/cli.py +6 -11
- vantage6/cli/common/start.py +1 -1
- vantage6/cli/common/utils.py +42 -4
- vantage6/cli/configuration_wizard.py +63 -51
- vantage6/cli/context/node.py +18 -1
- vantage6/cli/node/attach.py +5 -62
- vantage6/cli/node/clean.py +6 -2
- vantage6/cli/node/common/__init__.py +26 -4
- vantage6/cli/node/create_private_key.py +10 -2
- vantage6/cli/node/new.py +7 -3
- vantage6/cli/node/restart.py +128 -0
- vantage6/cli/node/set_api_key.py +7 -3
- vantage6/cli/node/start.py +12 -4
- vantage6/cli/node/stop.py +7 -3
- vantage6/cli/node/version.py +7 -3
- vantage6/cli/server/attach.py +5 -51
- vantage6/cli/server/new.py +7 -3
- vantage6/cli/server/start.py +1 -1
- vantage6/cli/server/stop.py +7 -3
- vantage6/cli/template/node_config.j2 +3 -1
- vantage6/cli/test/common/diagnostic_runner.py +2 -4
- vantage6/cli/test/feature_tester.py +10 -3
- vantage6/cli/test/integration_test.py +113 -113
- vantage6/cli/utils.py +5 -1
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a9.dist-info}/METADATA +5 -5
- vantage6-5.0.0a9.dist-info/RECORD +70 -0
- vantage6/cli/dev/create.py +0 -632
- vantage6/cli/dev/data/olympic_athletes_2016.csv +0 -2425
- vantage6/cli/dev/remove.py +0 -94
- vantage6/cli/dev/start.py +0 -123
- vantage6/cli/dev/stop.py +0 -47
- vantage6/cli/dev/utils.py +0 -24
- vantage6-5.0.0a0.dist-info/RECORD +0 -75
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a9.dist-info}/WHEEL +0 -0
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a9.dist-info}/entry_points.txt +0 -0
- {vantage6-5.0.0a0.dist-info → vantage6-5.0.0a9.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import click
|
|
3
|
+
import questionary as q
|
|
4
|
+
import docker
|
|
5
|
+
|
|
6
|
+
from vantage6.common import warning, error
|
|
7
|
+
from vantage6.common.docker.addons import check_docker_running
|
|
8
|
+
from vantage6.cli.common.utils import get_name_from_container_name
|
|
9
|
+
from vantage6.cli.node.stop import cli_node_stop
|
|
10
|
+
from vantage6.cli.node.common import find_running_node_names
|
|
11
|
+
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.command()
|
|
15
|
+
@click.option("-n", "--name", default=None, help="Configuration name")
|
|
16
|
+
@click.option(
|
|
17
|
+
"--system",
|
|
18
|
+
"system_folders",
|
|
19
|
+
flag_value=True,
|
|
20
|
+
help="Search for configuration in system folders instead of " "user folders",
|
|
21
|
+
)
|
|
22
|
+
@click.option(
|
|
23
|
+
"--user",
|
|
24
|
+
"system_folders",
|
|
25
|
+
flag_value=False,
|
|
26
|
+
default=N_FOL,
|
|
27
|
+
help="Search for configuration in the user folders instead of "
|
|
28
|
+
"system folders. This is the default.",
|
|
29
|
+
)
|
|
30
|
+
@click.option("-i", "--image", default=None, help="Node Docker image to use")
|
|
31
|
+
@click.option(
|
|
32
|
+
"--keep/--auto-remove",
|
|
33
|
+
default=False,
|
|
34
|
+
help="Keep node container after finishing. Useful for debugging",
|
|
35
|
+
)
|
|
36
|
+
@click.option(
|
|
37
|
+
"--force-db-mount",
|
|
38
|
+
is_flag=True,
|
|
39
|
+
help="Always mount node databases; skip the check if they are existing files.",
|
|
40
|
+
)
|
|
41
|
+
@click.option(
|
|
42
|
+
"--attach/--detach",
|
|
43
|
+
default=False,
|
|
44
|
+
help="Show node logs on the current console after starting the " "node",
|
|
45
|
+
)
|
|
46
|
+
@click.option(
|
|
47
|
+
"--mount-src",
|
|
48
|
+
default="",
|
|
49
|
+
help="Override vantage6 source code in container with the source"
|
|
50
|
+
" code in this path",
|
|
51
|
+
)
|
|
52
|
+
@click.option("--all", "all_nodes", flag_value=True, help="Stop all running nodes")
|
|
53
|
+
@click.option(
|
|
54
|
+
"--force",
|
|
55
|
+
"force",
|
|
56
|
+
flag_value=True,
|
|
57
|
+
help="Kill nodes instantly; don't wait for them to shut down",
|
|
58
|
+
)
|
|
59
|
+
@click.pass_context
|
|
60
|
+
def cli_node_restart(
|
|
61
|
+
click_ctx: click.Context,
|
|
62
|
+
name: str,
|
|
63
|
+
system_folders: bool,
|
|
64
|
+
image: str,
|
|
65
|
+
keep: bool,
|
|
66
|
+
mount_src: str,
|
|
67
|
+
attach: bool,
|
|
68
|
+
force_db_mount: bool,
|
|
69
|
+
all_nodes: bool,
|
|
70
|
+
force: bool,
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Restart the node"""
|
|
73
|
+
check_docker_running()
|
|
74
|
+
client = docker.from_env()
|
|
75
|
+
|
|
76
|
+
running_node_names = find_running_node_names(client)
|
|
77
|
+
if not running_node_names:
|
|
78
|
+
warning("No nodes are currently running. No action taken.")
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
if attach and all_nodes:
|
|
82
|
+
error(
|
|
83
|
+
"Cannot attach logs of all nodes at once. Please remove either the "
|
|
84
|
+
"'--all' or '--attach' option."
|
|
85
|
+
)
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
if all_nodes:
|
|
89
|
+
names = [
|
|
90
|
+
get_name_from_container_name(container_name)
|
|
91
|
+
for container_name in running_node_names
|
|
92
|
+
]
|
|
93
|
+
else:
|
|
94
|
+
if not name:
|
|
95
|
+
try:
|
|
96
|
+
container_name = q.select(
|
|
97
|
+
"Select the node you wish to restart:", choices=running_node_names
|
|
98
|
+
).unsafe_ask()
|
|
99
|
+
except KeyboardInterrupt:
|
|
100
|
+
error("Aborted by user!")
|
|
101
|
+
return
|
|
102
|
+
names = [get_name_from_container_name(container_name)]
|
|
103
|
+
else:
|
|
104
|
+
names = [name]
|
|
105
|
+
|
|
106
|
+
for node_name in names:
|
|
107
|
+
click_ctx.invoke(
|
|
108
|
+
cli_node_stop,
|
|
109
|
+
name=node_name,
|
|
110
|
+
system_folders=system_folders,
|
|
111
|
+
all_nodes=False,
|
|
112
|
+
force=force,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
cmd = ["v6", "node", "start", "--name", node_name]
|
|
116
|
+
if system_folders:
|
|
117
|
+
cmd.append("--system")
|
|
118
|
+
if image:
|
|
119
|
+
cmd.extend(["--image", image])
|
|
120
|
+
if keep:
|
|
121
|
+
cmd.append("--keep")
|
|
122
|
+
if mount_src:
|
|
123
|
+
cmd.extend(["--mount-src", mount_src])
|
|
124
|
+
if attach:
|
|
125
|
+
cmd.append("--attach")
|
|
126
|
+
if force_db_mount:
|
|
127
|
+
cmd.append("--force-db-mount")
|
|
128
|
+
subprocess.run(cmd, check=True)
|
vantage6/cli/node/set_api_key.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import click
|
|
2
2
|
import questionary as q
|
|
3
3
|
|
|
4
|
-
from vantage6.common import error, info,
|
|
4
|
+
from vantage6.common import error, info, ensure_config_dir_writable
|
|
5
5
|
from vantage6.cli.context.node import NodeContext
|
|
6
6
|
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
7
7
|
from vantage6.cli.configuration_wizard import NodeConfigurationManager
|
|
@@ -33,12 +33,16 @@ def cli_node_set_api_key(name: str, api_key: str, system_folders: bool) -> None:
|
|
|
33
33
|
name = select_node(name, system_folders)
|
|
34
34
|
|
|
35
35
|
# Check that we can write in the config folder
|
|
36
|
-
if not
|
|
36
|
+
if not ensure_config_dir_writable(system_folders):
|
|
37
37
|
error("Your user does not have write access to all folders. Exiting")
|
|
38
38
|
exit(1)
|
|
39
39
|
|
|
40
40
|
if not api_key:
|
|
41
|
-
|
|
41
|
+
try:
|
|
42
|
+
api_key = q.text("Please enter your new API key:").unsafe_ask()
|
|
43
|
+
except KeyboardInterrupt:
|
|
44
|
+
error("API key input aborted.")
|
|
45
|
+
exit(1)
|
|
42
46
|
|
|
43
47
|
# get configuration manager
|
|
44
48
|
ctx = NodeContext(name, system_folders=system_folders)
|
vantage6/cli/node/start.py
CHANGED
|
@@ -177,7 +177,7 @@ def cli_node_start(
|
|
|
177
177
|
if Path(fullpath).exists():
|
|
178
178
|
mounts.append(("/mnt/private_key.pem", str(fullpath)))
|
|
179
179
|
else:
|
|
180
|
-
warning(f"
|
|
180
|
+
warning(f"Private key file is provided {fullpath}, but does not exist")
|
|
181
181
|
|
|
182
182
|
# Mount private keys for ssh tunnels
|
|
183
183
|
ssh_tunnels = ctx.config.get("ssh-tunnels", [])
|
|
@@ -235,15 +235,23 @@ def cli_node_start(
|
|
|
235
235
|
label_capitals = label.upper()
|
|
236
236
|
|
|
237
237
|
try:
|
|
238
|
-
|
|
238
|
+
db_file_exists = Path(uri).exists()
|
|
239
239
|
except Exception:
|
|
240
240
|
# If the database uri cannot be parsed, it is definitely not a
|
|
241
241
|
# file. In case of http servers or sql servers, checking the path
|
|
242
242
|
# of the the uri will lead to an OS-dependent error, which is why
|
|
243
243
|
# we catch all exceptions here.
|
|
244
|
-
|
|
244
|
+
db_file_exists = False
|
|
245
245
|
|
|
246
|
-
if
|
|
246
|
+
if db_type in ["folder", "csv", "parquet", "excel"] and not db_file_exists:
|
|
247
|
+
error(
|
|
248
|
+
f"Database {Fore.RED}{uri}{Style.RESET_ALL} not found. Databases of "
|
|
249
|
+
f"type '{db_type}' must be present on the harddrive. Please update "
|
|
250
|
+
"your node configuration file."
|
|
251
|
+
)
|
|
252
|
+
exit(1)
|
|
253
|
+
|
|
254
|
+
if not db_file_exists and not force_db_mount:
|
|
247
255
|
debug(" - non file-based database added")
|
|
248
256
|
env[f"{label_capitals}_DATABASE_URI"] = uri
|
|
249
257
|
else:
|
vantage6/cli/node/stop.py
CHANGED
|
@@ -69,9 +69,13 @@ def cli_node_stop(
|
|
|
69
69
|
_stop_node(client, container_name, force, system_folders)
|
|
70
70
|
else:
|
|
71
71
|
if not name:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
try:
|
|
73
|
+
container_name = q.select(
|
|
74
|
+
"Select the node you wish to stop:", choices=running_node_names
|
|
75
|
+
).unsafe_ask()
|
|
76
|
+
except KeyboardInterrupt:
|
|
77
|
+
error("Aborted by user!")
|
|
78
|
+
return
|
|
75
79
|
else:
|
|
76
80
|
post_fix = "system" if system_folders else "user"
|
|
77
81
|
container_name = f"{APPNAME}-{name}-{post_fix}"
|
vantage6/cli/node/version.py
CHANGED
|
@@ -42,9 +42,13 @@ def cli_node_version(name: str, system_folders: bool) -> None:
|
|
|
42
42
|
"nodes that are running"
|
|
43
43
|
)
|
|
44
44
|
exit(1)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
try:
|
|
46
|
+
name = q.select(
|
|
47
|
+
"Select the node you wish to inspect:", choices=running_node_names
|
|
48
|
+
).unsafe_ask()
|
|
49
|
+
except KeyboardInterrupt:
|
|
50
|
+
error("Aborted by user!")
|
|
51
|
+
return
|
|
48
52
|
else:
|
|
49
53
|
post_fix = "system" if system_folders else "user"
|
|
50
54
|
name = f"{APPNAME}-{name}-{post_fix}"
|
vantage6/cli/server/attach.py
CHANGED
|
@@ -1,59 +1,13 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from threading import Thread
|
|
3
|
-
|
|
4
1
|
import click
|
|
5
|
-
import questionary as q
|
|
6
|
-
import docker
|
|
7
|
-
|
|
8
|
-
from colorama import Fore, Style
|
|
9
|
-
|
|
10
|
-
from vantage6.common import info, error
|
|
11
|
-
from vantage6.common.docker.addons import check_docker_running
|
|
12
|
-
from vantage6.common.globals import APPNAME, InstanceType
|
|
13
2
|
|
|
14
|
-
from vantage6.
|
|
15
|
-
from vantage6.cli.common.utils import
|
|
3
|
+
from vantage6.common import info
|
|
4
|
+
from vantage6.cli.common.utils import attach_logs
|
|
16
5
|
|
|
17
6
|
|
|
18
7
|
@click.command()
|
|
19
|
-
|
|
20
|
-
@click.option("--system", "system_folders", flag_value=True)
|
|
21
|
-
@click.option(
|
|
22
|
-
"--user", "system_folders", flag_value=False, default=DEFAULT_SERVER_SYSTEM_FOLDERS
|
|
23
|
-
)
|
|
24
|
-
def cli_server_attach(name: str, system_folders: bool) -> None:
|
|
8
|
+
def cli_server_attach() -> None:
|
|
25
9
|
"""
|
|
26
10
|
Show the server logs in the current console.
|
|
27
11
|
"""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
running_servers = client.containers.list(
|
|
32
|
-
filters={"label": f"{APPNAME}-type={InstanceType.SERVER}"}
|
|
33
|
-
)
|
|
34
|
-
running_server_names = [node.name for node in running_servers]
|
|
35
|
-
|
|
36
|
-
if not name:
|
|
37
|
-
name = q.select(
|
|
38
|
-
"Select the server you wish to inspect:", choices=running_server_names
|
|
39
|
-
).ask()
|
|
40
|
-
else:
|
|
41
|
-
post_fix = "system" if system_folders else "user"
|
|
42
|
-
name = f"{APPNAME}-{name}-{post_fix}-{InstanceType.SERVER}"
|
|
43
|
-
|
|
44
|
-
if name in running_server_names:
|
|
45
|
-
container = client.containers.get(name)
|
|
46
|
-
logs = container.attach(stream=True, logs=True, stdout=True)
|
|
47
|
-
Thread(target=print_log_worker, args=(logs,), daemon=True).start()
|
|
48
|
-
while True:
|
|
49
|
-
try:
|
|
50
|
-
time.sleep(1)
|
|
51
|
-
except KeyboardInterrupt:
|
|
52
|
-
info("Closing log file. Keyboard Interrupt.")
|
|
53
|
-
info(
|
|
54
|
-
"Note that your server is still running! Shut it down "
|
|
55
|
-
f"with {Fore.RED}v6 server stop{Style.RESET_ALL}"
|
|
56
|
-
)
|
|
57
|
-
exit(0)
|
|
58
|
-
else:
|
|
59
|
-
error(f"{Fore.RED}{name}{Style.RESET_ALL} was not running!?")
|
|
12
|
+
info("Attaching to server logs...")
|
|
13
|
+
attach_logs("app=vantage6-server", "component=vantage6-server")
|
vantage6/cli/server/new.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import click
|
|
2
2
|
from colorama import Fore, Style
|
|
3
3
|
|
|
4
|
-
from vantage6.common import info, error,
|
|
4
|
+
from vantage6.common import info, error, ensure_config_dir_writable
|
|
5
5
|
from vantage6.cli.globals import DEFAULT_SERVER_SYSTEM_FOLDERS
|
|
6
6
|
from vantage6.cli.context.server import ServerContext
|
|
7
7
|
from vantage6.cli.configuration_wizard import configuration_wizard
|
|
@@ -36,7 +36,7 @@ def cli_server_new(name: str, system_folders: bool) -> None:
|
|
|
36
36
|
exit(1)
|
|
37
37
|
|
|
38
38
|
# Check that we can write in this folder
|
|
39
|
-
if not
|
|
39
|
+
if not ensure_config_dir_writable(system_folders):
|
|
40
40
|
error("Your user does not have write access to all folders. Exiting")
|
|
41
41
|
info(
|
|
42
42
|
f"Create a new server using '{Fore.GREEN}v6 server new "
|
|
@@ -45,7 +45,11 @@ def cli_server_new(name: str, system_folders: bool) -> None:
|
|
|
45
45
|
exit(1)
|
|
46
46
|
|
|
47
47
|
# create config in ctx location
|
|
48
|
-
|
|
48
|
+
try:
|
|
49
|
+
cfg_file = configuration_wizard(InstanceType.SERVER, name, system_folders)
|
|
50
|
+
except KeyboardInterrupt:
|
|
51
|
+
error("Configuration creation aborted.")
|
|
52
|
+
exit(1)
|
|
49
53
|
info(f"New configuration created: {Fore.GREEN}{cfg_file}{Style.RESET_ALL}")
|
|
50
54
|
|
|
51
55
|
# info(f"root user created.")
|
vantage6/cli/server/start.py
CHANGED
vantage6/cli/server/stop.py
CHANGED
|
@@ -53,9 +53,13 @@ def cli_server_stop(name: str, system_folders: bool, all_servers: bool):
|
|
|
53
53
|
|
|
54
54
|
# make sure we have a configuration name to work with
|
|
55
55
|
if not name:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
try:
|
|
57
|
+
container_name = q.select(
|
|
58
|
+
"Select the server you wish to stop:", choices=running_server_names
|
|
59
|
+
).unsafe_ask()
|
|
60
|
+
except KeyboardInterrupt:
|
|
61
|
+
error("Aborted by user!")
|
|
62
|
+
return
|
|
59
63
|
else:
|
|
60
64
|
post_fix = "system" if system_folders else "user"
|
|
61
65
|
container_name = f"{APPNAME}-{name}-{post_fix}-{InstanceType.SERVER}"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
api_key: {{ api_key }}
|
|
2
|
-
api_path:
|
|
2
|
+
api_path: {{ api_path }}
|
|
3
3
|
databases:
|
|
4
4
|
{% for label, path in databases.items() %}
|
|
5
5
|
- label: {{ label }}
|
|
@@ -28,6 +28,8 @@ logging:
|
|
|
28
28
|
name: docker.utils.config
|
|
29
29
|
- level: warning
|
|
30
30
|
name: docker.auth
|
|
31
|
+
- level: warning
|
|
32
|
+
name: kubernetes.client.rest
|
|
31
33
|
port: {{ port }}
|
|
32
34
|
server_url: {{ server_url }}
|
|
33
35
|
task_dir: {{ task_dir}}
|
|
@@ -97,9 +97,7 @@ class DiagnosticRunner:
|
|
|
97
97
|
name="test",
|
|
98
98
|
description="Basic Diagnostic test",
|
|
99
99
|
image=DIAGNOSTICS_IMAGE,
|
|
100
|
-
|
|
101
|
-
"method": "base_features",
|
|
102
|
-
},
|
|
100
|
+
method="base_features",
|
|
103
101
|
organizations=self.organization_ids,
|
|
104
102
|
databases=[{"label": "default"}],
|
|
105
103
|
)
|
|
@@ -123,8 +121,8 @@ class DiagnosticRunner:
|
|
|
123
121
|
name="test",
|
|
124
122
|
description="VPN Diagnostic test",
|
|
125
123
|
image=DIAGNOSTICS_IMAGE,
|
|
124
|
+
method="vpn_features",
|
|
126
125
|
input_={
|
|
127
|
-
"method": "vpn_features",
|
|
128
126
|
"kwargs": {"other_nodes": self.organization_ids},
|
|
129
127
|
},
|
|
130
128
|
organizations=self.organization_ids,
|
|
@@ -16,13 +16,13 @@ from vantage6.cli.test.common.diagnostic_runner import DiagnosticRunner
|
|
|
16
16
|
@click.option(
|
|
17
17
|
"--username",
|
|
18
18
|
type=str,
|
|
19
|
-
default="
|
|
19
|
+
default="dev_admin",
|
|
20
20
|
help="Username of vantage6 user account to create the task with",
|
|
21
21
|
)
|
|
22
22
|
@click.option(
|
|
23
23
|
"--password",
|
|
24
24
|
type=str,
|
|
25
|
-
default="
|
|
25
|
+
default="password",
|
|
26
26
|
help="Password of vantage6 user account to create the task with",
|
|
27
27
|
)
|
|
28
28
|
@click.option(
|
|
@@ -56,6 +56,12 @@ from vantage6.cli.test.common.diagnostic_runner import DiagnosticRunner
|
|
|
56
56
|
default=None,
|
|
57
57
|
help="Path to the private key for end-to-end encryption",
|
|
58
58
|
)
|
|
59
|
+
@click.option(
|
|
60
|
+
"--mfa-code",
|
|
61
|
+
type=str,
|
|
62
|
+
help="Multi-factor authentication code. Use this if MFA is enabled on the "
|
|
63
|
+
"server.",
|
|
64
|
+
)
|
|
59
65
|
def cli_test_features(
|
|
60
66
|
host: str,
|
|
61
67
|
port: int,
|
|
@@ -68,6 +74,7 @@ def cli_test_features(
|
|
|
68
74
|
online_only: bool,
|
|
69
75
|
no_vpn: bool,
|
|
70
76
|
private_key: str | None,
|
|
77
|
+
mfa_code: str | None,
|
|
71
78
|
) -> list[dict]:
|
|
72
79
|
"""
|
|
73
80
|
Run diagnostic checks on an existing vantage6 network.
|
|
@@ -83,7 +90,7 @@ def cli_test_features(
|
|
|
83
90
|
organizations = None
|
|
84
91
|
|
|
85
92
|
client = UserClient(host=host, port=port, path=api_path, log_level="critical")
|
|
86
|
-
client.authenticate(username=username, password=password)
|
|
93
|
+
client.authenticate(username=username, password=password, mfa_code=mfa_code)
|
|
87
94
|
client.setup_encryption(private_key)
|
|
88
95
|
diagnose = DiagnosticRunner(client, collaboration, organizations, online_only)
|
|
89
96
|
res = diagnose(base=True, vpn=not no_vpn)
|