@@ -242,9 +242,8 @@ def create_container(self,
242242
243243 def recreate_containers (self , insecure_registry = False , do_build = True , ** override_options ):
244244 """
245- If a container for this service doesn't exist, create and start one. If
246- there are any, stop them, create+start new ones, and remove the old
247- containers.
245+ If a container for this service doesn't exist, create and start one. If there are
246+ any, stop them, create+start new ones, and remove the old containers.
248247 """
249248 containers = self .containers (stopped = True )
250249 if not containers :
@@ -254,22 +253,21 @@ def recreate_containers(self, insecure_registry=False, do_build=True, **override
254253 do_build = do_build ,
255254 ** override_options )
256255 self .start_container (container )
257- return [container ]
256+ return [( None , container ) ]
258257 else :
259- return [
260- self . recreate_container (
261- container ,
262- insecure_registry = insecure_registry ,
263- ** override_options )
264- for container in containers
265- ]
258+ tuples = []
259+
260+ for c in containers :
261+ log . info ( "Recreating %s..." % c . name )
262+ tuples . append ( self . recreate_container ( c , insecure_registry = insecure_registry , ** override_options ) )
263+
264+ return tuples
266265
267266 def recreate_container (self , container , ** override_options ):
268267 """Recreate a container. An intermediate container is created so that
269268 the new container has the same name, while still supporting
270269 `volumes-from` the original container.
271270 """
272- log .info ("Recreating %s..." % container .name )
273271 try :
274272 container .stop ()
275273 except APIError as e :
@@ -280,30 +278,24 @@ def recreate_container(self, container, **override_options):
280278 else :
281279 raise
282280
283- intermediate_options = dict (self .options , ** override_options )
284281 intermediate_container = Container .create (
285282 self .client ,
286283 image = container .image ,
287284 entrypoint = ['/bin/echo' ],
288285 command = [],
289286 detach = True ,
290287 )
291- intermediate_container .start (
292- binds = get_container_data_volumes (
293- container , intermediate_options .get ('volumes' )))
288+ intermediate_container .start (volumes_from = container .id )
294289 intermediate_container .wait ()
295290 container .remove ()
296291
297- # TODO: volumes are being passed to both start and create, this is
298- # probably unnecessary
299292 options = dict (override_options )
300293 new_container = self .create_container (do_build = False , ** options )
301- self .start_container (
302- new_container ,
303- intermediate_container = intermediate_container )
294+ self .start_container (new_container , intermediate_container = intermediate_container )
304295
305296 intermediate_container .remove ()
306- return new_container
297+
298+ return (intermediate_container , new_container )
307299
308300 def start_container_if_stopped (self , container , ** options ):
309301 if container .is_running :
@@ -315,6 +307,12 @@ def start_container_if_stopped(self, container, **options):
315307 def start_container (self , container , intermediate_container = None , ** override_options ):
316308 options = dict (self .options , ** override_options )
317309 port_bindings = build_port_bindings (options .get ('ports' ) or [])
310+
311+ volume_bindings = dict (
312+ build_volume_binding (parse_volume_spec (volume ))
313+ for volume in options .get ('volumes' ) or []
314+ if ':' in volume )
315+
318316 privileged = options .get ('privileged' , False )
319317 net = options .get ('net' , 'bridge' )
320318 dns = options .get ('dns' , None )
@@ -323,14 +321,12 @@ def start_container(self, container, intermediate_container=None, **override_opt
323321 cap_drop = options .get ('cap_drop' , None )
324322
325323 restart = parse_restart_spec (options .get ('restart' , None ))
326- binds = get_volume_bindings (
327- options .get ('volumes' ), intermediate_container )
328324
329325 container .start (
330326 links = self ._get_links (link_to_self = options .get ('one_off' , False )),
331327 port_bindings = port_bindings ,
332- binds = binds ,
333- volumes_from = self ._get_volumes_from (),
328+ binds = volume_bindings ,
329+ volumes_from = self ._get_volumes_from (intermediate_container ),
334330 privileged = privileged ,
335331 network_mode = net ,
336332 dns = dns ,
@@ -392,7 +388,7 @@ def _get_links(self, link_to_self):
392388 links .append ((external_link , link_name ))
393389 return links
394390
395- def _get_volumes_from (self ):
391+ def _get_volumes_from (self , intermediate_container = None ):
396392 volumes_from = []
397393 for volume_source in self .volumes_from :
398394 if isinstance (volume_source , Service ):
@@ -406,6 +402,9 @@ def _get_volumes_from(self):
406402 elif isinstance (volume_source , Container ):
407403 volumes_from .append (volume_source .id )
408404
405+ if intermediate_container :
406+ volumes_from .append (intermediate_container .id )
407+
409408 return volumes_from
410409
411410 def _get_container_create_options (self , override_options , one_off = False ):
@@ -520,45 +519,6 @@ def pull(self, insecure_registry=False):
520519 )
521520
522521
523- def get_container_data_volumes (container , volumes_option ):
524- """Find the container data volumes that are in `volumes_option`, and return
525- a mapping of volume bindings for those volumes.
526- """
527- volumes = []
528- for volume in volumes_option or []:
529- volume = parse_volume_spec (volume )
530- # No need to preserve host volumes
531- if volume .external :
532- continue
533-
534- volume_path = (container .get ('Volumes' ) or {}).get (volume .internal )
535- # New volume, doesn't exist in the old container
536- if not volume_path :
537- continue
538-
539- # Copy existing volume from old container
540- volume = volume ._replace (external = volume_path )
541- volumes .append (build_volume_binding (volume ))
542-
543- return dict (volumes )
544-
545-
546- def get_volume_bindings (volumes_option , intermediate_container ):
547- """Return a list of volume bindings for a container. Container data volume
548- bindings are replaced by those in the intermediate container.
549- """
550- volume_bindings = dict (
551- build_volume_binding (parse_volume_spec (volume ))
552- for volume in volumes_option or []
553- if ':' in volume )
554-
555- if intermediate_container :
556- volume_bindings .update (
557- get_container_data_volumes (intermediate_container , volumes_option ))
558-
559- return volume_bindings
560-
561-
562522NAME_RE = re .compile (r'^([^_]+)_([^_]+)_(run_)?(\d+)$' )
563523
564524
0 commit comments