traefik/vendor/github.com/docker/libcompose/docker/service/service_create.go
Vincent Demeester b7daa2f3a4 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`)
2017-07-06 16:28:13 +02:00

181 lines
5.5 KiB
Go

package service
import (
"fmt"
"strconv"
"strings"
"golang.org/x/net/context"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/libcompose/config"
composecontainer "github.com/docker/libcompose/docker/container"
"github.com/docker/libcompose/labels"
"github.com/docker/libcompose/project"
"github.com/docker/libcompose/project/events"
util "github.com/docker/libcompose/utils"
)
func (s *Service) createContainer(ctx context.Context, namer Namer, oldContainer string, configOverride *config.ServiceConfig, oneOff bool) (*composecontainer.Container, error) {
serviceConfig := s.serviceConfig
if configOverride != nil {
serviceConfig.Command = configOverride.Command
serviceConfig.Tty = configOverride.Tty
serviceConfig.StdinOpen = configOverride.StdinOpen
}
configWrapper, err := ConvertToAPI(serviceConfig, s.context.Context, s.clientFactory)
if err != nil {
return nil, err
}
configWrapper.Config.Image = s.imageName()
containerName, containerNumber := namer.Next()
configWrapper.Config.Labels[labels.SERVICE.Str()] = s.name
configWrapper.Config.Labels[labels.PROJECT.Str()] = s.project.Name
configWrapper.Config.Labels[labels.HASH.Str()] = config.GetServiceHash(s.name, serviceConfig)
configWrapper.Config.Labels[labels.ONEOFF.Str()] = strings.Title(strconv.FormatBool(oneOff))
configWrapper.Config.Labels[labels.NUMBER.Str()] = fmt.Sprintf("%d", containerNumber)
configWrapper.Config.Labels[labels.VERSION.Str()] = project.ComposeVersion
err = s.populateAdditionalHostConfig(configWrapper.HostConfig)
if err != nil {
return nil, err
}
// FIXME(vdemeester): oldContainer should be a Container instead of a string
client := s.clientFactory.Create(s)
if oldContainer != "" {
info, err := client.ContainerInspect(ctx, oldContainer)
if err != nil {
return nil, err
}
configWrapper.HostConfig.Binds = util.Merge(configWrapper.HostConfig.Binds, volumeBinds(configWrapper.Config.Volumes, &info))
}
logrus.Debugf("Creating container %s %#v", containerName, configWrapper)
// FIXME(vdemeester): long-term will be container.Create(…)
container, err := composecontainer.Create(ctx, client, containerName, configWrapper.Config, configWrapper.HostConfig, configWrapper.NetworkingConfig)
if err != nil {
return nil, err
}
s.project.Notify(events.ContainerCreated, s.name, map[string]string{
"name": containerName,
})
return container, nil
}
func (s *Service) populateAdditionalHostConfig(hostConfig *containertypes.HostConfig) error {
links, err := s.getLinks()
if err != nil {
return err
}
for _, link := range s.DependentServices() {
if !s.project.ServiceConfigs.Has(link.Target) {
continue
}
service, err := s.project.CreateService(link.Target)
if err != nil {
return err
}
containers, err := service.Containers(context.Background())
if err != nil {
return err
}
if link.Type == project.RelTypeIpcNamespace {
hostConfig, err = addIpc(hostConfig, service, containers, s.serviceConfig.Ipc)
} else if link.Type == project.RelTypeNetNamespace {
hostConfig, err = addNetNs(hostConfig, service, containers, s.serviceConfig.NetworkMode)
}
if err != nil {
return err
}
}
hostConfig.Links = []string{}
for k, v := range links {
hostConfig.Links = append(hostConfig.Links, strings.Join([]string{v, k}, ":"))
}
for _, v := range s.serviceConfig.ExternalLinks {
hostConfig.Links = append(hostConfig.Links, v)
}
return nil
}
// FIXME(vdemeester) this is temporary
func (s *Service) getLinks() (map[string]string, error) {
links := map[string]string{}
for _, link := range s.DependentServices() {
if !s.project.ServiceConfigs.Has(link.Target) {
continue
}
service, err := s.project.CreateService(link.Target)
if err != nil {
return nil, err
}
// FIXME(vdemeester) container should not know service
containers, err := service.Containers(context.Background())
if err != nil {
return nil, err
}
if link.Type == project.RelTypeLink {
addLinks(links, service, link, containers)
}
if err != nil {
return nil, err
}
}
return links, nil
}
func addLinks(links map[string]string, service project.Service, rel project.ServiceRelationship, containers []project.Container) {
for _, container := range containers {
if _, ok := links[rel.Alias]; !ok {
links[rel.Alias] = container.Name()
}
links[container.Name()] = container.Name()
}
}
func addIpc(config *containertypes.HostConfig, service project.Service, containers []project.Container, ipc string) (*containertypes.HostConfig, error) {
if len(containers) == 0 {
return nil, fmt.Errorf("Failed to find container for IPC %v", ipc)
}
id := containers[0].ID()
config.IpcMode = containertypes.IpcMode("container:" + id)
return config, nil
}
func addNetNs(config *containertypes.HostConfig, service project.Service, containers []project.Container, networkMode string) (*containertypes.HostConfig, error) {
if len(containers) == 0 {
return nil, fmt.Errorf("Failed to find container for networks ns %v", networkMode)
}
id := containers[0].ID()
config.NetworkMode = containertypes.NetworkMode("container:" + id)
return config, nil
}
func volumeBinds(volumes map[string]struct{}, container *types.ContainerJSON) []string {
result := make([]string, 0, len(container.Mounts))
for _, mount := range container.Mounts {
if _, ok := volumes[mount.Destination]; ok {
result = append(result, fmt.Sprint(mount.Source, ":", mount.Destination))
}
}
return result
}