1
1
import json
2
+ import os
2
3
import tempfile
3
4
from importlib .resources import files
4
5
from pathlib import Path
22
23
)
23
24
from .process import stream_command
24
25
25
- DEFAULT_GRAPH_FILE = files ("graphs" ).joinpath ("default.graphml" )
26
26
WAR_MANIFESTS = files ("manifests" )
27
-
27
+ NETWORK_DIR = Path ("networks" )
28
+ DEFAULT_NETWORK = "6_node_bitcoin"
29
+ NETWORK_FILE = "network.yaml"
30
+ DEFAULTS_FILE = "defaults.yaml"
31
+ HELM_COMMAND = "helm upgrade --install --create-namespace"
32
+ BITCOIN_CHART_LOCATION = "./resources/charts/bitcoincore"
33
+ NAMESPACE = "warnet"
28
34
29
35
@click .group (name = "network" )
30
36
def network ():
31
37
"""Network commands"""
32
38
33
39
34
- def read_graph_file (graph_file : Path ) -> nx .Graph :
35
- with open (graph_file ) as f :
36
- return nx .parse_graphml (f .read ())
37
-
38
-
39
- def generate_node_config (node : int , data : dict , graph : nx .Graph ) -> str :
40
- base_config = """
41
- regtest=1
42
- checkmempool=0
43
- acceptnonstdtxn=1
44
- debuglogfile=0
45
- logips=1
46
- logtimemicros=1
47
- capturemessages=1
48
- fallbackfee=0.00001000
49
- listen=1
50
-
51
- [regtest]
52
- rpcuser=user
53
- rpcpassword=password
54
- rpcport=18443
55
- rpcallowip=0.0.0.0/0
56
- rpcbind=0.0.0.0
57
-
58
- zmqpubrawblock=tcp://0.0.0.0:28332
59
- zmqpubrawtx=tcp://0.0.0.0:28333
60
- """
61
- node_specific_config = data .get ("bitcoin_config" , "" ).replace ("," , "\n " )
62
-
63
- # Add addnode configurations for connected nodes
64
- connected_nodes = list (graph .neighbors (node ))
65
- addnode_configs = [f"addnode=warnet-tank-{ index } -service" for index in connected_nodes ]
66
-
67
- return f"{ base_config } \n { node_specific_config } \n " + "\n " .join (addnode_configs )
68
-
69
-
70
- def create_node_deployment (node : int , data : dict ) -> Dict [str , Any ]:
71
- image = data .get ("image" , "bitcoindevproject/bitcoin:27.0" )
72
- version = data .get ("version" , "27.0" )
73
-
74
- return create_kubernetes_object (
75
- kind = "Pod" ,
76
- metadata = {
77
- "name" : f"warnet-tank-{ node } " ,
78
- "namespace" : "warnet" ,
79
- "labels" : {"app" : "warnet" , "mission" : "tank" , "index" : str (node )},
80
- "annotations" : {"data" : json .dumps (data )},
81
- },
82
- spec = {
83
- "containers" : [
84
- {
85
- "name" : "bitcoin" ,
86
- "image" : image ,
87
- "env" : [{"name" : "BITCOIN_VERSION" , "value" : version }],
88
- "volumeMounts" : [
89
- {
90
- "name" : "config" ,
91
- "mountPath" : "/root/.bitcoin/bitcoin.conf" ,
92
- "subPath" : "bitcoin.conf" ,
93
- }
94
- ],
95
- "ports" : [
96
- {"containerPort" : 18444 },
97
- {"containerPort" : 18443 },
98
- ],
99
- }
100
- ],
101
- "volumes" : [{"name" : "config" , "configMap" : {"name" : f"bitcoin-config-tank-{ node } " }}],
102
- },
103
- )
104
-
105
-
106
- def create_node_service (node : int ) -> Dict [str , Any ]:
107
- return create_kubernetes_object (
108
- kind = "Service" ,
109
- metadata = {"name" : f"warnet-tank-{ node } -service" , "namespace" : "warnet" },
110
- spec = {
111
- "selector" : {"app" : "warnet" , "mission" : "tank" , "index" : str (node )},
112
- "ports" : [
113
- {"name" : "p2p" , "port" : 18444 , "targetPort" : 18444 },
114
- {"name" : "rpc" , "port" : 18443 , "targetPort" : 18443 },
115
- ],
116
- },
117
- )
118
-
119
-
120
- def create_config_map (node : int , config : str ) -> Dict [str , Any ]:
121
- config_map = create_kubernetes_object (
122
- kind = "ConfigMap" ,
123
- metadata = {
124
- "name" : f"bitcoin-config-tank-{ node } " ,
125
- "namespace" : "warnet" ,
126
- },
127
- )
128
- config_map ["data" ] = {"bitcoin.conf" : config }
129
- return config_map
130
-
131
-
132
40
def create_edges_map (graph ):
133
41
edges = []
134
42
for src , dst , data in graph .edges (data = True ):
@@ -144,23 +52,6 @@ def create_edges_map(graph):
144
52
return config_map
145
53
146
54
147
- def generate_kubernetes_yaml (graph : nx .Graph ) -> List [Dict [str , Any ]]:
148
- kubernetes_objects = [create_namespace ()]
149
-
150
- for node , data in graph .nodes (data = True ):
151
- config = generate_node_config (node , data , graph )
152
- kubernetes_objects .extend (
153
- [
154
- create_config_map (node , config ),
155
- create_node_deployment (node , data ),
156
- create_node_service (node ),
157
- ]
158
- )
159
- kubernetes_objects .append (create_edges_map (graph ))
160
-
161
- return kubernetes_objects
162
-
163
-
164
55
def setup_logging_helm () -> bool :
165
56
helm_commands = [
166
57
"helm repo add grafana https://grafana.github.io/helm-charts" ,
@@ -180,30 +71,46 @@ def setup_logging_helm() -> bool:
180
71
181
72
182
73
@network .command ()
183
- @click .argument ("graph_file" , default = DEFAULT_GRAPH_FILE , type = click .Path ())
74
+ @click .argument ("network_name" , default = DEFAULT_NETWORK )
75
+ @click .option ("--network" , default = "warnet" , show_default = True )
184
76
@click .option ("--logging/--no-logging" , default = False )
185
- def start (graph_file : Path , logging : bool ):
186
- """Start a warnet with topology loaded from a <graph_file>"""
187
- graph = read_graph_file (graph_file )
188
- kubernetes_yaml = generate_kubernetes_yaml (graph )
189
-
190
- with tempfile .NamedTemporaryFile (mode = "w" , suffix = ".yaml" , delete = False ) as temp_file :
191
- yaml .dump_all (kubernetes_yaml , temp_file )
192
- temp_file_path = temp_file .name
193
-
194
- try :
195
- if deploy_base_configurations () and apply_kubernetes_yaml (temp_file_path ):
196
- print ("Warnet network started successfully." )
197
- if not set_kubectl_context ("warnet" ):
198
- print (
199
- "Warning: Failed to set kubectl context. You may need to manually switch to the warnet namespace."
200
- )
201
- if logging and not setup_logging_helm ():
202
- print ("Failed to install Helm charts." )
203
- else :
204
- print ("Failed to start warnet network." )
205
- finally :
206
- Path (temp_file_path ).unlink ()
77
+ def start (network_name : str , logging : bool , network : str ):
78
+ """Start a warnet with topology loaded from <network_name> into [network]"""
79
+ full_path = os .path .join (NETWORK_DIR , network_name )
80
+ network_file_path = os .path .join (full_path , NETWORK_FILE )
81
+ defaults_file_path = os .path .join (full_path , DEFAULTS_FILE )
82
+
83
+ network_file = {}
84
+ with open (network_file_path ) as f :
85
+ network_file = yaml .safe_load (f )
86
+
87
+ for node in network_file ["nodes" ]:
88
+ print (f"Starting node: { node .get ('name' )} " )
89
+ try :
90
+ temp_override_file_path = ""
91
+ node_name = node .get ("name" )
92
+ # all the keys apart from name
93
+ node_config_override = {k : v for k , v in node .items () if k != "name" }
94
+
95
+ cmd = f"{ HELM_COMMAND } { node_name } { BITCOIN_CHART_LOCATION } --namespace { NAMESPACE } -f { defaults_file_path } "
96
+
97
+ if node_config_override :
98
+ with tempfile .NamedTemporaryFile (
99
+ mode = "w" , suffix = ".yaml" , delete = False
100
+ ) as temp_file :
101
+ yaml .dump (node_config_override , temp_file )
102
+ temp_override_file_path = temp_file .name
103
+ cmd = f"{ cmd } -f { temp_override_file_path } "
104
+
105
+ if not stream_command (cmd ):
106
+ print (f"Failed to run Helm command: { cmd } " )
107
+ return
108
+ except Exception as e :
109
+ print (f"Error: { e } " )
110
+ return
111
+ finally :
112
+ if temp_override_file_path :
113
+ Path (temp_override_file_path ).unlink ()
207
114
208
115
209
116
@network .command ()
@@ -268,18 +175,4 @@ def _status():
268
175
"bitcoin_status" : tank .status .phase .lower (),
269
176
}
270
177
stats .append (status )
271
- return stats
272
-
273
-
274
- @network .command ()
275
- @click .argument ("graph_file" , default = DEFAULT_GRAPH_FILE , type = click .Path ())
276
- @click .option ("--output" , "-o" , default = "warnet-deployment.yaml" , help = "Output YAML file" )
277
- def generate_yaml (graph_file : Path , output : str ):
278
- """Generate a Kubernetes YAML file from a graph file for deploying warnet nodes."""
279
- graph = read_graph_file (graph_file )
280
- kubernetes_yaml = generate_kubernetes_yaml (graph )
281
-
282
- with open (output , "w" ) as f :
283
- yaml .dump_all (kubernetes_yaml , f )
284
-
285
- print (f"Kubernetes YAML file generated: { output } " )
178
+ return stats
0 commit comments