github.com/xiaobinqt/libcompose@v1.1.0/docker/service/name.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "golang.org/x/net/context" 8 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/api/types/filters" 11 "github.com/docker/docker/client" 12 "github.com/xiaobinqt/libcompose/labels" 13 ) 14 15 const format = "%s_%s_%d" 16 17 // Namer defines method to provide container name. 18 type Namer interface { 19 Next() (string, int) 20 } 21 22 type defaultNamer struct { 23 project string 24 service string 25 oneOff bool 26 currentNumber int 27 } 28 29 type singleNamer struct { 30 name string 31 } 32 33 // NewSingleNamer returns a namer that only allows a single name. 34 func NewSingleNamer(name string) Namer { 35 return &singleNamer{name} 36 } 37 38 // NewNamer returns a namer that returns names based on the specified project and 39 // service name and an inner counter, e.g. project_service_1, project_service_2… 40 func NewNamer(ctx context.Context, client client.ContainerAPIClient, project, service string, oneOff bool) (Namer, error) { 41 namer := &defaultNamer{ 42 project: project, 43 service: service, 44 oneOff: oneOff, 45 } 46 47 filter := filters.NewArgs() 48 filter.Add("label", fmt.Sprintf("%s=%s", labels.PROJECT.Str(), project)) 49 filter.Add("label", fmt.Sprintf("%s=%s", labels.SERVICE.Str(), service)) 50 if oneOff { 51 filter.Add("label", fmt.Sprintf("%s=%s", labels.ONEOFF.Str(), "True")) 52 } else { 53 filter.Add("label", fmt.Sprintf("%s=%s", labels.ONEOFF.Str(), "False")) 54 } 55 56 containers, err := client.ContainerList(ctx, types.ContainerListOptions{ 57 All: true, 58 Filters: filter, 59 }) 60 if err != nil { 61 return nil, err 62 } 63 64 maxNumber := 0 65 for _, container := range containers { 66 number, err := strconv.Atoi(container.Labels[labels.NUMBER.Str()]) 67 if err != nil { 68 return nil, err 69 } 70 if number > maxNumber { 71 maxNumber = number 72 } 73 } 74 namer.currentNumber = maxNumber + 1 75 76 return namer, nil 77 } 78 79 func (i *defaultNamer) Next() (string, int) { 80 service := i.service 81 if i.oneOff { 82 service = i.service + "_run" 83 } 84 name := fmt.Sprintf(format, i.project, service, i.currentNumber) 85 number := i.currentNumber 86 i.currentNumber = i.currentNumber + 1 87 return name, number 88 } 89 90 func (s *singleNamer) Next() (string, int) { 91 return s.name, 1 92 }