浏览代码

Merge pull request #5982 from docker/5933-retrieve-legacy-containers

Allow all Compose commands to retrieve and handle legacy-name containers
Joffrey F 7 年之前
父节点
当前提交
706164accd
共有 3 个文件被更改,包括 46 次插入21 次删除
  1. 8 0
      compose/container.py
  2. 16 3
      compose/project.py
  3. 22 18
      compose/service.py

+ 8 - 0
compose/container.py

@@ -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])
 

+ 16 - 3
compose/project.py

@@ -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:

+ 22 - 18
compose/service.py

@@ -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(