vantage6 4.6.1__tar.gz → 4.7.0__tar.gz

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.

Files changed (83) hide show
  1. {vantage6-4.6.1 → vantage6-4.7.0}/PKG-INFO +3 -3
  2. {vantage6-4.6.1 → vantage6-4.7.0}/setup.py +3 -0
  3. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/_version.py +1 -1
  4. vantage6-4.7.0/vantage6/cli/algostore/remove.py +52 -0
  5. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/algostore/start.py +0 -6
  6. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/algostore/stop.py +8 -8
  7. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/cli.py +2 -0
  8. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/dev/create.py +179 -45
  9. vantage6-4.7.0/vantage6/cli/dev/data/olympic_athletes_2016.csv +2425 -0
  10. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/dev/remove.py +36 -5
  11. vantage6-4.7.0/vantage6/cli/dev/start.py +121 -0
  12. vantage6-4.7.0/vantage6/cli/dev/stop.py +47 -0
  13. vantage6-4.7.0/vantage6/cli/dev/utils.py +24 -0
  14. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/globals.py +3 -0
  15. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/remove.py +4 -5
  16. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/start.py +5 -1
  17. vantage6-4.7.0/vantage6/cli/rabbitmq/__init__.py +0 -0
  18. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/rabbitmq/queue_manager.py +1 -1
  19. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/import_.py +2 -2
  20. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/remove.py +14 -4
  21. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/stop.py +1 -1
  22. vantage6-4.7.0/vantage6/cli/template/algo_store_config.j2 +23 -0
  23. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/template/node_config.j2 +11 -0
  24. vantage6-4.7.0/vantage6/cli/template/server_config.j2 +35 -0
  25. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/template/server_import_config.j2 +3 -4
  26. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/test/integration_test.py +1 -1
  27. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6.egg-info/PKG-INFO +3 -3
  28. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6.egg-info/SOURCES.txt +4 -0
  29. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6.egg-info/requires.txt +3 -2
  30. vantage6-4.6.1/vantage6/cli/dev/start.py +0 -52
  31. vantage6-4.6.1/vantage6/cli/dev/stop.py +0 -32
  32. vantage6-4.6.1/vantage6/cli/rabbitmq/__init__.py +0 -28
  33. vantage6-4.6.1/vantage6/cli/template/server_config.j2 +0 -16
  34. {vantage6-4.6.1 → vantage6-4.7.0}/setup.cfg +0 -0
  35. {vantage6-4.6.1 → vantage6-4.7.0}/tests_cli/__init__.py +0 -0
  36. {vantage6-4.6.1 → vantage6-4.7.0}/tests_cli/test_example.py +0 -0
  37. {vantage6-4.6.1 → vantage6-4.7.0}/tests_cli/test_node_cli.py +0 -0
  38. {vantage6-4.6.1 → vantage6-4.7.0}/tests_cli/test_server_cli.py +0 -0
  39. {vantage6-4.6.1 → vantage6-4.7.0}/tests_cli/test_wizard.py +0 -0
  40. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/__build__ +0 -0
  41. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/__init__.py +0 -0
  42. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/algorithm/create.py +0 -0
  43. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/algorithm/update.py +0 -0
  44. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/algostore/attach.py +0 -0
  45. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/algostore/files.py +0 -0
  46. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/algostore/list.py +0 -0
  47. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/algostore/new.py +0 -0
  48. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/common/decorator.py +0 -0
  49. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/common/start.py +0 -0
  50. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/common/utils.py +0 -0
  51. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/configuration_manager.py +0 -0
  52. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/configuration_wizard.py +0 -0
  53. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/context/__init__.py +0 -0
  54. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/context/algorithm_store.py +0 -0
  55. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/context/base_server.py +0 -0
  56. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/context/node.py +0 -0
  57. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/context/server.py +0 -0
  58. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/attach.py +0 -0
  59. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/clean.py +0 -0
  60. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/common/__init__.py +0 -0
  61. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/create_private_key.py +0 -0
  62. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/files.py +0 -0
  63. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/list.py +0 -0
  64. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/new.py +0 -0
  65. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/set_api_key.py +0 -0
  66. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/stop.py +0 -0
  67. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/node/version.py +0 -0
  68. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/rabbitmq/definitions.py +0 -0
  69. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/rabbitmq/rabbitmq.config +0 -0
  70. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/attach.py +0 -0
  71. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/common/__init__.py +0 -0
  72. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/files.py +0 -0
  73. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/list.py +0 -0
  74. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/new.py +0 -0
  75. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/shell.py +0 -0
  76. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/start.py +0 -0
  77. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/server/version.py +0 -0
  78. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/test/common/diagnostic_runner.py +0 -0
  79. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/test/feature_tester.py +0 -0
  80. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6/cli/utils.py +0 -0
  81. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6.egg-info/dependency_links.txt +0 -0
  82. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6.egg-info/entry_points.txt +0 -0
  83. {vantage6-4.6.1 → vantage6-4.7.0}/vantage6.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vantage6
