13
13
from docker .errors import NotFound
14
14
from docker .types import IPAMConfig , IPAMPool
15
15
16
- from launcher .utils import ArgumentParser , yes_or_no
16
+ from launcher .utils import ArgumentParser , yes_or_no , parallel
17
17
from .DockerTemplate import DockerTemplate
18
18
from .arby import Arby
19
19
from .base import Node , ContainerNotFound , NoWaiting
@@ -69,7 +69,8 @@ def execute(self, *args) -> None:
69
69
args = self .parser .parse_args (args )
70
70
name = args .service
71
71
service = self .get_service (name )
72
- for line in service .logs (tail = args .tail , since = args .since , until = args .until , follow = args .follow , timestamps = args .timestamps ):
72
+ for line in service .logs (tail = args .tail , since = args .since , until = args .until , follow = args .follow ,
73
+ timestamps = args .timestamps ):
73
74
print (line )
74
75
75
76
@@ -151,6 +152,10 @@ class ServiceNotFound(Exception):
151
152
pass
152
153
153
154
155
+ class NetworkNotFound (Exception ):
156
+ pass
157
+
158
+
154
159
class NodeManager :
155
160
config : Config
156
161
client : DockerClient
@@ -165,7 +170,7 @@ def __init__(self, config: Config):
165
170
ctx = Context (self .config , self .client , self .image_manager , self )
166
171
167
172
self .nodes = {name : globals ()[name .capitalize ()](name , ctx ) for name in self .config .nodes }
168
- self .docker_network = self .create_docker_network ()
173
+ # self.docker_network = self.create_docker_network()
169
174
170
175
self .cmd_logs = LogsCommand (self .get_service )
171
176
self .cmd_start = StartCommand (self .get_service )
@@ -197,17 +202,23 @@ def get_network_ipam_pool(self):
197
202
elif self .network == "mainnet" :
198
203
return IPAMPool (subnet = '10.0.3.0/24' , gateway = '10.0.3.1' )
199
204
200
- def create_docker_network (self ):
201
- name = self .network_name
202
- try :
203
- network = self .client .networks .get (name )
204
- return network
205
- except NotFound :
206
- pass
205
+ def _create_docker_network (self ) -> None :
207
206
ipam_pool = self .get_network_ipam_pool ()
208
207
ipam_config = IPAMConfig (pool_configs = [ipam_pool ])
209
- network = self .client .networks .create (name , driver = "bridge" , ipam = ipam_config )
210
- return network
208
+ network = self .client .networks .create (self .network_name , driver = "bridge" , ipam = ipam_config )
209
+ logger .info ("Created network: %r" , network )
210
+
211
+ def _remove_docker_network (self ) -> None :
212
+ network = self .docker_network
213
+ network .remove ()
214
+ logger .info ("Removed network: %r" , network )
215
+
216
+ @property
217
+ def docker_network (self ):
218
+ try :
219
+ return self .client .networks .get (self .network_name )
220
+ except docker .errors .NotFound as e :
221
+ raise NetworkNotFound (self .network_name ) from e
211
222
212
223
def get_service (self , name : str ) -> Node :
213
224
try :
@@ -216,46 +227,46 @@ def get_service(self, name: str) -> Node:
216
227
raise ServiceNotFound (name ) from e
217
228
218
229
@property
219
- def valid_nodes (self ):
230
+ def valid_nodes (self ) -> Dict [ str , Node ] :
220
231
return {name : node for name , node in self .nodes .items () if node .mode == "native" and not node .disabled }
221
232
222
- @property
223
- def enabled_nodes (self ):
224
- return {name : node for name , node in self .nodes .items () if not node .disabled }
225
-
226
233
def up (self ):
227
- self . docker_network = self .create_docker_network ()
234
+ nodes = self .valid_nodes
228
235
229
- nodes = self . valid_nodes . values ( )
236
+ logger . info ( "Up services: %s" , ", " . join ( nodes ) )
230
237
231
- executor = self .config .executor
232
- futs = {executor .submit (node .start ): node for node in nodes }
233
- done , not_done = wait (futs , 60 )
234
- if len (not_done ) > 0 :
235
- # TODO retry failed tasks
236
- raise RuntimeError ("Failed to up" )
238
+ try :
239
+ _ = self .docker_network
240
+ except NetworkNotFound :
241
+ self ._create_docker_network ()
242
+
243
+ def linehead (node ):
244
+ return "starting %s" % node .container_name
245
+
246
+ def start (node , stop ):
247
+ node .start ()
248
+
249
+ nodes = [node for node in nodes .values () if not node .is_running ]
250
+
251
+ parallel (self .config .executor , nodes , linehead , start )
237
252
238
253
def down (self ):
239
254
nodes = self .valid_nodes
240
255
241
- for name , container in nodes .items ():
242
- print (f"Stopping { name } ..." )
243
- container .stop ()
244
- for name , container in nodes .items ():
245
- print (f"Removing { name } ..." )
246
- container .remove ()
256
+ logger .info ("Down services: %s" , ", " .join (nodes ))
257
+
258
+ running_nodes = [node for node in nodes .values () if node .is_running ]
259
+
260
+ parallel (self .config .executor , running_nodes ,
261
+ lambda node : "stopping %s" % node .container_name ,
262
+ lambda node , stop : node .stop ())
263
+
264
+ parallel (self .config .executor , list (nodes .values ()),
265
+ lambda node : "removing %s" % node .container_name ,
266
+ lambda node , stop : node .remove ())
267
+
247
268
print (f"Removing network { self .network_name } " )
248
- self .docker_network .remove ()
249
-
250
- def _display_container_status_text (self , status ):
251
- if status == "missing" :
252
- return "create"
253
- elif status == "outdated" :
254
- return "recreate"
255
- elif status == "external_with_container" :
256
- return "remove"
257
- elif status == "disabled_with_container" :
258
- return "remove"
269
+ self ._remove_docker_network ()
259
270
260
271
def check_for_updates (self ) -> Dict [Node , str ]:
261
272
logger .info ("Checking for container updates" )
@@ -305,24 +316,35 @@ def update(self) -> None:
305
316
if b1 and b2 :
306
317
print ("All up-to-date." )
307
318
308
- for container , action in containers .items ():
319
+ def linehead (node ):
320
+ action = containers [node ]
309
321
if action == "CREATE" :
310
- print ("Creating %s..." % container .container_name )
311
- container .create ()
322
+ return "creating %s" % node .container_name
312
323
elif action == "RECREATE" :
313
- if container .is_running :
314
- print ("Stopping %s..." % container .container_name )
315
- container .stop ()
316
- print ("Removing %s..." % container .container_name )
317
- container .remove ()
318
- print ("Creating %s..." % container .container_name )
319
- container .create ()
324
+ return "recreating %s" % node .container_name
320
325
elif action == "REMOVE" :
321
- if container .is_running :
322
- print ("Stopping %s..." % container .container_name )
323
- container .stop ()
324
- print ("Removing %s..." % container .container_name )
325
- container .remove ()
326
+ return "removing %s" % node .container_name
327
+
328
+ def update (node , stop ):
329
+ action = containers [node ]
330
+ if action == "CREATE" :
331
+ node .create ()
332
+ elif action == "RECREATE" :
333
+ if node .is_running :
334
+ node .stop ()
335
+ node .remove ()
336
+ node .create ()
337
+ elif action == "REMOVE" :
338
+ if node .is_running :
339
+ node .stop ()
340
+ node .remove ()
341
+
342
+ items = []
343
+ for container , action in containers .items ():
344
+ if action != "NONE" :
345
+ items .append (container )
346
+
347
+ parallel (self .config .executor , items , linehead , update )
326
348
327
349
def _get_status_nodes (self ):
328
350
optional_nodes = ["arby" , "boltz" , "webui" , "proxy" ]
0 commit comments