vantage6 4.0.2__py3-none-any.whl → 4.1.0b0__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 +60 -55
- tests_cli/test_server_cli.py +30 -30
- vantage6/cli/_version.py +1 -1
- vantage6/cli/cli.py +102 -0
- vantage6/cli/{dev.py → dev/create.py} +18 -151
- vantage6/cli/dev/remove.py +63 -0
- vantage6/cli/dev/start.py +52 -0
- vantage6/cli/dev/stop.py +30 -0
- vantage6/cli/node/attach.py +58 -0
- vantage6/cli/node/clean.py +40 -0
- vantage6/cli/node/common/__init__.py +124 -0
- vantage6/cli/node/create_private_key.py +139 -0
- vantage6/cli/node/files.py +34 -0
- vantage6/cli/node/list.py +62 -0
- vantage6/cli/node/new.py +46 -0
- vantage6/cli/node/remove.py +103 -0
- vantage6/cli/node/set_api_key.py +45 -0
- vantage6/cli/node/start.py +311 -0
- vantage6/cli/node/stop.py +73 -0
- vantage6/cli/node/version.py +47 -0
- vantage6/cli/server/attach.py +54 -0
- vantage6/cli/server/common/__init__.py +146 -0
- vantage6/cli/server/files.py +16 -0
- vantage6/cli/server/import_.py +144 -0
- vantage6/cli/server/list.py +60 -0
- vantage6/cli/server/new.py +50 -0
- vantage6/cli/server/shell.py +42 -0
- vantage6/cli/server/start.py +302 -0
- vantage6/cli/server/stop.py +158 -0
- vantage6/cli/server/version.py +46 -0
- {vantage6-4.0.2.dist-info → vantage6-4.1.0b0.dist-info}/METADATA +7 -6
- vantage6-4.1.0b0.dist-info/RECORD +52 -0
- vantage6-4.1.0b0.dist-info/entry_points.txt +5 -0
- vantage6/cli/node.py +0 -1092
- vantage6/cli/server.py +0 -1033
- vantage6-4.0.2.dist-info/RECORD +0 -28
- vantage6-4.0.2.dist-info/entry_points.txt +0 -4
- {vantage6-4.0.2.dist-info → vantage6-4.1.0b0.dist-info}/WHEEL +0 -0
- {vantage6-4.0.2.dist-info → vantage6-4.1.0b0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import click
|
|
3
|
+
from colorama import Fore, Style
|
|
4
|
+
|
|
5
|
+
from vantage6.common import (
|
|
6
|
+
warning, error, info, debug, bytes_to_base64s,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from vantage6.common.encryption import RSACryptor
|
|
10
|
+
from vantage6.cli.context import NodeContext
|
|
11
|
+
from vantage6.cli.globals import (
|
|
12
|
+
DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
13
|
+
)
|
|
14
|
+
from vantage6.cli.node.common import (
|
|
15
|
+
select_node, create_client_and_authenticate
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@click.command()
|
|
20
|
+
@click.option("-n", "--name", default=None, help="Configuration name")
|
|
21
|
+
@click.option("-c", "--config", default=None,
|
|
22
|
+
help='Absolute path to configuration-file; overrides NAME')
|
|
23
|
+
@click.option('--system', 'system_folders', flag_value=True,
|
|
24
|
+
help="Search for configuration in system folders rather than "
|
|
25
|
+
"user folders")
|
|
26
|
+
@click.option('--user', 'system_folders', flag_value=False, default=N_FOL,
|
|
27
|
+
help="Search for configuration in user folders rather than "
|
|
28
|
+
"system folders. This is the default")
|
|
29
|
+
@click.option('--no-upload', 'upload', flag_value=False, default=True,
|
|
30
|
+
help="Don't upload the public key to the server")
|
|
31
|
+
@click.option("-o", "--organization-name", default=None,
|
|
32
|
+
help="Organization name. Used in the filename of the private key"
|
|
33
|
+
" so that it can easily be recognized again later")
|
|
34
|
+
@click.option('--overwrite', 'overwrite', flag_value=True, default=False,
|
|
35
|
+
help="Overwrite existing private key if present")
|
|
36
|
+
def cli_node_create_private_key(
|
|
37
|
+
name: str, config: str, system_folders: bool, upload: bool,
|
|
38
|
+
organization_name: str, overwrite: bool) -> None:
|
|
39
|
+
"""
|
|
40
|
+
Create and upload a new private key
|
|
41
|
+
|
|
42
|
+
Use this command with caution! Uploading a new key has several
|
|
43
|
+
consequences, e.g. you and other users of your organization
|
|
44
|
+
will no longer be able to read the results of tasks encrypted with current
|
|
45
|
+
key.
|
|
46
|
+
"""
|
|
47
|
+
NodeContext.LOGGING_ENABLED = False
|
|
48
|
+
if config:
|
|
49
|
+
name = Path(config).stem
|
|
50
|
+
ctx = NodeContext(name, system_folders, config)
|
|
51
|
+
else:
|
|
52
|
+
# retrieve context
|
|
53
|
+
name = select_node(name, system_folders)
|
|
54
|
+
|
|
55
|
+
# Create node context
|
|
56
|
+
ctx = NodeContext(name, system_folders)
|
|
57
|
+
|
|
58
|
+
# Authenticate with the server to obtain organization name if it wasn't
|
|
59
|
+
# provided
|
|
60
|
+
if organization_name is None:
|
|
61
|
+
client = create_client_and_authenticate(ctx)
|
|
62
|
+
organization_name = client.whoami.organization_name
|
|
63
|
+
|
|
64
|
+
# create directory where private key goes if it doesn't exist yet
|
|
65
|
+
ctx.type_data_folder(system_folders).mkdir(parents=True, exist_ok=True)
|
|
66
|
+
|
|
67
|
+
# generate new key, and save it
|
|
68
|
+
filename = f"privkey_{organization_name}.pem"
|
|
69
|
+
file_ = ctx.type_data_folder(system_folders) / filename
|
|
70
|
+
|
|
71
|
+
if file_.exists():
|
|
72
|
+
warning(f"File '{Fore.CYAN}{file_}{Style.RESET_ALL}' exists!")
|
|
73
|
+
|
|
74
|
+
if overwrite:
|
|
75
|
+
warning("'--override' specified, so it will be overwritten ...")
|
|
76
|
+
|
|
77
|
+
if file_.exists() and not overwrite:
|
|
78
|
+
error("Could not create private key!")
|
|
79
|
+
warning(
|
|
80
|
+
"If you're **sure** you want to create a new key, "
|
|
81
|
+
"please run this command with the '--overwrite' flag"
|
|
82
|
+
)
|
|
83
|
+
warning("Continuing with existing key instead!")
|
|
84
|
+
private_key = RSACryptor(file_).private_key
|
|
85
|
+
|
|
86
|
+
else:
|
|
87
|
+
try:
|
|
88
|
+
info("Generating new private key")
|
|
89
|
+
private_key = RSACryptor.create_new_rsa_key(file_)
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
error(f"Could not create new private key '{file_}'!?")
|
|
93
|
+
debug(e)
|
|
94
|
+
info("Bailing out ...")
|
|
95
|
+
exit(1)
|
|
96
|
+
|
|
97
|
+
warning(f"Private key written to '{file_}'")
|
|
98
|
+
warning(
|
|
99
|
+
"If you're running multiple nodes, be sure to copy the private "
|
|
100
|
+
"key to the appropriate directories!"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# create public key
|
|
104
|
+
info("Deriving public key")
|
|
105
|
+
public_key = RSACryptor.create_public_key_bytes(private_key)
|
|
106
|
+
|
|
107
|
+
# update config file
|
|
108
|
+
info("Updating configuration")
|
|
109
|
+
ctx.config["encryption"]["private_key"] = str(file_)
|
|
110
|
+
ctx.config_manager.put(ctx.config)
|
|
111
|
+
ctx.config_manager.save(ctx.config_file)
|
|
112
|
+
|
|
113
|
+
# upload key to the server
|
|
114
|
+
if upload:
|
|
115
|
+
info(
|
|
116
|
+
"Uploading public key to the server. "
|
|
117
|
+
"This will overwrite any previously existing key!"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if 'client' not in locals():
|
|
121
|
+
client = create_client_and_authenticate(ctx)
|
|
122
|
+
|
|
123
|
+
# TODO what happens if the user doesn't have permission to upload key?
|
|
124
|
+
# Does that lead to an exception or not?
|
|
125
|
+
try:
|
|
126
|
+
client.request(
|
|
127
|
+
f"/organization/{client.whoami.organization_id}",
|
|
128
|
+
method="patch",
|
|
129
|
+
json={"public_key": bytes_to_base64s(public_key)}
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
except Exception as e:
|
|
133
|
+
error("Could not upload the public key!")
|
|
134
|
+
debug(e)
|
|
135
|
+
exit(1)
|
|
136
|
+
else:
|
|
137
|
+
warning("Public key not uploaded!")
|
|
138
|
+
|
|
139
|
+
info("[Done]")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from vantage6.common import info
|
|
4
|
+
from vantage6.cli.context import NodeContext
|
|
5
|
+
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
6
|
+
from vantage6.cli.node.common import select_node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.command()
|
|
10
|
+
@click.option("-n", "--name", default=None, help="Configuration name")
|
|
11
|
+
@click.option('--system', 'system_folders', flag_value=True,
|
|
12
|
+
help="Search for the configuration in the system folders")
|
|
13
|
+
@click.option('--user', 'system_folders', flag_value=False, default=N_FOL,
|
|
14
|
+
help="Search for the configuration in the user folders. This is "
|
|
15
|
+
"the default")
|
|
16
|
+
def cli_node_files(name: str, system_folders: bool) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Prints the location of important node files.
|
|
19
|
+
|
|
20
|
+
If the specified configuration cannot be found, it exits. Otherwise
|
|
21
|
+
it returns the absolute path to the output.
|
|
22
|
+
"""
|
|
23
|
+
name = select_node(name, system_folders)
|
|
24
|
+
|
|
25
|
+
# create node context
|
|
26
|
+
ctx = NodeContext(name, system_folders=system_folders)
|
|
27
|
+
|
|
28
|
+
# return path of the configuration
|
|
29
|
+
info(f"Configuration file = {ctx.config_file}")
|
|
30
|
+
info(f"Log file = {ctx.log_file}")
|
|
31
|
+
info(f"data folders = {ctx.data_dir}")
|
|
32
|
+
info("Database labels and files")
|
|
33
|
+
for db in ctx.databases:
|
|
34
|
+
info(f" - {db['label']:15} = {db['uri']} (type: {db['type']})")
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import docker
|
|
3
|
+
from colorama import Fore, Style
|
|
4
|
+
|
|
5
|
+
from vantage6.common import warning
|
|
6
|
+
from vantage6.common.globals import APPNAME
|
|
7
|
+
from vantage6.common.docker.addons import check_docker_running
|
|
8
|
+
from vantage6.cli.context import NodeContext
|
|
9
|
+
from vantage6.cli.node.common import find_running_node_names
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.command()
|
|
13
|
+
def cli_node_list() -> None:
|
|
14
|
+
"""
|
|
15
|
+
Lists all node configurations.
|
|
16
|
+
|
|
17
|
+
Note that this command cannot find node configuration files in custom
|
|
18
|
+
directories.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
check_docker_running()
|
|
22
|
+
client = docker.from_env()
|
|
23
|
+
|
|
24
|
+
running_node_names = find_running_node_names(client)
|
|
25
|
+
|
|
26
|
+
header = \
|
|
27
|
+
"\nName"+(21*" ") + \
|
|
28
|
+
"Status"+(10*" ") + \
|
|
29
|
+
"System/User"
|
|
30
|
+
|
|
31
|
+
click.echo(header)
|
|
32
|
+
click.echo("-"*len(header))
|
|
33
|
+
|
|
34
|
+
running = Fore.GREEN + "Running" + Style.RESET_ALL
|
|
35
|
+
stopped = Fore.RED + "Not running" + Style.RESET_ALL
|
|
36
|
+
|
|
37
|
+
# system folders
|
|
38
|
+
configs, f1 = NodeContext.available_configurations(
|
|
39
|
+
system_folders=True)
|
|
40
|
+
for config in configs:
|
|
41
|
+
status = running if f"{APPNAME}-{config.name}-system" in \
|
|
42
|
+
running_node_names else stopped
|
|
43
|
+
click.echo(
|
|
44
|
+
f"{config.name:25}"
|
|
45
|
+
f"{status:25}System "
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# user folders
|
|
49
|
+
configs, f2 = NodeContext.available_configurations(
|
|
50
|
+
system_folders=False)
|
|
51
|
+
for config in configs:
|
|
52
|
+
status = running if f"{APPNAME}-{config.name}-user" in \
|
|
53
|
+
running_node_names else stopped
|
|
54
|
+
click.echo(
|
|
55
|
+
f"{config.name:25}"
|
|
56
|
+
f"{status:25}User "
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
click.echo("-"*53)
|
|
60
|
+
if len(f1)+len(f2):
|
|
61
|
+
warning(
|
|
62
|
+
f"{Fore.RED}Failed imports: {len(f1)+len(f2)}{Style.RESET_ALL}")
|
vantage6/cli/node/new.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from colorama import Fore, Style
|
|
3
|
+
|
|
4
|
+
from vantage6.common import error, info, check_config_writeable
|
|
5
|
+
from vantage6.cli.context import NodeContext
|
|
6
|
+
from vantage6.cli.globals import (
|
|
7
|
+
DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
8
|
+
)
|
|
9
|
+
from vantage6.cli.configuration_wizard import configuration_wizard
|
|
10
|
+
from vantage6.cli.utils import check_config_name_allowed, prompt_config_name
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.command()
|
|
14
|
+
@click.option("-n", "--name", default=None, help="Configuration name")
|
|
15
|
+
@click.option('--system', 'system_folders', flag_value=True,
|
|
16
|
+
help="Store this configuration in the system folders")
|
|
17
|
+
@click.option('--user', 'system_folders', flag_value=False, default=N_FOL,
|
|
18
|
+
help="Store this configuration in the user folders. This is the "
|
|
19
|
+
"default")
|
|
20
|
+
def cli_node_new_configuration(name: str, system_folders: bool) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Create a new node configuration.
|
|
23
|
+
|
|
24
|
+
Checks if the configuration already exists. If this is not the case
|
|
25
|
+
a questionnaire is invoked to create a new configuration file.
|
|
26
|
+
"""
|
|
27
|
+
name = prompt_config_name(name)
|
|
28
|
+
# check if config name is allowed docker name
|
|
29
|
+
check_config_name_allowed(name)
|
|
30
|
+
|
|
31
|
+
# check that this config does not exist
|
|
32
|
+
if NodeContext.config_exists(name, system_folders):
|
|
33
|
+
error(f"Configuration {name} already exists!")
|
|
34
|
+
exit(1)
|
|
35
|
+
|
|
36
|
+
# Check that we can write in this folder
|
|
37
|
+
if not check_config_writeable(system_folders):
|
|
38
|
+
error("Cannot write configuration file. Exiting...")
|
|
39
|
+
exit(1)
|
|
40
|
+
|
|
41
|
+
# create config in ctx location
|
|
42
|
+
flag = "--system" if system_folders else ""
|
|
43
|
+
cfg_file = configuration_wizard("node", name, system_folders)
|
|
44
|
+
info(f"New configuration created: {Fore.GREEN}{cfg_file}{Style.RESET_ALL}")
|
|
45
|
+
info(f"You can start the node by running "
|
|
46
|
+
f"{Fore.GREEN}v6 node start {flag}{Style.RESET_ALL}")
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import questionary as q
|
|
3
|
+
import docker
|
|
4
|
+
import os.path
|
|
5
|
+
import itertools
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from shutil import rmtree
|
|
9
|
+
|
|
10
|
+
from vantage6.common import (
|
|
11
|
+
error, info, debug,
|
|
12
|
+
)
|
|
13
|
+
from vantage6.common.globals import APPNAME
|
|
14
|
+
|
|
15
|
+
from vantage6.common.globals import VPN_CONFIG_FILE
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from vantage6.cli.context import NodeContext
|
|
19
|
+
from vantage6.cli.globals import (
|
|
20
|
+
DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
21
|
+
)
|
|
22
|
+
from vantage6.cli.utils import (
|
|
23
|
+
check_if_docker_daemon_is_running, remove_file
|
|
24
|
+
)
|
|
25
|
+
from vantage6.cli.node.common import select_node, find_running_node_names
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.command()
|
|
29
|
+
@click.option("-n", "--name", default=None, help="Configuration name")
|
|
30
|
+
@click.option('--system', 'system_folders', flag_value=True,
|
|
31
|
+
help="Search for configuration in system folders rather than "
|
|
32
|
+
"user folders")
|
|
33
|
+
@click.option('--user', 'system_folders', flag_value=False, default=N_FOL,
|
|
34
|
+
help="Search for configuration in user folders rather than "
|
|
35
|
+
"system folders. This is the default")
|
|
36
|
+
@click.option('-f', "--force", type=bool, flag_value=True,
|
|
37
|
+
help='Don\'t ask for confirmation')
|
|
38
|
+
def cli_node_remove(name: str, system_folders: bool, force: bool) -> None:
|
|
39
|
+
"""
|
|
40
|
+
Delete a node permanently.
|
|
41
|
+
|
|
42
|
+
Remove the configuration file, log file, and docker volumes attached to
|
|
43
|
+
the node.
|
|
44
|
+
"""
|
|
45
|
+
# select configuration name if none supplied
|
|
46
|
+
name = select_node(name, system_folders)
|
|
47
|
+
|
|
48
|
+
client = docker.from_env()
|
|
49
|
+
check_if_docker_daemon_is_running(client)
|
|
50
|
+
|
|
51
|
+
# check if node is still running, otherwise don't allow deleting it
|
|
52
|
+
running_node_names = find_running_node_names(client)
|
|
53
|
+
|
|
54
|
+
post_fix = "system" if system_folders else "user"
|
|
55
|
+
node_container_name = f"{APPNAME}-{name}-{post_fix}"
|
|
56
|
+
if node_container_name in running_node_names:
|
|
57
|
+
error(f"Node {name} is still running! Please stop the node before "
|
|
58
|
+
"deleting it.")
|
|
59
|
+
exit(1)
|
|
60
|
+
|
|
61
|
+
if not force:
|
|
62
|
+
if not q.confirm(
|
|
63
|
+
"This node will be deleted permanently including its "
|
|
64
|
+
"configuration. Are you sure?", default=False
|
|
65
|
+
).ask():
|
|
66
|
+
info("Node will not be deleted")
|
|
67
|
+
exit(0)
|
|
68
|
+
|
|
69
|
+
# create node context
|
|
70
|
+
ctx = NodeContext(name, system_folders=system_folders)
|
|
71
|
+
|
|
72
|
+
# remove the docker volume and any temporary volumes
|
|
73
|
+
debug("Deleting docker volumes")
|
|
74
|
+
volumes = client.volumes.list()
|
|
75
|
+
for vol in volumes:
|
|
76
|
+
if vol.name.startswith(ctx.docker_volume_name): # includes tmp volumes
|
|
77
|
+
info(f"Deleting docker volume {vol.name}")
|
|
78
|
+
vol.remove()
|
|
79
|
+
# remove docker vpn volume
|
|
80
|
+
if vol.name == ctx.docker_vpn_volume_name:
|
|
81
|
+
info(f"Deleting VPN docker volume {vol.name}")
|
|
82
|
+
vol.remove()
|
|
83
|
+
|
|
84
|
+
# remove the VPN configuration file
|
|
85
|
+
vpn_config_file = os.path.join(ctx.data_dir, 'vpn', VPN_CONFIG_FILE)
|
|
86
|
+
remove_file(vpn_config_file, 'VPN configuration')
|
|
87
|
+
|
|
88
|
+
# remove the config file
|
|
89
|
+
remove_file(ctx.config_file, 'configuration')
|
|
90
|
+
|
|
91
|
+
# remove the log file. As this process opens the log file above, the log
|
|
92
|
+
# handlers need to be closed before deleting
|
|
93
|
+
info(f"Removing log file {ctx.log_file}")
|
|
94
|
+
for handler in itertools.chain(ctx.log.handlers, ctx.log.root.handlers):
|
|
95
|
+
handler.close()
|
|
96
|
+
# remove_file(ctx.log_file, 'log')
|
|
97
|
+
|
|
98
|
+
# removes the whole folder
|
|
99
|
+
rmtree(Path(ctx.log_file.parent))
|
|
100
|
+
|
|
101
|
+
# remove the folder: if it hasn't been started yet this won't exist...
|
|
102
|
+
if Path.exists(ctx.config_dir / name):
|
|
103
|
+
rmtree(ctx.config_dir / name)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import questionary as q
|
|
3
|
+
|
|
4
|
+
from vantage6.common import error, info, check_config_writeable
|
|
5
|
+
from vantage6.cli.context import NodeContext
|
|
6
|
+
from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
|
|
7
|
+
from vantage6.cli.configuration_wizard import NodeConfigurationManager
|
|
8
|
+
from vantage6.cli.node.common import select_node
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.command()
|
|
12
|
+
@click.option("-n", "--name", default=None, help="Configuration name")
|
|
13
|
+
@click.option("--api-key", default=None, help="New API key")
|
|
14
|
+
@click.option('--system', 'system_folders', flag_value=True,
|
|
15
|
+
help="Search for configuration in system folders rather than "
|
|
16
|
+
"user folders")
|
|
17
|
+
@click.option('--user', 'system_folders', flag_value=False, default=N_FOL,
|
|
18
|
+
help="Search for configuration in user folders rather than "
|
|
19
|
+
"system folders. This is the default")
|
|
20
|
+
def cli_node_set_api_key(name: str, api_key: str,
|
|
21
|
+
system_folders: bool) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Put a new API key into the node configuration file
|
|
24
|
+
"""
|
|
25
|
+
# select node name
|
|
26
|
+
name = select_node(name, system_folders)
|
|
27
|
+
|
|
28
|
+
# Check that we can write in the config folder
|
|
29
|
+
if not check_config_writeable(system_folders):
|
|
30
|
+
error("Your user does not have write access to all folders. Exiting")
|
|
31
|
+
exit(1)
|
|
32
|
+
|
|
33
|
+
if not api_key:
|
|
34
|
+
api_key = q.text("Please enter your new API key:").ask()
|
|
35
|
+
|
|
36
|
+
# get configuration manager
|
|
37
|
+
ctx = NodeContext(name, system_folders=system_folders)
|
|
38
|
+
conf_mgr = NodeConfigurationManager.from_file(ctx.config_file)
|
|
39
|
+
|
|
40
|
+
# set new api key, and save the file
|
|
41
|
+
ctx.config['api_key'] = api_key
|
|
42
|
+
conf_mgr.put(ctx.config)
|
|
43
|
+
conf_mgr.save(ctx.config_file)
|
|
44
|
+
info("Your new API key has been uploaded to the config file "
|
|
45
|
+
f"{ctx.config_file}.")
|