Update traefik dependencies (docker/docker and related) (#1823)
Update traefik dependencies (docker/docker and related) - Update dependencies - Fix compilation problems - Remove vdemeester/docker-events (in docker api now) - Remove `integration/vendor` - Use `testImport` - update some deps. - regenerate the lock from scratch (after a `glide cc`)
This commit is contained in:
parent
7d178f49b4
commit
b7daa2f3a4
1301 changed files with 21476 additions and 150099 deletions
749
vendor/github.com/docker/libcompose/docker/service/service.go
generated
vendored
Normal file
749
vendor/github.com/docker/libcompose/docker/service/service.go
generated
vendored
Normal file
|
@ -0,0 +1,749 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/docker/auth"
|
||||
"github.com/docker/libcompose/docker/builder"
|
||||
composeclient "github.com/docker/libcompose/docker/client"
|
||||
"github.com/docker/libcompose/docker/container"
|
||||
"github.com/docker/libcompose/docker/ctx"
|
||||
"github.com/docker/libcompose/docker/image"
|
||||
"github.com/docker/libcompose/labels"
|
||||
"github.com/docker/libcompose/project"
|
||||
"github.com/docker/libcompose/project/events"
|
||||
"github.com/docker/libcompose/project/options"
|
||||
"github.com/docker/libcompose/utils"
|
||||
"github.com/docker/libcompose/yaml"
|
||||
)
|
||||
|
||||
// Service is a project.Service implementations.
|
||||
type Service struct {
|
||||
name string
|
||||
project *project.Project
|
||||
serviceConfig *config.ServiceConfig
|
||||
clientFactory composeclient.Factory
|
||||
authLookup auth.Lookup
|
||||
|
||||
// FIXME(vdemeester) remove this at some point
|
||||
context *ctx.Context
|
||||
}
|
||||
|
||||
// NewService creates a service
|
||||
func NewService(name string, serviceConfig *config.ServiceConfig, context *ctx.Context) *Service {
|
||||
return &Service{
|
||||
name: name,
|
||||
project: context.Project,
|
||||
serviceConfig: serviceConfig,
|
||||
clientFactory: context.ClientFactory,
|
||||
authLookup: context.AuthLookup,
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the service name.
|
||||
func (s *Service) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Config returns the configuration of the service (config.ServiceConfig).
|
||||
func (s *Service) Config() *config.ServiceConfig {
|
||||
return s.serviceConfig
|
||||
}
|
||||
|
||||
// DependentServices returns the dependent services (as an array of ServiceRelationship) of the service.
|
||||
func (s *Service) DependentServices() []project.ServiceRelationship {
|
||||
return DefaultDependentServices(s.project, s)
|
||||
}
|
||||
|
||||
// Create implements Service.Create. It ensures the image exists or build it
|
||||
// if it can and then create a container.
|
||||
func (s *Service) Create(ctx context.Context, options options.Create) error {
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.ensureImageExists(ctx, options.NoBuild, options.ForceBuild); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(containers) != 0 {
|
||||
return s.eachContainer(ctx, containers, func(c *container.Container) error {
|
||||
_, err := s.recreateIfNeeded(ctx, c, options.NoRecreate, options.ForceRecreate)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
namer, err := s.namer(ctx, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.createContainer(ctx, namer, "", nil, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) namer(ctx context.Context, count int) (Namer, error) {
|
||||
var namer Namer
|
||||
var err error
|
||||
|
||||
if s.serviceConfig.ContainerName != "" {
|
||||
if count > 1 {
|
||||
logrus.Warnf(`The "%s" service is using the custom container name "%s". Docker requires each container to have a unique name. Remove the custom name to scale the service.`, s.name, s.serviceConfig.ContainerName)
|
||||
}
|
||||
namer = NewSingleNamer(s.serviceConfig.ContainerName)
|
||||
} else {
|
||||
client := s.clientFactory.Create(s)
|
||||
namer, err = NewNamer(ctx, client, s.project.Name, s.name, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return namer, nil
|
||||
}
|
||||
|
||||
func (s *Service) collectContainers(ctx context.Context) ([]*container.Container, error) {
|
||||
client := s.clientFactory.Create(s)
|
||||
containers, err := container.ListByFilter(ctx, client, labels.SERVICE.Eq(s.name), labels.PROJECT.Eq(s.project.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*container.Container{}
|
||||
|
||||
for _, cont := range containers {
|
||||
c, err := container.New(ctx, client, cont.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, c)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Service) ensureImageExists(ctx context.Context, noBuild bool, forceBuild bool) error {
|
||||
if forceBuild {
|
||||
return s.build(ctx, options.Build{})
|
||||
}
|
||||
|
||||
exists, err := image.Exists(ctx, s.clientFactory.Create(s), s.imageName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.Config().Build.Context != "" {
|
||||
if noBuild {
|
||||
return fmt.Errorf("Service %q needs to be built, but no-build was specified", s.name)
|
||||
}
|
||||
return s.build(ctx, options.Build{})
|
||||
}
|
||||
|
||||
return s.Pull(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) imageName() string {
|
||||
if s.Config().Image != "" {
|
||||
return s.Config().Image
|
||||
}
|
||||
return fmt.Sprintf("%s_%s", s.project.Name, s.Name())
|
||||
}
|
||||
|
||||
// Build implements Service.Build. It will try to build the image and returns an error if any.
|
||||
func (s *Service) Build(ctx context.Context, buildOptions options.Build) error {
|
||||
return s.build(ctx, buildOptions)
|
||||
}
|
||||
|
||||
func (s *Service) build(ctx context.Context, buildOptions options.Build) error {
|
||||
if s.Config().Build.Context == "" {
|
||||
return fmt.Errorf("Specified service does not have a build section")
|
||||
}
|
||||
builder := &builder.DaemonBuilder{
|
||||
Client: s.clientFactory.Create(s),
|
||||
ContextDirectory: s.Config().Build.Context,
|
||||
Dockerfile: s.Config().Build.Dockerfile,
|
||||
BuildArgs: s.Config().Build.Args,
|
||||
AuthConfigs: s.authLookup.All(),
|
||||
NoCache: buildOptions.NoCache,
|
||||
ForceRemove: buildOptions.ForceRemove,
|
||||
Pull: buildOptions.Pull,
|
||||
LoggerFactory: s.context.LoggerFactory,
|
||||
}
|
||||
return builder.Build(ctx, s.imageName())
|
||||
}
|
||||
|
||||
func (s *Service) constructContainers(ctx context.Context, count int) ([]*container.Container, error) {
|
||||
result, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := s.clientFactory.Create(s)
|
||||
|
||||
var namer Namer
|
||||
|
||||
if s.serviceConfig.ContainerName != "" {
|
||||
if count > 1 {
|
||||
logrus.Warnf(`The "%s" service is using the custom container name "%s". Docker requires each container to have a unique name. Remove the custom name to scale the service.`, s.name, s.serviceConfig.ContainerName)
|
||||
}
|
||||
namer = NewSingleNamer(s.serviceConfig.ContainerName)
|
||||
} else {
|
||||
namer, err = NewNamer(ctx, client, s.project.Name, s.name, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for i := len(result); i < count; i++ {
|
||||
c, err := s.createContainer(ctx, namer, "", nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id := c.ID()
|
||||
logrus.Debugf("Created container %s: %v", id, c.Name())
|
||||
|
||||
result = append(result, c)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Up implements Service.Up. It builds the image if needed, creates a container
|
||||
// and start it.
|
||||
func (s *Service) Up(ctx context.Context, options options.Up) error {
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var imageName = s.imageName()
|
||||
if len(containers) == 0 || !options.NoRecreate {
|
||||
if err = s.ensureImageExists(ctx, options.NoBuild, options.ForceBuild); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return s.up(ctx, imageName, true, options)
|
||||
}
|
||||
|
||||
// Run implements Service.Run. It runs a one of command within the service container.
|
||||
// It always create a new container.
|
||||
func (s *Service) Run(ctx context.Context, commandParts []string, options options.Run) (int, error) {
|
||||
err := s.ensureImageExists(ctx, false, false)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
client := s.clientFactory.Create(s)
|
||||
|
||||
namer, err := NewNamer(ctx, client, s.project.Name, s.name, true)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
configOverride := &config.ServiceConfig{Command: commandParts, Tty: true, StdinOpen: true}
|
||||
|
||||
c, err := s.createContainer(ctx, namer, "", configOverride, true)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if err := s.connectContainerToNetworks(ctx, c, true); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if options.Detached {
|
||||
logrus.Infof("%s", c.Name())
|
||||
return 0, c.Start(ctx)
|
||||
}
|
||||
return c.Run(ctx, configOverride)
|
||||
}
|
||||
|
||||
// Info implements Service.Info. It returns an project.InfoSet with the containers
|
||||
// related to this service (can be multiple if using the scale command).
|
||||
func (s *Service) Info(ctx context.Context) (project.InfoSet, error) {
|
||||
result := project.InfoSet{}
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
info, err := c.Info(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, info)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Start implements Service.Start. It tries to start a container without creating it.
|
||||
func (s *Service) Start(ctx context.Context) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *container.Container) error {
|
||||
if err := s.connectContainerToNetworks(ctx, c, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Start(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) up(ctx context.Context, imageName string, create bool, options options.Up) error {
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debugf("Found %d existing containers for service %s", len(containers), s.name)
|
||||
|
||||
if len(containers) == 0 && create {
|
||||
namer, err := s.namer(ctx, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c, err := s.createContainer(ctx, namer, "", nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containers = []*container.Container{c}
|
||||
}
|
||||
|
||||
return s.eachContainer(ctx, containers, func(c *container.Container) error {
|
||||
var err error
|
||||
if create {
|
||||
c, err = s.recreateIfNeeded(ctx, c, options.NoRecreate, options.ForceRecreate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.connectContainerToNetworks(ctx, c, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.Start(ctx)
|
||||
|
||||
if err == nil {
|
||||
s.project.Notify(events.ContainerStarted, s.name, map[string]string{
|
||||
"name": c.Name(),
|
||||
})
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) connectContainerToNetworks(ctx context.Context, c *container.Container, oneOff bool) error {
|
||||
connectedNetworks, err := c.Networks()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if s.serviceConfig.Networks != nil {
|
||||
for _, network := range s.serviceConfig.Networks.Networks {
|
||||
existingNetwork, ok := connectedNetworks[network.Name]
|
||||
if ok {
|
||||
// FIXME(vdemeester) implement alias checking (to not disconnect/reconnect for nothing)
|
||||
aliasPresent := false
|
||||
for _, alias := range existingNetwork.Aliases {
|
||||
ID := c.ShortID()
|
||||
if alias == ID {
|
||||
aliasPresent = true
|
||||
}
|
||||
}
|
||||
if aliasPresent {
|
||||
continue
|
||||
}
|
||||
if err := s.NetworkDisconnect(ctx, c, network, oneOff); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := s.NetworkConnect(ctx, c, network, oneOff); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NetworkDisconnect disconnects the container from the specified network
|
||||
func (s *Service) NetworkDisconnect(ctx context.Context, c *container.Container, net *yaml.Network, oneOff bool) error {
|
||||
containerID := c.ID()
|
||||
client := s.clientFactory.Create(s)
|
||||
return client.NetworkDisconnect(ctx, net.RealName, containerID, true)
|
||||
}
|
||||
|
||||
// NetworkConnect connects the container to the specified network
|
||||
// FIXME(vdemeester) will be refactor with Container refactoring
|
||||
func (s *Service) NetworkConnect(ctx context.Context, c *container.Container, net *yaml.Network, oneOff bool) error {
|
||||
containerID := c.ID()
|
||||
client := s.clientFactory.Create(s)
|
||||
internalLinks, err := s.getLinks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
links := []string{}
|
||||
// TODO(vdemeester) handle link to self (?)
|
||||
for k, v := range internalLinks {
|
||||
links = append(links, strings.Join([]string{v, k}, ":"))
|
||||
}
|
||||
for _, v := range s.serviceConfig.ExternalLinks {
|
||||
links = append(links, v)
|
||||
}
|
||||
aliases := []string{}
|
||||
if !oneOff {
|
||||
aliases = []string{s.Name()}
|
||||
}
|
||||
aliases = append(aliases, net.Aliases...)
|
||||
return client.NetworkConnect(ctx, net.RealName, containerID, &network.EndpointSettings{
|
||||
Aliases: aliases,
|
||||
Links: links,
|
||||
IPAddress: net.IPv4Address,
|
||||
IPAMConfig: &network.EndpointIPAMConfig{
|
||||
IPv4Address: net.IPv4Address,
|
||||
IPv6Address: net.IPv6Address,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) recreateIfNeeded(ctx context.Context, c *container.Container, noRecreate, forceRecreate bool) (*container.Container, error) {
|
||||
if noRecreate {
|
||||
return c, nil
|
||||
}
|
||||
outOfSync, err := s.OutOfSync(ctx, c)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"outOfSync": outOfSync,
|
||||
"ForceRecreate": forceRecreate,
|
||||
"NoRecreate": noRecreate}).Debug("Going to decide if recreate is needed")
|
||||
|
||||
if forceRecreate || outOfSync {
|
||||
logrus.Infof("Recreating %s", s.name)
|
||||
newContainer, err := s.recreate(ctx, c)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
return newContainer, nil
|
||||
}
|
||||
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (s *Service) recreate(ctx context.Context, c *container.Container) (*container.Container, error) {
|
||||
name := c.Name()
|
||||
id := c.ID()
|
||||
newName := fmt.Sprintf("%s_%s", name, id[:12])
|
||||
logrus.Debugf("Renaming %s => %s", name, newName)
|
||||
if err := c.Rename(ctx, newName); err != nil {
|
||||
logrus.Errorf("Failed to rename old container %s", c.Name())
|
||||
return nil, err
|
||||
}
|
||||
namer := NewSingleNamer(name)
|
||||
newContainer, err := s.createContainer(ctx, namer, id, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newID := newContainer.ID()
|
||||
logrus.Debugf("Created replacement container %s", newID)
|
||||
if err := c.Remove(ctx, false); err != nil {
|
||||
logrus.Errorf("Failed to remove old container %s", c.Name())
|
||||
return nil, err
|
||||
}
|
||||
logrus.Debugf("Removed old container %s %s", c.Name(), id)
|
||||
return newContainer, nil
|
||||
}
|
||||
|
||||
// OutOfSync checks if the container is out of sync with the service definition.
|
||||
// It looks if the the service hash container label is the same as the computed one.
|
||||
func (s *Service) OutOfSync(ctx context.Context, c *container.Container) (bool, error) {
|
||||
if c.ImageConfig() != s.serviceConfig.Image {
|
||||
logrus.Debugf("Images for %s do not match %s!=%s", c.Name(), c.ImageConfig(), s.serviceConfig.Image)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
expectedHash := config.GetServiceHash(s.name, s.Config())
|
||||
if c.Hash() != expectedHash {
|
||||
logrus.Debugf("Hashes for %s do not match %s!=%s", c.Name(), c.Hash(), expectedHash)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
image, err := image.InspectImage(ctx, s.clientFactory.Create(s), c.ImageConfig())
|
||||
if err != nil {
|
||||
if client.IsErrImageNotFound(err) {
|
||||
logrus.Debugf("Image %s do not exist, do not know if it's out of sync", c.Image())
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
logrus.Debugf("Checking existing image name vs id: %s == %s", image.ID, c.Image())
|
||||
return image.ID != c.Image(), err
|
||||
}
|
||||
|
||||
func (s *Service) collectContainersAndDo(ctx context.Context, action func(*container.Container) error) error {
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.eachContainer(ctx, containers, action)
|
||||
}
|
||||
|
||||
func (s *Service) eachContainer(ctx context.Context, containers []*container.Container, action func(*container.Container) error) error {
|
||||
|
||||
tasks := utils.InParallel{}
|
||||
for _, cont := range containers {
|
||||
task := func(cont *container.Container) func() error {
|
||||
return func() error {
|
||||
return action(cont)
|
||||
}
|
||||
}(cont)
|
||||
|
||||
tasks.Add(task)
|
||||
}
|
||||
|
||||
return tasks.Wait()
|
||||
}
|
||||
|
||||
// Stop implements Service.Stop. It stops any containers related to the service.
|
||||
func (s *Service) Stop(ctx context.Context, timeout int) error {
|
||||
timeout = s.stopTimeout(timeout)
|
||||
return s.collectContainersAndDo(ctx, func(c *container.Container) error {
|
||||
return c.Stop(ctx, timeout)
|
||||
})
|
||||
}
|
||||
|
||||
// Restart implements Service.Restart. It restarts any containers related to the service.
|
||||
func (s *Service) Restart(ctx context.Context, timeout int) error {
|
||||
timeout = s.stopTimeout(timeout)
|
||||
return s.collectContainersAndDo(ctx, func(c *container.Container) error {
|
||||
return c.Restart(ctx, timeout)
|
||||
})
|
||||
}
|
||||
|
||||
// Kill implements Service.Kill. It kills any containers related to the service.
|
||||
func (s *Service) Kill(ctx context.Context, signal string) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *container.Container) error {
|
||||
return c.Kill(ctx, signal)
|
||||
})
|
||||
}
|
||||
|
||||
// Delete implements Service.Delete. It removes any containers related to the service.
|
||||
func (s *Service) Delete(ctx context.Context, options options.Delete) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *container.Container) error {
|
||||
running := c.IsRunning(ctx)
|
||||
if !running || options.RemoveRunning {
|
||||
return c.Remove(ctx, options.RemoveVolume)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Log implements Service.Log. It returns the docker logs for each container related to the service.
|
||||
func (s *Service) Log(ctx context.Context, follow bool) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *container.Container) error {
|
||||
containerNumber, err := c.Number()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := fmt.Sprintf("%s_%d", s.name, containerNumber)
|
||||
if s.Config().ContainerName != "" {
|
||||
name = s.Config().ContainerName
|
||||
}
|
||||
l := s.context.LoggerFactory.CreateContainerLogger(name)
|
||||
return c.Log(ctx, l, follow)
|
||||
})
|
||||
}
|
||||
|
||||
// Scale implements Service.Scale. It creates or removes containers to have the specified number
|
||||
// of related container to the service to run.
|
||||
func (s *Service) Scale(ctx context.Context, scale int, timeout int) error {
|
||||
if s.specificiesHostPort() {
|
||||
logrus.Warnf("The \"%s\" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.", s.Name())
|
||||
}
|
||||
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(containers) > scale {
|
||||
foundCount := 0
|
||||
for _, c := range containers {
|
||||
foundCount++
|
||||
if foundCount > scale {
|
||||
timeout = s.stopTimeout(timeout)
|
||||
if err := c.Stop(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
// FIXME(vdemeester) remove volume in scale by default ?
|
||||
if err := c.Remove(ctx, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(containers) < scale {
|
||||
err := s.ensureImageExists(ctx, false, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = s.constructContainers(ctx, scale); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return s.up(ctx, "", false, options.Up{})
|
||||
}
|
||||
|
||||
// Pull implements Service.Pull. It pulls the image of the service and skip the service that
|
||||
// would need to be built.
|
||||
func (s *Service) Pull(ctx context.Context) error {
|
||||
if s.Config().Image == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return image.PullImage(ctx, s.clientFactory.Create(s), s.name, s.authLookup, s.Config().Image)
|
||||
}
|
||||
|
||||
// Pause implements Service.Pause. It puts into pause the container(s) related
|
||||
// to the service.
|
||||
func (s *Service) Pause(ctx context.Context) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *container.Container) error {
|
||||
return c.Pause(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
// Unpause implements Service.Pause. It brings back from pause the container(s)
|
||||
// related to the service.
|
||||
func (s *Service) Unpause(ctx context.Context) error {
|
||||
return s.collectContainersAndDo(ctx, func(c *container.Container) error {
|
||||
return c.Unpause(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
// RemoveImage implements Service.RemoveImage. It removes images used for the service
|
||||
// depending on the specified type.
|
||||
func (s *Service) RemoveImage(ctx context.Context, imageType options.ImageType) error {
|
||||
switch imageType {
|
||||
case "local":
|
||||
if s.Config().Image != "" {
|
||||
return nil
|
||||
}
|
||||
return image.RemoveImage(ctx, s.clientFactory.Create(s), s.imageName())
|
||||
case "all":
|
||||
return image.RemoveImage(ctx, s.clientFactory.Create(s), s.imageName())
|
||||
default:
|
||||
// Don't do a thing, should be validated up-front
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var eventAttributes = []string{"image", "name"}
|
||||
|
||||
// Events implements Service.Events. It listen to all real-time events happening
|
||||
// for the service, and put them into the specified chan.
|
||||
func (s *Service) Events(ctx context.Context, evts chan events.ContainerEvent) error {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", labels.PROJECT, s.project.Name))
|
||||
filter.Add("label", fmt.Sprintf("%s=%s", labels.SERVICE, s.name))
|
||||
client := s.clientFactory.Create(s)
|
||||
eventq, errq := client.Events(ctx, types.EventsOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event := <-eventq:
|
||||
service := event.Actor.Attributes[labels.SERVICE.Str()]
|
||||
attributes := map[string]string{}
|
||||
for _, attr := range eventAttributes {
|
||||
attributes[attr] = event.Actor.Attributes[attr]
|
||||
}
|
||||
e := events.ContainerEvent{
|
||||
Service: service,
|
||||
Event: event.Action,
|
||||
Type: event.Type,
|
||||
ID: event.Actor.ID,
|
||||
Time: time.Unix(event.Time, 0),
|
||||
Attributes: attributes,
|
||||
}
|
||||
evts <- e
|
||||
}
|
||||
}
|
||||
}()
|
||||
return <-errq
|
||||
}
|
||||
|
||||
// Containers implements Service.Containers. It returns the list of containers
|
||||
// that are related to the service.
|
||||
func (s *Service) Containers(ctx context.Context) ([]project.Container, error) {
|
||||
result := []project.Container{}
|
||||
containers, err := s.collectContainers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
result = append(result, c)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Service) specificiesHostPort() bool {
|
||||
_, bindings, err := nat.ParsePortSpecs(s.Config().Ports)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
for _, portBindings := range bindings {
|
||||
for _, portBinding := range portBindings {
|
||||
if portBinding.HostPort != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//take in timeout flag from cli as parameter
|
||||
//return timeout if it is set,
|
||||
//else return stop_grace_period if it is set,
|
||||
//else return default 10s
|
||||
func (s *Service) stopTimeout(timeout int) int {
|
||||
DEFAULTTIMEOUT := 10
|
||||
if timeout != 0 {
|
||||
return timeout
|
||||
}
|
||||
configTimeout := utils.DurationStrToSecondsInt(s.Config().StopGracePeriod)
|
||||
if configTimeout != nil {
|
||||
return *configTimeout
|
||||
}
|
||||
return DEFAULTTIMEOUT
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue