mirror of https://github.com/docker/compose.git
Add up flag `--renew-anon-volumes` (shorthand -V)
to avoid reusing the previous container's data Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
fd1e8024f7
commit
b07091ac5f
|
@ -936,7 +936,7 @@ class TopLevelCommand(object):
|
|||
--always-recreate-deps Recreate dependent containers.
|
||||
Incompatible with --no-recreate.
|
||||
--no-recreate If containers already exist, don't recreate
|
||||
them. Incompatible with --force-recreate.
|
||||
them. Incompatible with --force-recreate and -V.
|
||||
--no-build Don't build an image, even if it's missing.
|
||||
--no-start Don't start the services after creating them.
|
||||
--build Build images before starting containers.
|
||||
|
@ -945,8 +945,10 @@ class TopLevelCommand(object):
|
|||
-t, --timeout TIMEOUT Use this timeout in seconds for container
|
||||
shutdown when attached or when containers are
|
||||
already running. (default: 10)
|
||||
--remove-orphans Remove containers for services not
|
||||
defined in the Compose file
|
||||
-V, --renew-anon-volumes Recreate anonymous volumes instead of retrieving
|
||||
data from the previous containers.
|
||||
--remove-orphans Remove containers for services not defined
|
||||
in the Compose file.
|
||||
--exit-code-from SERVICE Return the exit code of the selected service
|
||||
container. Implies --abort-on-container-exit.
|
||||
--scale SERVICE=NUM Scale SERVICE to NUM instances. Overrides the
|
||||
|
@ -992,6 +994,7 @@ class TopLevelCommand(object):
|
|||
start=not no_start,
|
||||
always_recreate_deps=always_recreate_deps,
|
||||
reset_container_image=rebuild,
|
||||
renew_anonymous_volumes=options.get('--renew-anon-volumes')
|
||||
)
|
||||
|
||||
try:
|
||||
|
@ -1083,10 +1086,14 @@ def compute_exit_code(exit_value_from, attached_containers, cascade_starter, all
|
|||
def convergence_strategy_from_opts(options):
|
||||
no_recreate = options['--no-recreate']
|
||||
force_recreate = options['--force-recreate']
|
||||
renew_anonymous_volumes = options.get('--renew-anon-volumes')
|
||||
if force_recreate and no_recreate:
|
||||
raise UserError("--force-recreate and --no-recreate cannot be combined.")
|
||||
|
||||
if force_recreate:
|
||||
if no_recreate and renew_anonymous_volumes:
|
||||
raise UserError('--no-recreate and --renew-anon-volumes cannot be combined.')
|
||||
|
||||
if force_recreate or renew_anonymous_volumes:
|
||||
return ConvergenceStrategy.always
|
||||
|
||||
if no_recreate:
|
||||
|
|
|
@ -445,7 +445,8 @@ class Project(object):
|
|||
rescale=True,
|
||||
start=True,
|
||||
always_recreate_deps=False,
|
||||
reset_container_image=False):
|
||||
reset_container_image=False,
|
||||
renew_anonymous_volumes=False):
|
||||
|
||||
self.initialize()
|
||||
if not ignore_orphans:
|
||||
|
@ -474,7 +475,8 @@ class Project(object):
|
|||
rescale=rescale,
|
||||
start=start,
|
||||
project_services=scaled_services,
|
||||
reset_container_image=reset_container_image
|
||||
reset_container_image=reset_container_image,
|
||||
renew_anonymous_volumes=renew_anonymous_volumes,
|
||||
)
|
||||
|
||||
def get_deps(service):
|
||||
|
|
|
@ -409,7 +409,8 @@ class Service(object):
|
|||
|
||||
return containers
|
||||
|
||||
def _execute_convergence_recreate(self, containers, scale, timeout, detached, start):
|
||||
def _execute_convergence_recreate(self, containers, scale, timeout, detached, start,
|
||||
renew_anonymous_volumes):
|
||||
if scale is not None and len(containers) > scale:
|
||||
self._downscale(containers[scale:], timeout)
|
||||
containers = containers[:scale]
|
||||
|
@ -417,7 +418,7 @@ class Service(object):
|
|||
def recreate(container):
|
||||
return self.recreate_container(
|
||||
container, timeout=timeout, attach_logs=not detached,
|
||||
start_new_container=start
|
||||
start_new_container=start, renew_anonymous_volumes=renew_anonymous_volumes
|
||||
)
|
||||
containers, errors = parallel_execute(
|
||||
containers,
|
||||
|
@ -470,7 +471,7 @@ class Service(object):
|
|||
def execute_convergence_plan(self, plan, timeout=None, detached=False,
|
||||
start=True, scale_override=None,
|
||||
rescale=True, project_services=None,
|
||||
reset_container_image=False):
|
||||
reset_container_image=False, renew_anonymous_volumes=False):
|
||||
(action, containers) = plan
|
||||
scale = scale_override if scale_override is not None else self.scale_num
|
||||
containers = sorted(containers, key=attrgetter('number'))
|
||||
|
@ -495,7 +496,8 @@ class Service(object):
|
|||
for c in containers:
|
||||
c.reset_image(img_id)
|
||||
return self._execute_convergence_recreate(
|
||||
containers, scale, timeout, detached, start
|
||||
containers, scale, timeout, detached, start,
|
||||
renew_anonymous_volumes,
|
||||
)
|
||||
|
||||
if action == 'start':
|
||||
|
@ -515,7 +517,8 @@ class Service(object):
|
|||
|
||||
raise Exception("Invalid action: {}".format(action))
|
||||
|
||||
def recreate_container(self, container, timeout=None, attach_logs=False, start_new_container=True):
|
||||
def recreate_container(self, container, timeout=None, attach_logs=False, start_new_container=True,
|
||||
renew_anonymous_volumes=False):
|
||||
"""Recreate a container.
|
||||
|
||||
The original container is renamed to a temporary name so that data
|
||||
|
@ -526,7 +529,7 @@ class Service(object):
|
|||
container.stop(timeout=self.stop_timeout(timeout))
|
||||
container.rename_to_tmp_name()
|
||||
new_container = self.create_container(
|
||||
previous_container=container,
|
||||
previous_container=container if not renew_anonymous_volumes else None,
|
||||
number=container.labels.get(LABEL_CONTAINER_NUMBER),
|
||||
quiet=True,
|
||||
)
|
||||
|
|
|
@ -589,6 +589,25 @@ class ServiceTest(DockerClientTestCase):
|
|||
assert [mount['Destination'] for mount in new_container.get('Mounts')] == ['/data']
|
||||
assert new_container.get_mount('/data')['Source'] == volume_path
|
||||
|
||||
def test_execute_convergence_plan_with_image_declared_volume_renew(self):
|
||||
service = Service(
|
||||
project='composetest',
|
||||
name='db',
|
||||
client=self.client,
|
||||
build={'context': 'tests/fixtures/dockerfile-with-volume'},
|
||||
)
|
||||
|
||||
old_container = create_and_start_container(service)
|
||||
assert [mount['Destination'] for mount in old_container.get('Mounts')] == ['/data']
|
||||
volume_path = old_container.get_mount('/data')['Source']
|
||||
|
||||
new_container, = service.execute_convergence_plan(
|
||||
ConvergencePlan('recreate', [old_container]), renew_anonymous_volumes=True
|
||||
)
|
||||
|
||||
assert [mount['Destination'] for mount in new_container.get('Mounts')] == ['/data']
|
||||
assert new_container.get_mount('/data')['Source'] != volume_path
|
||||
|
||||
def test_execute_convergence_plan_when_image_volume_masks_config(self):
|
||||
service = self.create_service(
|
||||
'db',
|
||||
|
@ -637,6 +656,64 @@ class ServiceTest(DockerClientTestCase):
|
|||
)
|
||||
assert new_container.get_mount('/data')['Source'] != host_path
|
||||
|
||||
def test_execute_convergence_plan_anonymous_volume_renew(self):
|
||||
service = self.create_service(
|
||||
'db',
|
||||
image='busybox',
|
||||
volumes=[VolumeSpec(None, '/data', 'rw')])
|
||||
|
||||
old_container = create_and_start_container(service)
|
||||
assert (
|
||||
[mount['Destination'] for mount in old_container.get('Mounts')] ==
|
||||
['/data']
|
||||
)
|
||||
volume_path = old_container.get_mount('/data')['Source']
|
||||
|
||||
new_container, = service.execute_convergence_plan(
|
||||
ConvergencePlan('recreate', [old_container]),
|
||||
renew_anonymous_volumes=True
|
||||
)
|
||||
|
||||
assert (
|
||||
[mount['Destination'] for mount in new_container.get('Mounts')] ==
|
||||
['/data']
|
||||
)
|
||||
assert new_container.get_mount('/data')['Source'] != volume_path
|
||||
|
||||
def test_execute_convergence_plan_anonymous_volume_recreate_then_renew(self):
|
||||
service = self.create_service(
|
||||
'db',
|
||||
image='busybox',
|
||||
volumes=[VolumeSpec(None, '/data', 'rw')])
|
||||
|
||||
old_container = create_and_start_container(service)
|
||||
assert (
|
||||
[mount['Destination'] for mount in old_container.get('Mounts')] ==
|
||||
['/data']
|
||||
)
|
||||
volume_path = old_container.get_mount('/data')['Source']
|
||||
|
||||
mid_container, = service.execute_convergence_plan(
|
||||
ConvergencePlan('recreate', [old_container]),
|
||||
)
|
||||
|
||||
assert (
|
||||
[mount['Destination'] for mount in mid_container.get('Mounts')] ==
|
||||
['/data']
|
||||
)
|
||||
assert mid_container.get_mount('/data')['Source'] == volume_path
|
||||
|
||||
new_container, = service.execute_convergence_plan(
|
||||
ConvergencePlan('recreate', [mid_container]),
|
||||
renew_anonymous_volumes=True
|
||||
)
|
||||
|
||||
assert (
|
||||
[mount['Destination'] for mount in new_container.get('Mounts')] ==
|
||||
['/data']
|
||||
)
|
||||
assert new_container.get_mount('/data')['Source'] != volume_path
|
||||
|
||||
def test_execute_convergence_plan_without_start(self):
|
||||
service = self.create_service(
|
||||
'db',
|
||||
|
|
Loading…
Reference in New Issue