11from __future__ import unicode_literals
22from __future__ import absolute_import
33from collections import namedtuple
4- from docker .errors import APIError
54import logging
65import re
76import os
87import sys
8+
9+ from docker .errors import APIError
10+
911from .container import Container
1012from .progress_stream import stream_output , StreamOutputError
1113
@@ -43,6 +45,9 @@ class ConfigError(ValueError):
4345VolumeSpec = namedtuple ('VolumeSpec' , 'external internal mode' )
4446
4547
48+ ServiceName = namedtuple ('ServiceName' , 'project service number' )
49+
50+
4651class Service (object ):
4752 def __init__ (self , name , client = None , project = 'default' , links = None , volumes_from = None , ** options ):
4853 if not re .match ('^%s+$' % VALID_NAME_CHARS , name ):
@@ -185,8 +190,8 @@ def recreate_containers(self, **override_options):
185190 """
186191 containers = self .containers (stopped = True )
187192
188- if len ( containers ) == 0 :
189- log .info ("Creating %s..." % self .next_container_name ( ))
193+ if not containers :
194+ log .info ("Creating %s..." % self ._next_container_name ( containers ))
190195 container = self .create_container (** override_options )
191196 self .start_container (container )
192197 return [(None , container )]
@@ -264,7 +269,7 @@ def start_or_create_containers(self):
264269 containers = self .containers (stopped = True )
265270
266271 if not containers :
267- log .info ("Creating %s..." % self .next_container_name ( ))
272+ log .info ("Creating %s..." % self ._next_container_name ( containers ))
268273 new_container = self .create_container ()
269274 return [self .start_container (new_container )]
270275 else :
@@ -273,19 +278,15 @@ def start_or_create_containers(self):
273278 def get_linked_names (self ):
274279 return [s .name for (s , _ ) in self .links ]
275280
276- def next_container_name (self , one_off = False ):
281+ def _next_container_name (self , all_containers , one_off = False ):
277282 bits = [self .project , self .name ]
278283 if one_off :
279284 bits .append ('run' )
280- return '_' .join (bits + [str (self .next_container_number ( one_off = one_off ))])
285+ return '_' .join (bits + [str (self ._next_container_number ( all_containers ))])
281286
282- def next_container_number (self , one_off = False ):
283- numbers = [parse_name (c .name )[2 ] for c in self .containers (stopped = True , one_off = one_off )]
284-
285- if len (numbers ) == 0 :
286- return 1
287- else :
288- return max (numbers ) + 1
287+ def _next_container_number (self , all_containers ):
288+ numbers = [parse_name (c .name ).number for c in all_containers ]
289+ return 1 if not numbers else max (numbers ) + 1
289290
290291 def _get_links (self , link_to_self ):
291292 links = []
@@ -319,7 +320,9 @@ def _get_container_create_options(self, override_options, one_off=False):
319320 container_options = dict ((k , self .options [k ]) for k in DOCKER_CONFIG_KEYS if k in self .options )
320321 container_options .update (override_options )
321322
322- container_options ['name' ] = self .next_container_name (one_off )
323+ container_options ['name' ] = self ._next_container_name (
324+ self .containers (stopped = True , one_off = one_off ),
325+ one_off )
323326
324327 # If a qualified hostname was given, split it into an
325328 # unqualified hostname and a domainname unless domainname
@@ -424,10 +427,10 @@ def is_valid_name(name, one_off=False):
424427 return match .group (3 ) is None
425428
426429
427- def parse_name (name , one_off = False ):
430+ def parse_name (name ):
428431 match = NAME_RE .match (name )
429432 (project , service_name , _ , suffix ) = match .groups ()
430- return (project , service_name , int (suffix ))
433+ return ServiceName (project , service_name , int (suffix ))
431434
432435
433436def get_container_name (container ):
0 commit comments