Skip to content

Commit 4416e6d

Browse files
authored
Merge pull request #528 from josibake/refactor-config
Refactor hardcoded strings into a config / constants file
2 parents 74fe2bf + 96d9eee commit 4416e6d

File tree

8 files changed

+148
-123
lines changed

8 files changed

+148
-123
lines changed

src/warnet/admin.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import click
55
from rich import print as richprint
66

7+
from .constants import NETWORK_DIR
78
from .namespaces import copy_namespaces_defaults, namespaces
89
from .network import copy_network_defaults
910

@@ -17,22 +18,6 @@ def admin():
1718
admin.add_command(namespaces)
1819

1920

20-
@admin.command()
21-
@click.argument("directory", type=Path)
22-
def create(directory):
23-
"""Create a new warnet project in the specified directory"""
24-
if os.path.exists(directory):
25-
richprint(f"[red]Error: Directory {directory} already exists[/red]")
26-
return
27-
28-
copy_network_defaults(directory)
29-
copy_namespaces_defaults(directory)
30-
richprint(
31-
f"[green]Copied network and namespace example files to {directory / 'networks'}[/green]"
32-
)
33-
richprint(f"[green]Created warnet project structure in {directory}[/green]")
34-
35-
3621
@admin.command()
3722
def init():
3823
"""Initialize a warnet project in the current directory"""
@@ -45,6 +30,6 @@ def init():
4530
copy_network_defaults(Path(current_dir))
4631
copy_namespaces_defaults(Path(current_dir))
4732
richprint(
48-
f"[green]Copied network and namespace example files to {Path(current_dir) / 'networks'}[/green]"
33+
f"[green]Copied network and namespace example files to {Path(current_dir) / NETWORK_DIR.name}[/green]"
4934
)
5035
richprint(f"[green]Created warnet project structure in {current_dir}[/green]")

