harness-drone/builder/docker/ambassador.go

110 lines
3.1 KiB
Go

package docker
import (
"errors"
log "github.com/Sirupsen/logrus"
"github.com/samalba/dockerclient"
)
var errNop = errors.New("Operation not supported")
// Ambassador is a wrapper around the Docker client that
// provides a shared volume and network for all containers.
type Ambassador struct {
dockerclient.Client
name string
}
// NewAmbassador creates an ambassador container and wraps the Docker
// client to inject the ambassador volume and network into containers.
func NewAmbassador(client dockerclient.Client) (_ *Ambassador, err error) {
amb := &Ambassador{client, ""}
conf := &dockerclient.ContainerConfig{}
host := &dockerclient.HostConfig{}
conf.Entrypoint = []string{"/bin/sleep"}
conf.Cmd = []string{"86400"}
conf.Image = "busybox"
conf.Volumes = map[string]struct{}{}
conf.Volumes["/drone"] = struct{}{}
// creates the ambassador container
amb.name, err = client.CreateContainer(conf, "")
if err != nil {
log.WithField("ambassador", conf.Image).Errorln(err)
// on failure attempts to pull the image
client.PullImage(conf.Image, nil)
// then attempts to re-create the container
amb.name, err = client.CreateContainer(conf, "")
if err != nil {
log.WithField("ambassador", conf.Image).Errorln(err)
return nil, err
}
}
err = client.StartContainer(amb.name, host)
if err != nil {
log.WithField("ambassador", conf.Image).Errorln(err)
}
return amb, err
}
// Destroy stops and deletes the ambassador container.
func (c *Ambassador) Destroy() error {
c.Client.StopContainer(c.name, 5)
c.Client.KillContainer(c.name, "9")
return c.Client.RemoveContainer(c.name, true, true)
}
// CreateContainer creates a container.
func (c *Ambassador) CreateContainer(conf *dockerclient.ContainerConfig, name string) (string, error) {
log.WithField("image", conf.Image).Infoln("create container")
// add the affinity flag for swarm
conf.Env = append(conf.Env, "affinity:container=="+c.name)
id, err := c.Client.CreateContainer(conf, name)
if err != nil {
log.WithField("image", conf.Image).Errorln(err)
}
return id, err
}
// StartContainer starts a container. The ambassador volume
// is automatically linked. The ambassador network is linked
// iff a network mode is not already specified.
func (c *Ambassador) StartContainer(id string, conf *dockerclient.HostConfig) error {
log.WithField("container", id).Debugln("start container")
conf.VolumesFrom = append(conf.VolumesFrom, c.name)
if len(conf.NetworkMode) == 0 {
conf.NetworkMode = "container:" + c.name
}
err := c.Client.StartContainer(id, conf)
if err != nil {
log.WithField("container", id).Errorln(err)
}
return err
}
// StopContainer stops a container.
func (c *Ambassador) StopContainer(id string, timeout int) error {
log.WithField("container", id).Debugln("stop container")
err := c.Client.StopContainer(id, timeout)
if err != nil {
log.WithField("container", id).Errorln(err)
}
return err
}
// PullImage pulls an image.
func (c *Ambassador) PullImage(name string, auth *dockerclient.AuthConfig) error {
log.WithField("image", name).Debugln("pull image")
err := c.Client.PullImage(name, auth)
if err != nil {
log.WithField("image", name).Errorln(err)
}
return err
}