49
49
'workdir' : 'working_dir' ,
50
50
}
51
51
52
+ DOCKER_START_KEYS = [
53
+ 'cap_add' ,
54
+ 'cap_drop' ,
55
+ 'dns' ,
56
+ 'env_file' ,
57
+ 'net' ,
58
+ 'privileged' ,
59
+ 'restart' ,
60
+ ]
61
+
52
62
VALID_NAME_CHARS = '[a-zA-Z0-9]'
53
63
54
64
@@ -144,7 +154,8 @@ def restart(self, **options):
144
154
145
155
def scale (self , desired_num ):
146
156
"""
147
- Adjusts the number of containers to the specified number and ensures they are running.
157
+ Adjusts the number of containers to the specified number and ensures
158
+ they are running.
148
159
149
160
- creates containers until there are at least `desired_num`
150
161
- stops containers until there are at most `desired_num` running
@@ -191,12 +202,24 @@ def remove_stopped(self, **options):
191
202
log .info ("Removing %s..." % c .name )
192
203
c .remove (** options )
193
204
194
- def create_container (self , one_off = False , insecure_registry = False , ** override_options ):
205
+ def create_container (self ,
206
+ one_off = False ,
207
+ insecure_registry = False ,
208
+ do_build = True ,
209
+ ** override_options ):
195
210
"""
196
211
Create a container for this service. If the image doesn't exist, attempt to pull
197
212
it.
198
213
"""
199
- container_options = self ._get_container_create_options (override_options , one_off = one_off )
214
+ container_options = self ._get_container_create_options (
215
+ override_options ,
216
+ one_off = one_off )
217
+
218
+ if (do_build and
219
+ self .can_be_built () and
220
+ not self .client .images (name = self .full_name )):
221
+ self .build ()
222
+
200
223
try :
201
224
return Container .create (self .client , ** container_options )
202
225
except APIError as e :
@@ -211,15 +234,18 @@ def create_container(self, one_off=False, insecure_registry=False, **override_op
211
234
return Container .create (self .client , ** container_options )
212
235
raise
213
236
214
- def recreate_containers (self , insecure_registry = False , ** override_options ):
237
+ def recreate_containers (self , insecure_registry = False , do_build = True , ** override_options ):
215
238
"""
216
239
If a container for this service doesn't exist, create and start one. If there are
217
240
any, stop them, create+start new ones, and remove the old containers.
218
241
"""
219
242
containers = self .containers (stopped = True )
220
243
if not containers :
221
244
log .info ("Creating %s..." % self ._next_container_name (containers ))
222
- container = self .create_container (insecure_registry = insecure_registry , ** override_options )
245
+ container = self .create_container (
246
+ insecure_registry = insecure_registry ,
247
+ do_build = do_build ,
248
+ ** override_options )
223
249
self .start_container (container )
224
250
return [(None , container )]
225
251
else :
@@ -257,7 +283,7 @@ def recreate_container(self, container, **override_options):
257
283
container .remove ()
258
284
259
285
options = dict (override_options )
260
- new_container = self .create_container (** options )
286
+ new_container = self .create_container (do_build = False , ** options )
261
287
self .start_container (new_container , intermediate_container = intermediate_container )
262
288
263
289
intermediate_container .remove ()
@@ -271,8 +297,7 @@ def start_container_if_stopped(self, container, **options):
271
297
log .info ("Starting %s..." % container .name )
272
298
return self .start_container (container , ** options )
273
299
274
- def start_container (self , container = None , intermediate_container = None , ** override_options ):
275
- container = container or self .create_container (** override_options )
300
+ def start_container (self , container , intermediate_container = None , ** override_options ):
276
301
options = dict (self .options , ** override_options )
277
302
port_bindings = build_port_bindings (options .get ('ports' ) or [])
278
303
@@ -303,12 +328,14 @@ def start_container(self, container=None, intermediate_container=None, **overrid
303
328
)
304
329
return container
305
330
306
- def start_or_create_containers (self , insecure_registry = False ):
331
+ def start_or_create_containers (self , insecure_registry = False , do_build = True ):
307
332
containers = self .containers (stopped = True )
308
333
309
334
if not containers :
310
335
log .info ("Creating %s..." % self ._next_container_name (containers ))
311
- new_container = self .create_container (insecure_registry = insecure_registry )
336
+ new_container = self .create_container (
337
+ insecure_registry = insecure_registry ,
338
+ do_build = do_build )
312
339
return [self .start_container (new_container )]
313
340
else :
314
341
return [self .start_container_if_stopped (c ) for c in containers ]
@@ -400,14 +427,11 @@ def _get_container_create_options(self, override_options, one_off=False):
400
427
container_options ['environment' ] = merge_environment (container_options )
401
428
402
429
if self .can_be_built ():
403
- if len (self .client .images (name = self ._build_tag_name ())) == 0 :
404
- self .build ()
405
- container_options ['image' ] = self ._build_tag_name ()
430
+ container_options ['image' ] = self .full_name
406
431
407
432
# Delete options which are only used when starting
408
- for key in ['privileged' , 'net' , 'dns' , 'restart' , 'cap_add' , 'cap_drop' , 'env_file' ]:
409
- if key in container_options :
410
- del container_options [key ]
433
+ for key in DOCKER_START_KEYS :
434
+ container_options .pop (key , None )
411
435
412
436
return container_options
413
437
@@ -416,7 +440,7 @@ def build(self, no_cache=False):
416
440
417
441
build_output = self .client .build (
418
442
self .options ['build' ],
419
- tag = self ._build_tag_name () ,
443
+ tag = self .full_name ,
420
444
stream = True ,
421
445
rm = True ,
422
446
nocache = no_cache ,
@@ -436,14 +460,15 @@ def build(self, no_cache=False):
436
460
image_id = match .group (1 )
437
461
438
462
if image_id is None :
439
- raise BuildError (self )
463
+ raise BuildError (self , event if all_events else 'Unknown' )
440
464
441
465
return image_id
442
466
443
467
def can_be_built (self ):
444
468
return 'build' in self .options
445
469
446
- def _build_tag_name (self ):
470
+ @property
471
+ def full_name (self ):
447
472
"""
448
473
The tag to give to images built for this service.
449
474
"""
0 commit comments