112 lines
2.6 KiB
Go
112 lines
2.6 KiB
Go
package docker
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/drone/drone/build"
|
|
"github.com/drone/drone/build/docker/internal"
|
|
"github.com/drone/drone/yaml"
|
|
|
|
"github.com/samalba/dockerclient"
|
|
)
|
|
|
|
type dockerEngine struct {
|
|
client dockerclient.Client
|
|
}
|
|
|
|
func (e *dockerEngine) ContainerStart(container *yaml.Container) (string, error) {
|
|
conf := toContainerConfig(container)
|
|
auth := toAuthConfig(container)
|
|
|
|
// pull the image if it does not exists or if the Container
|
|
// is configured to always pull a new image.
|
|
_, err := e.client.InspectImage(container.Image)
|
|
if err != nil || container.Pull {
|
|
e.client.PullImage(container.Image, auth)
|
|
}
|
|
|
|
// create and start the container and return the Container ID.
|
|
id, err := e.client.CreateContainer(conf, container.ID, auth)
|
|
if err != nil {
|
|
return id, err
|
|
}
|
|
err = e.client.StartContainer(id, &conf.HostConfig)
|
|
if err != nil {
|
|
|
|
// remove the container if it cannot be started
|
|
e.client.RemoveContainer(id, true, true)
|
|
return id, err
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func (e *dockerEngine) ContainerStop(id string) error {
|
|
e.client.StopContainer(id, 1)
|
|
e.client.KillContainer(id, "9")
|
|
return nil
|
|
}
|
|
|
|
func (e *dockerEngine) ContainerRemove(id string) error {
|
|
e.client.StopContainer(id, 1)
|
|
e.client.KillContainer(id, "9")
|
|
e.client.RemoveContainer(id, true, true)
|
|
return nil
|
|
}
|
|
|
|
func (e *dockerEngine) ContainerWait(id string) (*build.State, error) {
|
|
// wait for the container to exit
|
|
//
|
|
// TODO(bradrydzewski) we should have a for loop here
|
|
// to re-connect and wait if this channel returns a
|
|
// result even though the container is still running.
|
|
//
|
|
<-e.client.Wait(id)
|
|
v, err := e.client.InspectContainer(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &build.State{
|
|
ExitCode: v.State.ExitCode,
|
|
OOMKilled: v.State.OOMKilled,
|
|
}, nil
|
|
}
|
|
|
|
func (e *dockerEngine) ContainerLogs(id string) (io.ReadCloser, error) {
|
|
opts := &dockerclient.LogOptions{
|
|
Follow: true,
|
|
Stdout: true,
|
|
Stderr: true,
|
|
}
|
|
|
|
piper, pipew := io.Pipe()
|
|
go func() {
|
|
defer pipew.Close()
|
|
|
|
// sometimes the docker logs fails due to parsing errors. this
|
|
// routine will check for such a failure and attempt to resume
|
|
// if necessary.
|
|
for i := 0; i < 5; i++ {
|
|
if i > 0 {
|
|
opts.Tail = 1
|
|
}
|
|
|
|
rc, err := e.client.ContainerLogs(id, opts)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer rc.Close()
|
|
|
|
// use Docker StdCopy
|
|
internal.StdCopy(pipew, pipew, rc)
|
|
|
|
// check to see if the container is still running. If not,
|
|
// we can safely exit and assume there are no more logs left
|
|
// to stream.
|
|
v, err := e.client.InspectContainer(id)
|
|
if err != nil || !v.State.Running {
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
return piper, nil
|
|
}
|