3
- Version: 4.6.1
3
+ Version: 4.7.0
4
4
  Summary: vantage6 command line interface
5
5
  Home-page: https://github.com/vantage6/vantage6
6
6
  Requires-Python: >=3.10
@@ -88,7 +88,7 @@ v6 server attach
88
88
 
89
89
  From here you can use the [vantage6-client](https://pypi.org/project/vantage6-client) to interact with the server. The demo network has a pre-configured organization with the following credentials:
90
90
 
91
- - Username: `org_1-admin`
91
+ - Username: `dev_admin`
92
92
  - Password: `password`
93
93
 
94
94
  For example, you can create a new organization by running:
@@ -97,7 +97,7 @@ For example, you can create a new organization by running:
97
97
  from vantage6.client import Client
98
98
 
99
99
  client = Client('http://127.0.0.1', 5000, '/api', log_level='debug')
100
- client.authenticate('org_1-admin', 'password')
100
+ client.authenticate('dev_admin', 'password')
101
101
  client.setup_encryption(None)
102
102
 
103
103
  client.organization.create(
@@ -39,6 +39,7 @@ setup(
39
39
  "docker==7.1.0",
40
40
  "ipython==8.10.0",
41
41
  "jinja2==3.1.4",
42
+ "pandas>=1.5.3",
42
43
  "questionary==1.10.0",
43
44
  "rich==13.5.2",
44
45
  "schema==0.7.5",
@@ -60,6 +61,8 @@ setup(
60
61
  "template/node_config.j2",
61
62
  "template/server_config.j2",
62
63
  "template/server_import_config.j2",
64
+ "template/algo_store_config.j2",
65
+ "dev/data/olympic_athletes_2016.csv",
63
66
  ],
64
67
  },
65
68
  entry_points={
@@ -7,7 +7,7 @@ with open(os.path.join(here, "__build__")) as fp:
7
7
  __build__ = json.load(fp)
8
8
 
9
9
  # Module version
10
- version_info = (4, 6, 1, "final", __build__, 0)
10
+ version_info = (4, 7, 0, "final", __build__, 0)
11
11
 
12
12
  # Module version stage suffix map
13
13
  _specifier_ = {"alpha": "a", "beta": "b", "candidate": "rc", "final": ""}
@@ -0,0 +1,52 @@
1
+ import itertools
2
+ from pathlib import Path
3
+ from shutil import rmtree
4
+ import click
5
+ import questionary as q
6
+
7
+ from vantage6.common import info
8
+ from vantage6.common.docker.addons import check_docker_running
9
+ from vantage6.cli.common.decorator import click_insert_context
10
+ from vantage6.cli.context import AlgorithmStoreContext
11
+ from vantage6.cli.utils import remove_file
12
+ from vantage6.common.globals import InstanceType
13
+
14
+
15
+ @click.command()
16
+ @click_insert_context(type_=InstanceType.ALGORITHM_STORE)
17
+ @click.option("-f", "--force", "force", flag_value=True)
18
+ def cli_algo_store_remove(ctx: AlgorithmStoreContext, force: bool) -> None:
19
+ """
20
+ Function to remove an algorithm store.
21
+
22
+ Parameters
23
+ ----------
24
+ ctx : AlgorithmStoreContext
25
+ Algorithm store context object
26
+ force : bool
27
+ Whether to ask for confirmation before removing or not
28
+ """
29
+ check_docker_running()
30
+
31
+ if not force:
32
+ if not q.confirm(
33
+ "This algorithm store will be deleted permanently including its "
34
+ "configuration. Are you sure?",
35
+ default=False,
36
+ ).ask():
37
+ info("Algorithm store will not be deleted")
38
+ exit(0)
39
+
40
+ # now remove the folders...
41
+ remove_file(ctx.config_file, "configuration")
42
+
43
+ # ensure log files are closed before removing
44
+ log_dir = Path(ctx.log_file.parent)
45
+ info(f"Removing log directory: {log_dir}")
46
+ for handler in itertools.chain(ctx.log.handlers, ctx.log.root.handlers):
47
+ handler.close()
48
+ # remove the whole folder with all the log files (if it exists)
49
+ try:
50
+ rmtree(log_dir)
51
+ except FileNotFoundError:
52
+ pass
@@ -68,11 +68,6 @@ def cli_algo_store_start(
68
68
  if mount:
69
69
  mounts.append(mount)
70
70
 
71
- volume_spec = [
72
- ("/var/run/docker.sock", "/var/run/docker.sock"),
73
- ]
74
- volumes = [f"{v[1]}:{v[0]}" for v in volume_spec]
75
-
76
71
  # The `ip` and `port` refer here to the ip and port within the container.
77
72
  # So we do not really care that is it listening on all interfaces.
78
73
  internal_port = 5000
@@ -90,7 +85,6 @@ def cli_algo_store_start(
90
85
  image,
91
86
  command=cmd,
92
87
  mounts=mounts,
93
- volumes=volumes,
94
88
  detach=True,
95
89
  labels={
96
90
  f"{APPNAME}-type": InstanceType.ALGORITHM_STORE,
@@ -14,31 +14,31 @@ from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
14
14
 
15
15
  @click.command()
16
16
  @click_insert_context(InstanceType.ALGORITHM_STORE)
17
- @click.option("--all", "all_servers", flag_value=True, help="Stop all servers")
18
- def cli_algo_store_stop(ctx: AlgorithmStoreContext, all_servers: bool):
17
+ @click.option("--all", "all_stores", flag_value=True, help="Stop all algorithm stores")
18
+ def cli_algo_store_stop(ctx: AlgorithmStoreContext, all_stores: bool):
19
19
  """
20
20
  Stop one or all running server(s).
21
21
  """
22
22
  check_docker_running()
23
23
  client = docker.from_env()
24
24
 
25
- running_servers = client.containers.list(
25
+ running_stores = client.containers.list(
26
26
  filters={"label": f"{APPNAME}-type={InstanceType.ALGORITHM_STORE}"}
27
27
  )
28
28
 
29
- if not running_servers:
29
+ if not running_stores:
30
30
  warning("No algorithm stores are currently running.")
31
31
  return
32
32
 
33
- running_server_names = [server.name for server in running_servers]
33
+ running_store_names = [server.name for server in running_stores]
34
34
 
35
- if all_servers:
36
- for container_name in running_server_names:
35
+ if all_stores:
36
+ for container_name in running_store_names:
37
37
  _stop_algorithm_store(client, container_name)
38
38
  return
39
39
 
40
40
  container_name = ctx.docker_container_name
41
- if container_name not in running_server_names:
41
+ if container_name not in running_store_names:
42
42
  error(f"{Fore.RED}{ctx.name}{Style.RESET_ALL} is not running!")
43
43
  return
44
44
 
@@ -35,6 +35,7 @@ from vantage6.cli.algostore.start import cli_algo_store_start
35
35
  from vantage6.cli.algostore.stop import cli_algo_store_stop
36
36
  from vantage6.cli.algostore.files import cli_algo_store_files
37
37
  from vantage6.cli.algostore.list import cli_algo_store_configuration_list
38
+ from vantage6.cli.algostore.remove import cli_algo_store_remove
38
39
 
39
40
 
40
41
  # Define the server group
@@ -138,6 +139,7 @@ cli_algo_store.add_command(cli_algo_store_start, name="start")
138
139
  cli_algo_store.add_command(cli_algo_store_stop, name="stop")
139
140
  cli_algo_store.add_command(cli_algo_store_files, name="files")
140
141
  cli_algo_store.add_command(cli_algo_store_configuration_list, name="list")
142
+ cli_algo_store.add_command(cli_algo_store_remove, name="remove")
141
143
 
142
144
 
143
145
  # Define the overall group
@@ -1,13 +1,17 @@
1
1
  from pathlib import Path
2
- import csv
2
+ from importlib import resources as impresources
3
3
  import yaml
4
4
  import click
5
+ import pandas as pd
6
+
5
7
  from jinja2 import Environment, FileSystemLoader
6
8
  from colorama import Fore, Style
7
9
 
8
10
  from vantage6.common.globals import APPNAME, InstanceType
9
11
  from vantage6.common import info, error, generate_apikey
10
12
 
13
+ import vantage6.cli.dev.data as data_dir
14
+ from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
11
15
  from vantage6.cli.globals import PACKAGE_FOLDER
12
16
  from vantage6.cli.context.server import ServerContext
13
17
  from vantage6.cli.context.node import NodeContext
@@ -16,49 +20,45 @@ from vantage6.cli.server.import_ import cli_server_import
16
20
  from vantage6.cli.utils import prompt_config_name
17
21
 
18
22
 
19
- def create_dummy_data(node_name: str, dev_folder: Path) -> Path:
20
- """Synthesize csv dataset.
23
+ def create_node_data_files(num_nodes: int, server_name: str) -> list[Path]:
24
+ """Create data files for nodes.
21
25
 
22
26
  Parameters
23
27
  ----------
24
- node_name : str
25
- Name of node to be used as part of dataset.
26
- dev_folder : Path
27
- Path to the dev folder.
28
+ num_nodes : int
29
+ Number of nodes to create data files for.
30
+ server_name : str
31
+ Name of the server.
28
32
 
29
33
  Returns
30
34
  -------
31
- Path
32
- Directory the data is saved in.
35
+ list[Path]
36
+ List of paths to the created data files.
33
37
  """
34
- header = ["name", "mask", "weapon", "age"]
35
- data = [
36
- ["Raphael", "red", "sai", 44],
37
- ["Donatello", "purple", "bo staff", 60],
38
- ]
39
-
40
- data_file = dev_folder / f"df_{node_name}.csv"
41
- with open(data_file, "w", encoding="UTF8", newline="") as f:
42
- writer = csv.writer(f)
43
-
44
- # write the header
45
- writer.writerow(header)
38
+ info(f"Creating data files for {num_nodes} nodes.")
39
+ data_files = []
40
+ full_df = pd.read_csv(impresources.files(data_dir) / "olympic_athletes_2016.csv")
41
+ length_df = len(full_df)
42
+ for i in range(num_nodes):
43
+ node_name = f"{server_name}_node_{i + 1}"
44
+ dev_folder = NodeContext.instance_folders("node", node_name, False)["dev"]
45
+ data_folder = Path(dev_folder / server_name)
46
+ data_folder.mkdir(parents=True, exist_ok=True)
46
47
 
47
- # write the data
48
- for row in data:
49
- writer.writerow(row)
48
+ # Split the data over the nodes
49
+ start = i * length_df // num_nodes
50
+ end = (i + 1) * length_df // num_nodes
51
+ data = full_df[start:end]
52
+ data_file = data_folder / f"df_{node_name}.csv"
50
53
 
51
- f.close()
52
-
53
- info(
54
- f"Spawned dataset for {Fore.GREEN}{node_name}{Style.RESET_ALL}, "
55
- f"writing to {Fore.GREEN}{data_file}{Style.RESET_ALL}"
56
- )
57
- return data_file
54
+ # write data to file
55
+ data.to_csv(data_file, index=False)
56
+ data_files.append(data_file)
57
+ return data_files
58
58
 
59
59
 
60
60
  def create_node_config_file(
61
- server_url: str, port: int, config: dict, server_name: str
61
+ server_url: str, port: int, config: dict, server_name: str, datafile: Path
62
62
  ) -> None:
63
63
  """Create a node configuration file (YAML).
64
64
 
@@ -77,6 +77,8 @@ def create_node_config_file(
77
77
  additional user_defined_config.
78
78
  server_name : str
79
79
  Configuration name of the dummy server.
80
+ datafile : Path
81
+ Path to the data file for the node to use.
80
82
  """
81
83
  environment = Environment(
82
84
  loader=FileSystemLoader(PACKAGE_FOLDER / APPNAME / "cli" / "template"),
@@ -91,7 +93,6 @@ def create_node_config_file(
91
93
  folders = NodeContext.instance_folders("node", node_name, False)
92
94
  path_to_dev_dir = Path(folders["dev"] / server_name)
93
95
  path_to_dev_dir.mkdir(parents=True, exist_ok=True)
94
- dummy_datafile = create_dummy_data(node_name, path_to_dev_dir)
95
96
 
96
97
  path_to_data_dir = Path(folders["data"])
97
98
  path_to_data_dir.mkdir(parents=True, exist_ok=True)
@@ -104,7 +105,7 @@ def create_node_config_file(
104
105
  node_config = template.render(
105
106
  {
106
107
  "api_key": config["api_key"],
107
- "databases": {"default": dummy_datafile},
108
+ "databases": {"default": datafile},
108
109
  "logging": {"file": f"{node_name}.log"},
109
110
  "port": port,
110
111
  "server_url": server_url,
@@ -176,6 +177,7 @@ def generate_node_configs(
176
177
  """
177
178
  configs = []
178
179
  extra_config = _read_extra_config_file(extra_node_config)
180
+ node_data_files = create_node_data_files(num_nodes, server_name)
179
181
  for i in range(num_nodes):
180
182
  config = {
181
183
  "org_id": i + 1,
@@ -183,7 +185,9 @@ def generate_node_configs(
183
185
  "node_name": f"{server_name}_node_{i + 1}",
184
186
  "user_defined_config": extra_config,
185
187
  }
186
- create_node_config_file(server_url, port, config, server_name)
188
+ create_node_config_file(
189
+ server_url, port, config, server_name, node_data_files[i]
190
+ )
187
191
  configs.append(config)
188
192
 
189
193
  return configs
@@ -257,7 +261,14 @@ def create_vserver_import_config(node_configs: list[dict], server_name: str) ->
257
261
  return full_path
258
262
 
259
263
 
260
- def create_vserver_config(server_name: str, port: int, extra_config_file: Path) -> Path:
264
+ def create_vserver_config(
265
+ server_name: str,
266
+ port: int,
267
+ server_url: str,
268
+ extra_config_file: Path,
269
+ ui_port: int,
270
+ store_port: int,
271
+ ) -> Path:
261
272
  """Creates server configuration file (YAML).
262
273
 
263
274
  Parameters
@@ -266,8 +277,14 @@ def create_vserver_config(server_name: str, port: int, extra_config_file: Path)
266
277
  Server name.
267
278
  port : int
268
279
  Server port.
280
+ server_url : str
281
+ Url of the server this
269
282
  extra_config_file : Path
270
283
  Path to file with additional server configuration.
284
+ ui_port : int
285
+ Port to run the UI on.
286
+ store_port : int
287
+ Port to run the algorithm store on.
271
288
 
272
289
  Returns
273
290
  -------
@@ -285,10 +302,17 @@ def create_vserver_config(server_name: str, port: int, extra_config_file: Path)
285
302
 
286
303
  template = environment.get_template("server_config.j2")
287
304
  server_config = template.render(
288
- port=port, jwt_secret_key=generate_apikey(), user_provided_config=extra_config
305
+ port=port,
306
+ host_uri=server_url,
307
+ jwt_secret_key=generate_apikey(),
308
+ user_provided_config=extra_config,
309
+ ui_port=ui_port,
310
+ store_port=store_port,
289
311
  )
290
312
  folders = ServerContext.instance_folders(
291
- instance_type="server", instance_name=server_name, system_folders=True
313
+ instance_type=InstanceType.SERVER,
314
+ instance_name=server_name,
315
+ system_folders=False,
292
316
  )
293
317
 
294
318
  config_dir = Path(folders["config"] / server_name)
@@ -312,6 +336,71 @@ def create_vserver_config(server_name: str, port: int, extra_config_file: Path)
312
336
  return full_path
313
337
 
314
338
 
339
+ def create_algo_store_config(
340
+ server_name: str,
341
+ server_url: str,
342
+ server_port: int,
343
+ store_port: int,
344
+ extra_config_file: Path,
345
+ ) -> Path:
346
+ """Create algorithm store configuration file (YAML).
347
+
348
+ Parameters
349
+ ----------
350
+ server_name : str
351
+ Server name.
352
+ server_url : str
353
+ Url of the server this store connects to.
354
+ server_port : int
355
+ Port of the server this store connects to.
356
+ port : int
357
+ Port of the algorithm store.
358
+ extra_config_file : Path
359
+ Path to file with additional algorithm store configuration.
360
+ """
361
+ environment = Environment(
362
+ loader=FileSystemLoader(PACKAGE_FOLDER / APPNAME / "cli" / "template"),
363
+ trim_blocks=True,
364
+ lstrip_blocks=True,
365
+ autoescape=True,
366
+ )
367
+
368
+ extra_config = _read_extra_config_file(extra_config_file)
369
+
370
+ template = environment.get_template("algo_store_config.j2")
371
+ store_config = template.render(
372
+ port=store_port,
373
+ server_port=server_port,
374
+ host_uri=server_url,
375
+ user_provided_config=extra_config,
376
+ )
377
+ folders = AlgorithmStoreContext.instance_folders(
378
+ instance_type=InstanceType.ALGORITHM_STORE,
379
+ instance_name="{server_name}_store",
380
+ system_folders=False,
381
+ )
382
+
383
+ config_dir = Path(folders["config"] / f"{server_name}_store")
384
+ config_dir.mkdir(parents=True, exist_ok=True)
385
+ full_path = folders["config"] / f"{server_name}_store.yaml"
386
+ if full_path.exists():
387
+ error(f"Algorithm store configuration file already exists: {full_path}")
388
+ exit(1)
389
+
390
+ try:
391
+ with open(full_path, "x") as f:
392
+ f.write(store_config)
393
+ info(
394
+ "Algorithm store configuration ready, writing to "
395
+ f"{Fore.GREEN}{full_path}{Style.RESET_ALL}"
396
+ )
397
+ except Exception as e:
398
+ error(f"Could not write algorithm store configuration file: {e}")
399
+ exit(1)
400
+
401
+ return full_path
402
+
403
+
315
404
  def demo_network(
316
405
  num_nodes: int,
317
406
  server_url: str,
@@ -319,6 +408,9 @@ def demo_network(
319
408
  server_name: str,
320
409
  extra_server_config: Path,
321
410
  extra_node_config: Path,
411
+ extra_store_config: Path,
412
+ ui_port: int,
413
+ algorithm_store_port: int,
322
414
  ) -> tuple[list[dict], Path, Path]:
323
415
  """Generates the demo network.
324
416
 
@@ -336,6 +428,12 @@ def demo_network(
336
428
  Path to file with additional server configuration.
337
429
  extra_node_config : Path
338
430
  Path to file with additional node configuration.
431
+ extra_store_config : Path
432
+ Path to file with additional algorithm store configuration.
433
+ ui_port : int
434
+ Port to run the UI on.
435
+ algorithm_store_port : int
436
+ Port to run the algorithm store on.
339
437
 
340
438
  Returns
341
439
  -------
@@ -346,8 +444,18 @@ def demo_network(
346
444
  num_nodes, server_url, server_port, server_name, extra_node_config
347
445
  )
348
446
  server_import_config = create_vserver_import_config(node_configs, server_name)
349
- server_config = create_vserver_config(server_name, server_port, extra_server_config)
350
- return (node_configs, server_import_config, server_config)
447
+ server_config = create_vserver_config(
448
+ server_name,
449
+ server_port,
450
+ server_url,
451
+ extra_server_config,
452
+ ui_port,
453
+ algorithm_store_port,
454
+ )
455
+ store_config = create_algo_store_config(
456
+ server_name, server_url, server_port, algorithm_store_port, extra_store_config
457
+ )
458
+ return (node_configs, server_import_config, server_config, store_config)
351
459
 
352
460
 
353
461
  @click.command()
@@ -371,8 +479,20 @@ def demo_network(
371
479
  "-p",
372
480
  "--server-port",
373
481
  type=int,
374
- default=5000,
375
- help="Port to run the server on. Default is 5000.",
482
+ default=7601,
483
+ help="Port to run the server on. Default is 7601.",
484
+ )
485
+ @click.option(
486
+ "--ui-port",
487
+ type=int,
488
+ default=7600,
489
+ help="Port to run the UI on. Default is 7600.",
490
+ )
491
+ @click.option(
492
+ "--algorithm-store-port",
493
+ type=int,
494
+ default=7602,
495
+ help="Port to run the algorithm store on. Default is 7602.",
376
496
  )
377
497
  @click.option(
378
498
  "-i",
@@ -397,6 +517,13 @@ def demo_network(
397
517
  help="YAML File with additional node configuration. This will be"
398
518
  " appended to each of the node configuration files",
399
519
  )
520
+ @click.option(
521
+ "--extra-store-config",
522
+ type=click.Path("rb"),
523
+ default=None,
524
+ help="YAML File with additional algorithm store configuration. This will be"
525
+ " appended to the algorithm store configuration file",
526
+ )
400
527
  @click.pass_context
401
528
  def create_demo_network(
402
529
  click_ctx: click.Context,
@@ -404,9 +531,12 @@ def create_demo_network(
404
531
  num_nodes: int,
405
532
  server_url: str,
406
533
  server_port: int,
534
+ ui_port: int,
535
+ algorithm_store_port: int,
407
536
  image: str = None,
408
537
  extra_server_config: Path = None,
409
538
  extra_node_config: Path = None,
539
+ extra_store_config: Path = None,
410
540
  ) -> dict:
411
541
  """Creates a demo network.
412
542
 
@@ -416,7 +546,7 @@ def create_demo_network(
416
546
  organizations/collaborations/users and tasks.
417
547
  """
418
548
  server_name = prompt_config_name(name)
419
- if not ServerContext.config_exists(server_name):
549
+ if not ServerContext.config_exists(server_name, False):
420
550
  demo = demo_network(
421
551
  num_nodes,
422
552
  server_url,
@@ -424,6 +554,9 @@ def create_demo_network(
424
554
  server_name,
425
555
  extra_server_config,
426
556
  extra_node_config,
557
+ extra_store_config,
558
+ ui_port,
559
+ algorithm_store_port,
427
560
  )
428
561
  info(
429
562
  f"Created {Fore.GREEN}{len(demo[0])}{Style.RESET_ALL} node "
@@ -433,8 +566,8 @@ def create_demo_network(
433
566
  else:
434
567
  error(f"Configuration {Fore.RED}{server_name}{Style.RESET_ALL} already exists!")
435
568
  exit(1)
436
- (node_config, server_import_config, server_config) = demo
437
- ctx = get_server_context(server_name, True, ServerContext)
569
+ (node_config, server_import_config, server_config, store_config) = demo
570
+ ctx = get_server_context(server_name, False, ServerContext)
438
571
  click_ctx.invoke(
439
572
  cli_server_import,
440
573
  ctx=ctx,
@@ -471,4 +604,5 @@ def create_demo_network(
471
604
  "node_configs": node_config,
472
605
  "server_import_config": server_import_config,
473
606
  "server_config": server_config,
607
+ "store_config": store_config,
474
608
  }