Allow all Compose commands to retrieve and handle legacy-name containers

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2018-05-23 16:28:41 -07:00
parent cc62764c12
commit e245fb04cf
3 changed files with 46 additions and 21 deletions

View File

@ -9,6 +9,8 @@ from docker.errors import ImageNotFound
from .const import LABEL_CONTAINER_NUMBER
from .const import LABEL_PROJECT
from .const import LABEL_SERVICE
from .const import LABEL_VERSION
from .version import ComposeVersion
class Container(object):
@ -283,6 +285,12 @@ class Container(object):
def attach(self, *args, **kwargs):
return self.client.attach(self.id, *args, **kwargs)
def has_legacy_proj_name(self, project_name):
return (
ComposeVersion(self.labels.get(LABEL_VERSION)) < ComposeVersion('1.21.0') and
self.project != project_name
)
def __repr__(self):
return '<Container: %s (%s)>' % (self.name, self.id[:6])

View File

@ -4,6 +4,7 @@ from __future__ import unicode_literals
import datetime
import logging
import operator
import re
from functools import reduce
import enum
@ -70,8 +71,11 @@ class Project(object):
self.networks = networks or ProjectNetworks({}, False)
self.config_version = config_version
def labels(self, one_off=OneOffFilter.exclude):
labels = ['{0}={1}'.format(LABEL_PROJECT, self.name)]
def labels(self, one_off=OneOffFilter.exclude, legacy=False):
name = self.name
if legacy:
name = re.sub(r'[_-]', '', name)
labels = ['{0}={1}'.format(LABEL_PROJECT, name)]
OneOffFilter.update_labels(one_off, labels)
return labels
@ -571,12 +575,21 @@ class Project(object):
service.push(ignore_push_failures)
def _labeled_containers(self, stopped=False, one_off=OneOffFilter.exclude):
return list(filter(None, [
ctnrs = list(filter(None, [
Container.from_ps(self.client, container)
for container in self.client.containers(
all=stopped,
filters={'label': self.labels(one_off=one_off)})])
)
if ctnrs:
return ctnrs
return list(filter(lambda c: c.has_legacy_proj_name(self.name), filter(None, [
Container.from_ps(self.client, container)
for container in self.client.containers(
all=stopped,
filters={'label': self.labels(one_off=one_off, legacy=True)})])
))
def containers(self, service_names=None, stopped=False, one_off=OneOffFilter.exclude):
if service_names:

View File

@ -1,6 +1,7 @@
from __future__ import absolute_import
from __future__ import unicode_literals
import itertools
import logging
import os
import re
@ -51,7 +52,6 @@ from .progress_stream import StreamOutputError
from .utils import json_hash
from .utils import parse_bytes
from .utils import parse_seconds_float
from .version import ComposeVersion
log = logging.getLogger(__name__)
@ -192,8 +192,8 @@ class Service(object):
def __repr__(self):
return '<Service: {}>'.format(self.name)
def containers(self, stopped=False, one_off=False, filters={}):
filters.update({'label': self.labels(one_off=one_off)})
def containers(self, stopped=False, one_off=False, filters={}, labels=None):
filters.update({'label': self.labels(one_off=one_off) + (labels or [])})
result = list(filter(None, [
Container.from_ps(self.client, container)
@ -204,10 +204,10 @@ class Service(object):
if result:
return result
filters.update({'label': self.labels(one_off=one_off, legacy=True)})
filters.update({'label': self.labels(one_off=one_off, legacy=True) + (labels or [])})
return list(
filter(
self.has_legacy_proj_name, filter(None, [
lambda c: c.has_legacy_proj_name(self.project), filter(None, [
Container.from_ps(self.client, container)
for container in self.client.containers(
all=stopped,
@ -219,9 +219,9 @@ class Service(object):
"""Return a :class:`compose.container.Container` for this service. The
container must be active, and match `number`.
"""
labels = self.labels() + ['{0}={1}'.format(LABEL_CONTAINER_NUMBER, number)]
for container in self.client.containers(filters={'label': labels}):
return Container.from_ps(self.client, container)
for container in self.containers(labels=['{0}={1}'.format(LABEL_CONTAINER_NUMBER, number)]):
return container
raise ValueError("No container found for %s_%s" % (self.name, number))
@ -258,6 +258,11 @@ class Service(object):
running_containers = self.containers(stopped=False)
num_running = len(running_containers)
for c in running_containers:
if not c.has_legacy_proj_name(self.project):
continue
log.info('Recreating container with legacy name %s' % c.name)
self.recreate_container(c, timeout, start_new_container=False)
if desired_num == num_running:
# do nothing as we already have the desired number
@ -404,7 +409,7 @@ class Service(object):
has_diverged = False
for c in containers:
if self.has_legacy_proj_name(c):
if c.has_legacy_proj_name(self.project):
log.debug('%s has diverged: Legacy project name' % c.name)
has_diverged = True
continue
@ -713,9 +718,14 @@ class Service(object):
# TODO: this would benefit from github.com/docker/docker/pull/14699
# to remove the need to inspect every container
def _next_container_number(self, one_off=False):
containers = self._fetch_containers(
all=True,
filters={'label': self.labels(one_off=one_off)}
containers = itertools.chain(
self._fetch_containers(
all=True,
filters={'label': self.labels(one_off=one_off)}
), self._fetch_containers(
all=True,
filters={'label': self.labels(one_off=one_off, legacy=True)}
)
)
numbers = [c.number for c in containers]
return 1 if not numbers else max(numbers) + 1
@ -1243,12 +1253,6 @@ class Service(object):
return result
def has_legacy_proj_name(self, ctnr):
return (
ComposeVersion(ctnr.labels.get(LABEL_VERSION)) < ComposeVersion('1.21.0') and
ctnr.project != self.project
)
def short_id_alias_exists(container, network):
aliases = container.get(