@@ -280,23 +280,29 @@ def recreate_container(self, container, **override_options):
280280 else :
281281 raise
282282
283+ intermediate_options = dict (self .options , ** override_options )
283284 intermediate_container = Container .create (
284285 self .client ,
285286 image = container .image ,
286287 entrypoint = ['/bin/echo' ],
287288 command = [],
288289 detach = True ,
289290 )
290- intermediate_container .start (volumes_from = container .id )
291+ intermediate_container .start (
292+ binds = get_container_data_volumes (
293+ container , intermediate_options .get ('volumes' )))
291294 intermediate_container .wait ()
292295 container .remove ()
293296
297+ # TODO: volumes are being passed to both start and create, this is
298+ # probably unnecessary
294299 options = dict (override_options )
295300 new_container = self .create_container (do_build = False , ** options )
296- self .start_container (new_container , intermediate_container = intermediate_container )
301+ self .start_container (
302+ new_container ,
303+ intermediate_container = intermediate_container )
297304
298305 intermediate_container .remove ()
299-
300306 return new_container
301307
302308 def start_container_if_stopped (self , container , ** options ):
@@ -309,12 +315,6 @@ def start_container_if_stopped(self, container, **options):
309315 def start_container (self , container , intermediate_container = None , ** override_options ):
310316 options = dict (self .options , ** override_options )
311317 port_bindings = build_port_bindings (options .get ('ports' ) or [])
312-
313- volume_bindings = dict (
314- build_volume_binding (parse_volume_spec (volume ))
315- for volume in options .get ('volumes' ) or []
316- if ':' in volume )
317-
318318 privileged = options .get ('privileged' , False )
319319 net = options .get ('net' , 'bridge' )
320320 dns = options .get ('dns' , None )
@@ -323,12 +323,14 @@ def start_container(self, container, intermediate_container=None, **override_opt
323323 cap_drop = options .get ('cap_drop' , None )
324324
325325 restart = parse_restart_spec (options .get ('restart' , None ))
326+ binds = get_volume_bindings (
327+ options .get ('volumes' ), intermediate_container )
326328
327329 container .start (
328330 links = self ._get_links (link_to_self = options .get ('one_off' , False )),
329331 port_bindings = port_bindings ,
330- binds = volume_bindings ,
331- volumes_from = self ._get_volumes_from (intermediate_container ),
332+ binds = binds ,
333+ volumes_from = self ._get_volumes_from (),
332334 privileged = privileged ,
333335 network_mode = net ,
334336 dns = dns ,
@@ -390,7 +392,7 @@ def _get_links(self, link_to_self):
390392 links .append ((external_link , link_name ))
391393 return links
392394
393- def _get_volumes_from (self , intermediate_container = None ):
395+ def _get_volumes_from (self ):
394396 volumes_from = []
395397 for volume_source in self .volumes_from :
396398 if isinstance (volume_source , Service ):
@@ -404,9 +406,6 @@ def _get_volumes_from(self, intermediate_container=None):
404406 elif isinstance (volume_source , Container ):
405407 volumes_from .append (volume_source .id )
406408
407- if intermediate_container :
408- volumes_from .append (intermediate_container .id )
409-
410409 return volumes_from
411410
412411 def _get_container_create_options (self , override_options , one_off = False ):
@@ -521,6 +520,45 @@ def pull(self, insecure_registry=False):
521520 )
522521
523522
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+
524562NAME_RE = re .compile (r'^([^_]+)_([^_]+)_(run_)?(\d+)$' )
525563
526564
0 commit comments