2016-05-03 23:17:16 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2016-08-22 19:49:28 +00:00
|
|
|
const (
|
|
|
|
// default docker registry
|
|
|
|
defaultRegistry = "https://index.docker.io/v1/"
|
|
|
|
)
|
|
|
|
|
2016-05-03 23:17:16 +00:00
|
|
|
type (
|
|
|
|
// Daemon defines Docker daemon parameters.
|
|
|
|
Daemon struct {
|
|
|
|
Registry string // Docker registry
|
|
|
|
Mirror string // Docker registry mirror
|
|
|
|
Insecure bool // Docker daemon enable insecure registries
|
|
|
|
StorageDriver string // Docker daemon storage driver
|
|
|
|
StoragePath string // Docker daemon storage path
|
|
|
|
Disabled bool // DOcker daemon is disabled (already running)
|
|
|
|
Debug bool // Docker daemon started in debug mode
|
|
|
|
Bip string // Docker daemon network bridge IP address
|
|
|
|
DNS []string // Docker daemon dns server
|
2016-07-26 10:09:00 +00:00
|
|
|
MTU string // Docker daemon mtu setting
|
2016-05-03 23:17:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Login defines Docker login parameters.
|
|
|
|
Login struct {
|
|
|
|
Registry string // Docker registry address
|
|
|
|
Username string // Docker registry username
|
|
|
|
Password string // Docker registry password
|
|
|
|
Email string // Docker registry email
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build defines Docker build parameters.
|
|
|
|
Build struct {
|
|
|
|
Name string // Docker build using default named tag
|
|
|
|
Dockerfile string // Docker build Dockerfile
|
|
|
|
Context string // Docker build context
|
|
|
|
Tags []string // Docker build tags
|
|
|
|
Args []string // Docker build args
|
|
|
|
Repo string // Docker build repository
|
|
|
|
}
|
|
|
|
|
|
|
|
// Plugin defines the Docker plugin parameters.
|
|
|
|
Plugin struct {
|
|
|
|
Login Login // Docker login configuration
|
|
|
|
Build Build // Docker build configuration
|
|
|
|
Daemon Daemon // Docker daemon configuration
|
|
|
|
Dryrun bool // Docker push is skipped
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// Exec executes the plugin step
|
|
|
|
func (p Plugin) Exec() error {
|
2016-08-22 19:49:28 +00:00
|
|
|
// this code attempts to normalize the repository name by appending the fully
|
|
|
|
// qualified registry name if otherwise omitted.
|
|
|
|
if p.Login.Registry != defaultRegistry &&
|
|
|
|
strings.HasPrefix(p.Build.Repo, defaultRegistry) {
|
|
|
|
p.Build.Repo = p.Login.Registry + "/" + p.Build.Repo
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO execute code remove dangling images
|
|
|
|
// this is problematic because we are running docker in scratch which does
|
|
|
|
// not have bash, so we need to hack something together
|
|
|
|
// docker images --quiet --filter=dangling=true | xargs --no-run-if-empty docker rmi
|
|
|
|
|
|
|
|
/*
|
|
|
|
cmd = exec.Command("docker", "images", "-q", "-f", "dangling=true")
|
|
|
|
cmd = exec.Command("docker", append([]string{"rmi"}, images...)...)
|
|
|
|
*/
|
2016-05-03 23:17:16 +00:00
|
|
|
|
|
|
|
// start the Docker daemon server
|
|
|
|
if !p.Daemon.Disabled {
|
|
|
|
cmd := commandDaemon(p.Daemon)
|
|
|
|
if p.Daemon.Debug {
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
} else {
|
|
|
|
cmd.Stdout = ioutil.Discard
|
|
|
|
cmd.Stderr = ioutil.Discard
|
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
trace(cmd)
|
|
|
|
cmd.Run()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// poll the docker daemon until it is started. This ensures the daemon is
|
|
|
|
// ready to accept connections before we proceed.
|
|
|
|
for i := 0; i < 15; i++ {
|
|
|
|
cmd := commandInfo()
|
|
|
|
err := cmd.Run()
|
|
|
|
if err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
time.Sleep(time.Second * 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// login to the Docker registry
|
|
|
|
if p.Login.Password != "" {
|
|
|
|
cmd := commandLogin(p.Login)
|
|
|
|
err := cmd.Run()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error authenticating: %s", err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fmt.Println("Registry credentials not provided. Guest mode enabled.")
|
|
|
|
}
|
|
|
|
|
|
|
|
var cmds []*exec.Cmd
|
|
|
|
cmds = append(cmds, commandVersion()) // docker version
|
|
|
|
cmds = append(cmds, commandInfo()) // docker info
|
|
|
|
cmds = append(cmds, commandBuild(p.Build)) // docker build
|
2016-06-18 20:38:38 +00:00
|
|
|
|
2016-05-03 23:17:16 +00:00
|
|
|
for _, tag := range p.Build.Tags {
|
|
|
|
cmds = append(cmds, commandTag(p.Build, tag)) // docker tag
|
2016-06-18 20:38:38 +00:00
|
|
|
|
2016-05-03 23:17:16 +00:00
|
|
|
if p.Dryrun == false {
|
2016-05-04 19:51:06 +00:00
|
|
|
cmds = append(cmds, commandPush(p.Build, tag)) // docker push
|
2016-05-03 23:17:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// execute all commands in batch mode.
|
|
|
|
for _, cmd := range cmds {
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
trace(cmd)
|
|
|
|
|
|
|
|
err := cmd.Run()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-05-20 20:00:06 +00:00
|
|
|
const dockerExe = "/usr/local/bin/docker"
|
|
|
|
|
2016-05-03 23:17:16 +00:00
|
|
|
// helper function to create the docker login command.
|
|
|
|
func commandLogin(login Login) *exec.Cmd {
|
2016-06-18 21:24:57 +00:00
|
|
|
if login.Email != "" {
|
2016-06-18 21:15:03 +00:00
|
|
|
return commandLoginEmail(login)
|
2016-06-18 20:56:22 +00:00
|
|
|
}
|
|
|
|
return exec.Command(
|
|
|
|
dockerExe, "login",
|
|
|
|
"-u", login.Username,
|
|
|
|
"-p", login.Password,
|
|
|
|
login.Registry,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2016-06-18 21:13:45 +00:00
|
|
|
func commandLoginEmail(login Login) *exec.Cmd {
|
2016-05-03 23:17:16 +00:00
|
|
|
return exec.Command(
|
2016-05-20 20:00:06 +00:00
|
|
|
dockerExe, "login",
|
2016-05-03 23:17:16 +00:00
|
|
|
"-u", login.Username,
|
|
|
|
"-p", login.Password,
|
2016-06-18 20:56:22 +00:00
|
|
|
"-e", login.Email,
|
2016-05-03 23:17:16 +00:00
|
|
|
login.Registry,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// helper function to create the docker info command.
|
|
|
|
func commandVersion() *exec.Cmd {
|
2016-05-20 20:00:06 +00:00
|
|
|
return exec.Command(dockerExe, "version")
|
2016-05-03 23:17:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// helper function to create the docker info command.
|
|
|
|
func commandInfo() *exec.Cmd {
|
2016-05-20 20:00:06 +00:00
|
|
|
return exec.Command(dockerExe, "info")
|
2016-05-03 23:17:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// helper function to create the docker build command.
|
|
|
|
func commandBuild(build Build) *exec.Cmd {
|
|
|
|
cmd := exec.Command(
|
2016-05-20 20:00:06 +00:00
|
|
|
dockerExe, "build",
|
2016-05-03 23:17:16 +00:00
|
|
|
"--pull=true",
|
|
|
|
"--rm=true",
|
|
|
|
"-f", build.Dockerfile,
|
|
|
|
"-t", build.Name,
|
|
|
|
)
|
|
|
|
for _, arg := range build.Args {
|
|
|
|
cmd.Args = append(cmd.Args, "--build-arg", arg)
|
|
|
|
}
|
|
|
|
cmd.Args = append(cmd.Args, build.Context)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
// helper function to create the docker tag command.
|
|
|
|
func commandTag(build Build, tag string) *exec.Cmd {
|
|
|
|
var (
|
2016-05-03 23:34:08 +00:00
|
|
|
source = build.Name
|
|
|
|
target = fmt.Sprintf("%s:%s", build.Repo, tag)
|
2016-05-03 23:17:16 +00:00
|
|
|
)
|
|
|
|
return exec.Command(
|
2016-05-20 20:00:06 +00:00
|
|
|
dockerExe, "tag", source, target,
|
2016-05-03 23:17:16 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// helper function to create the docker push command.
|
2016-05-04 19:51:06 +00:00
|
|
|
func commandPush(build Build, tag string) *exec.Cmd {
|
|
|
|
target := fmt.Sprintf("%s:%s", build.Repo, tag)
|
2016-05-20 20:00:06 +00:00
|
|
|
return exec.Command(dockerExe, "push", target)
|
2016-05-03 23:17:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// helper function to create the docker daemon command.
|
|
|
|
func commandDaemon(daemon Daemon) *exec.Cmd {
|
|
|
|
args := []string{"daemon", "-g", daemon.StoragePath}
|
|
|
|
|
|
|
|
if daemon.StorageDriver != "" {
|
|
|
|
args = append(args, "-s", daemon.StorageDriver)
|
|
|
|
}
|
|
|
|
if daemon.Insecure && daemon.Registry != "" {
|
|
|
|
args = append(args, "--insecure-registry", daemon.Registry)
|
|
|
|
}
|
|
|
|
if len(daemon.Mirror) != 0 {
|
|
|
|
args = append(args, "--registry-mirror", daemon.Mirror)
|
|
|
|
}
|
|
|
|
if len(daemon.Bip) != 0 {
|
|
|
|
args = append(args, "--bip", daemon.Bip)
|
|
|
|
}
|
|
|
|
for _, dns := range daemon.DNS {
|
|
|
|
args = append(args, "--dns", dns)
|
|
|
|
}
|
2016-07-25 21:45:31 +00:00
|
|
|
if len(daemon.MTU) != 0 {
|
|
|
|
args = append(args, "--mtu", daemon.MTU)
|
|
|
|
}
|
2016-05-20 20:00:06 +00:00
|
|
|
return exec.Command(dockerExe, args...)
|
2016-05-03 23:17:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// trace writes each command to stdout with the command wrapped in an xml
|
|
|
|
// tag so that it can be extracted and displayed in the logs.
|
|
|
|
func trace(cmd *exec.Cmd) {
|
2016-05-11 08:43:44 +00:00
|
|
|
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
|
2016-05-03 23:17:16 +00:00
|
|
|
}
|