src/warnet/constants.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import os
2+
from importlib.resources import files
3+
from pathlib import Path
4+
5+
# Constants used throughout the project
6+
# Storing as constants for now but we might want a more sophisticated config management
7+
# at some point.
8+
SUPPORTED_TAGS = ["27.0", "26.0", "25.1", "24.2", "23.2", "22.2"]
9+
DEFAULT_TAG = SUPPORTED_TAGS[0]
10+
WEIGHTED_TAGS = [
11+
tag for index, tag in enumerate(reversed(SUPPORTED_TAGS)) for _ in range(index + 1)
12+
]
13+
14+
DEFAULT_NAMESPACE = "warnet"
15+
HELM_COMMAND = "helm upgrade --install --create-namespace"
16+
17+
# Directories and files for non-python assets, e.g., helm charts, example scenarios, default configs
18+
SRC_DIR = files("warnet")
19+
RESOURCES_DIR = files("resources")
20+
NETWORK_DIR = RESOURCES_DIR.joinpath("networks")
21+
SCENARIOS_DIR = RESOURCES_DIR.joinpath("scenarios")
22+
CHARTS_DIR = RESOURCES_DIR.joinpath("charts")
23+
MANIFESTS_DIR = RESOURCES_DIR.joinpath("manifests")
24+
NETWORK_FILE = "network.yaml"
25+
DEFAULTS_FILE = "node-defaults.yaml"
26+
NAMESPACES_FILE = "namespaces.yaml"
27+
28+
# Helm charts
29+
BITCOIN_CHART_LOCATION = str(CHARTS_DIR.joinpath("bitcoincore"))
30+
FORK_OBSERVER_CHART = str(CHARTS_DIR.joinpath("fork-observer"))
31+
NAMESPACES_CHART_LOCATION = CHARTS_DIR.joinpath("namespaces")
32+
DEFAULT_NETWORK = Path("6_node_bitcoin")
33+
DEFAULT_NAMESPACES = Path("two_namespaces_two_users")
34+
35+
# Kubeconfig related stuffs
36+
KUBECONFIG = os.environ.get("KUBECONFIG", os.path.expanduser("~/.kube/config"))
37+
38+
# TODO: all of this logging stuff should be a helm chart
39+
LOGGING_CONFIG = {
40+
"version": 1,
41+
"disable_existing_loggers": False,
42+
"formatters": {
43+
"simple": {
44+
"format": "%(asctime)s | %(levelname)-7s | %(name)-8s | %(message)s",
45+
"datefmt": "%Y-%m-%d %H:%M:%S",
46+
},
47+
"detailed": {
48+
"format": "%(asctime)s | %(levelname)-7s | [%(module)21s:%(lineno)4d] | %(message)s",
49+
"datefmt": "%Y-%m-%d %H:%M:%S",
50+
},
51+
},
52+
"handlers": {
53+
"stdout": {
54+
"class": "logging.StreamHandler",
55+
"level": "DEBUG",
56+
"formatter": "simple",
57+
"stream": "ext://sys.stdout",
58+
},
59+
"stderr": {
60+
"class": "logging.StreamHandler",
61+
"level": "WARNING",
62+
"formatter": "simple",
63+
"stream": "ext://sys.stderr",
64+
},
65+
"file": {
66+
"class": "logging.handlers.RotatingFileHandler",
67+
"level": "DEBUG",
68+
"formatter": "detailed",
69+
"filename": "warnet.log",
70+
"maxBytes": 16000000,
71+
"backupCount": 3,
72+
},
73+
},
74+
"loggers": {
75+
"root": {"level": "DEBUG", "handlers": ["stdout", "stderr", "file"]},
76+
"urllib3.connectionpool": {"level": "WARNING", "propagate": 1},
77+
"kubernetes.client.rest": {"level": "WARNING", "propagate": 1},
78+
"werkzeug": {"level": "WARNING", "propagate": 1},
79+
},
80+
}
81+
82+
# Helm commands for logging setup
83+
# TODO: also lots of hardcode stuff in these helm commands, will need to fix this when moving to helm charts
84+
LOGGING_HELM_COMMANDS = [
85+
"helm repo add grafana https://grafana.github.io/helm-charts",
86+
"helm repo add prometheus-community https://prometheus-community.github.io/helm-charts",
87+
"helm repo update",
88+
f"helm upgrade --install --namespace warnet-logging --create-namespace --values {MANIFESTS_DIR}/loki_values.yaml loki grafana/loki --version 5.47.2",
89+
"helm upgrade --install --namespace warnet-logging promtail grafana/promtail",
90+
"helm upgrade --install --namespace warnet-logging prometheus prometheus-community/kube-prometheus-stack --namespace warnet-logging --set grafana.enabled=false",
91+
f"helm upgrade --install --namespace warnet-logging loki-grafana grafana/grafana --values {MANIFESTS_DIR}/grafana_values.yaml",
92+
]

src/warnet/deploy.py

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,17 @@
44
import click
55
import yaml
66

