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  }