7-
from .k8s import get_default_namespace
8-
from .namespaces import (
9-
BITCOIN_CHART_LOCATION as NAMESPACES_CHART_LOCATION,
10-
)
11-
from .namespaces import (
12-
DEFAULTS_FILE as NAMESPACES_DEFAULTS_FILE,
13-
)
14-
from .namespaces import (
15-
NAMESPACES_FILE,
16-
)
17-
from .network import (
18-
BITCOIN_CHART_LOCATION as NETWORK_CHART_LOCATION,
19-
)
20-
from .network import (
21-
DEFAULTS_FILE as NETWORK_DEFAULTS_FILE,
22-
)
23-
24-
# Import necessary functions and variables from network.py and namespaces.py
25-
from .network import (
7+
from .constants import (
8+
BITCOIN_CHART_LOCATION,
9+
DEFAULTS_FILE,
2610
FORK_OBSERVER_CHART,
11+
HELM_COMMAND,
12+
NAMESPACES_FILE,
2713
NETWORK_FILE,
2814
)
15+
from .k8s import get_default_namespace
2916
from .process import stream_command
3017

31-
HELM_COMMAND = "helm upgrade --install --create-namespace"
32-
3318

3419
def validate_directory(ctx, param, value):
3520
directory = Path(value)
@@ -82,7 +67,6 @@ def deploy_fork_observer(directory: Path, debug: bool):
8267
override_string = ""
8368

8469
# Add an entry for each node in the graph
85-
# TODO: should this be moved into a chart, and only have substituted name and rpc_host values
8670
for i, node in enumerate(network_file["nodes"]):
8771
node_name = node.get("name")
8872
node_config = f"""
@@ -97,7 +81,6 @@ def deploy_fork_observer(directory: Path, debug: bool):
9781
"""
9882

9983
override_string += node_config
100-
# End loop
10184

10285
# Create yaml string using multi-line string format
10386
override_string = override_string.strip()
@@ -119,7 +102,7 @@ def deploy_fork_observer(directory: Path, debug: bool):
119102

120103
def deploy_network(directory: Path, debug: bool = False):
121104
network_file_path = directory / NETWORK_FILE
122-
defaults_file_path = directory / NETWORK_DEFAULTS_FILE
105+
defaults_file_path = directory / DEFAULTS_FILE
123106

124107
with network_file_path.open() as f:
125108
network_file = yaml.safe_load(f)
@@ -133,7 +116,7 @@ def deploy_network(directory: Path, debug: bool = False):
133116
node_name = node.get("name")
134117
node_config_override = {k: v for k, v in node.items() if k != "name"}
135118

136-
cmd = f"{HELM_COMMAND} {node_name} {NETWORK_CHART_LOCATION} --namespace {namespace} -f {defaults_file_path}"
119+
cmd = f"{HELM_COMMAND} {node_name} {BITCOIN_CHART_LOCATION} --namespace {namespace} -f {defaults_file_path}"
137120
if debug:
138121
cmd += " --debug"
139122

@@ -158,7 +141,7 @@ def deploy_network(directory: Path, debug: bool = False):
158141

159142
def deploy_namespaces(directory: Path):
160143
namespaces_file_path = directory / NAMESPACES_FILE
161-
defaults_file_path = directory / NAMESPACES_DEFAULTS_FILE
144+
defaults_file_path = directory / DEFAULTS_FILE
162145

163146
with namespaces_file_path.open() as f:
164147
namespaces_file = yaml.safe_load(f)
@@ -178,7 +161,9 @@ def deploy_namespaces(directory: Path):
178161
namespace_name = namespace.get("name")
179162
namespace_config_override = {k: v for k, v in namespace.items() if k != "name"}
180163

181-
cmd = f"{HELM_COMMAND} {namespace_name} {NAMESPACES_CHART_LOCATION} -f {defaults_file_path}"
164+
cmd = (
165+
f"{HELM_COMMAND} {namespace_name} {BITCOIN_CHART_LOCATION} -f {defaults_file_path}"
166+
)
182167

183168
if namespace_config_override:
184169
with tempfile.NamedTemporaryFile(

src/warnet/k8s.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,17 @@
77
from kubernetes.client.models import CoreV1Event, V1PodList
88
from kubernetes.dynamic import DynamicClient
99

10+
from .constants import DEFAULT_NAMESPACE, KUBECONFIG
1011
from .process import run_command, stream_command
1112

12-
DEFAULT_NAMESPACE = "warnet"
13-
1413

1514
def get_static_client() -> CoreV1Event:
16-
config.load_kube_config()
15+
config.load_kube_config(config_file=KUBECONFIG)
1716
return client.CoreV1Api()
1817

1918

2019
def get_dynamic_client() -> DynamicClient:
21-
config.load_kube_config()
20+
config.load_kube_config(config_file=KUBECONFIG)
2221
return DynamicClient(client.ApiClient())
2322

2423

src/warnet/main.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import sys
77
from dataclasses import dataclass
88
from enum import Enum, auto
9-
from importlib.resources import files
109
from pathlib import Path
1110
from typing import Callable
1211

@@ -15,6 +14,14 @@
1514
import yaml
1615
from inquirer.themes import GreenPassion
1716

17+
from warnet.constants import (
18+
DEFAULT_TAG,
19+
DEFAULTS_FILE,
20+
NETWORK_DIR,
21+
NETWORK_FILE,
22+
SRC_DIR,
23+
SUPPORTED_TAGS,
24+
)
1825
from warnet.k8s import get_default_namespace
1926
from warnet.process import run_command, stream_command
2027

@@ -26,9 +33,8 @@
2633
from .image import image
2734
from .network import copy_network_defaults, copy_scenario_defaults
2835
from .status import status as status_command
29-
from .util import DEFAULT_TAG, SUPPORTED_TAGS
3036

31-
QUICK_START_PATH = files("resources.scripts").joinpath("quick_start.sh")
37+
QUICK_START_PATH = SRC_DIR.joinpath("resources", "scripts", "quick_start.sh")
3238

3339

3440
@click.group()
@@ -592,10 +598,6 @@ def logs(pod_name: str, follow: bool):
592598
pass # cancelled by user
593599

594600

595-
if __name__ == "__main__":
596-
cli()
597-
598-
599601
def custom_graph(
600602
num_nodes: int,
601603
num_connections: int,
@@ -639,17 +641,19 @@ def custom_graph(
639641
"configQueryInterval": fork_obs_query_interval,
640642
}
641643

642-
with open(os.path.join(datadir, "network.yaml"), "w") as f:
644+
with open(os.path.join(datadir, NETWORK_FILE), "w") as f:
643645
yaml.dump(network_yaml_data, f, default_flow_style=False)
644646

645647
# Generate node-defaults.yaml
646-
default_yaml_path = files("resources.networks").joinpath("node-defaults.yaml")
648+
default_yaml_path = NETWORK_DIR.joinpath(DEFAULTS_FILE)
647649
with open(str(default_yaml_path)) as f:
648650
defaults_yaml_content = f.read()
649651

650-
with open(os.path.join(datadir, "node-defaults.yaml"), "w") as f:
652+
with open(os.path.join(datadir, DEFAULTS_FILE), "w") as f:
651653
f.write(defaults_yaml_content)
652654

653-
click.echo(
654-
f"Project '{datadir}' has been created with 'network.yaml' and 'node-defaults.yaml'."
655-
)
655+
click.echo(f"Project '{datadir}' has been created with '{NETWORK_FILE}' and '{DEFAULTS_FILE}'.")
656+
657+
658+
if __name__ == "__main__":
659+
cli()

src/warnet/namespaces.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,24 @@
11
import shutil
2-
from importlib.resources import files
32
from pathlib import Path
43

54
import click
65

6+
from .constants import (
7+
DEFAULT_NAMESPACES,
8+
DEFAULTS_FILE,
9+
NAMESPACES_FILE,
10+
NETWORK_DIR,
11+
)
712
from .process import run_command, stream_command
813

9-
WARNET_NAMESPACES_DIR = files("resources").joinpath("namespaces")
10-
NAMESPACES_DIR = Path("namespaces")
11-
DEFAULT_NAMESPACES = Path("two_namespaces_two_users")
12-
NAMESPACES_FILE = "namespaces.yaml"
13-
DEFAULTS_FILE = "namespace-defaults.yaml"
14-
HELM_COMMAND = "helm upgrade --install"
15-
BITCOIN_CHART_LOCATION = Path(str(files("resources.charts").joinpath("namespaces")))
16-
1714

1815
def copy_namespaces_defaults(directory: Path):
1916
"""Create the project structure for a warnet project"""
20-
(directory / NAMESPACES_DIR / DEFAULT_NAMESPACES).mkdir(parents=True, exist_ok=True)
21-
target_namespaces_defaults = directory / NAMESPACES_DIR / DEFAULT_NAMESPACES / DEFAULTS_FILE
22-
target_namespaces_example = directory / NAMESPACES_DIR / DEFAULT_NAMESPACES / NAMESPACES_FILE
23-
shutil.copy2(
24-
WARNET_NAMESPACES_DIR / DEFAULT_NAMESPACES / DEFAULTS_FILE, target_namespaces_defaults
25-
)
26-
shutil.copy2(
27-
WARNET_NAMESPACES_DIR / DEFAULT_NAMESPACES / NAMESPACES_FILE, target_namespaces_example
28-
)
17+
(directory / NETWORK_DIR / DEFAULT_NAMESPACES).mkdir(parents=True, exist_ok=True)
18+
target_namespaces_defaults = directory / NETWORK_DIR / DEFAULT_NAMESPACES / DEFAULTS_FILE
19+
target_namespaces_example = directory / NETWORK_DIR / DEFAULT_NAMESPACES / NAMESPACES_FILE
20+
shutil.copy2(NETWORK_DIR / DEFAULT_NAMESPACES / DEFAULTS_FILE, target_namespaces_defaults)
21+
shutil.copy2(NETWORK_DIR / DEFAULT_NAMESPACES / NAMESPACES_FILE, target_namespaces_example)
2922

3023

3124
@click.group(name="namespaces")

0 commit comments

Comments
 (0)