drone-docker/main.go

249 lines
6.1 KiB
Go
Raw Normal View History

2015-05-15 07:12:50 +02:00
package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
2015-05-15 07:12:50 +02:00
"strings"
"time"
"github.com/drone/drone-plugin-go/plugin"
)
type Archive struct {
File string `json:"file"`
Tag StrSlice `json:"tag"`
}
2015-05-15 07:12:50 +02:00
type Docker struct {
2015-10-28 01:53:51 +01:00
Storage string `json:"storage_driver"`
Registry string `json:"registry"`
Insecure bool `json:"insecure"`
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
Auth string `json:"auth"`
Repo string `json:"repo"`
Tag StrSlice `json:"tag"`
File string `json:"file"`
Context string `json:"context"`
Dns []string `json:"dns"`
Archive Archive `json:"archive"`
2015-05-15 07:12:50 +02:00
}
func main() {
2015-09-03 00:30:42 +02:00
workspace := plugin.Workspace{}
build := plugin.Build{}
2015-05-15 07:12:50 +02:00
vargs := Docker{}
2015-09-03 00:30:42 +02:00
plugin.Param("workspace", &workspace)
plugin.Param("build", &build)
2015-05-15 07:12:50 +02:00
plugin.Param("vargs", &vargs)
2015-09-03 00:30:42 +02:00
plugin.MustParse()
2015-05-15 07:12:50 +02:00
2015-09-04 22:01:18 +02:00
// in case someone uses the shorthand repository name
// with a custom registry, we should concatinate so that
// we have the fully qualified image name.
2015-10-21 14:27:34 +02:00
if strings.Count(vargs.Repo, "/") <= 1 && len(vargs.Registry) != 0 && !strings.HasPrefix(vargs.Repo, vargs.Registry) {
2015-09-04 22:01:18 +02:00
vargs.Repo = fmt.Sprintf("%s/%s", vargs.Registry, vargs.Repo)
}
// Set the Registry value
if len(vargs.Registry) == 0 {
vargs.Registry = "https://index.docker.io/v1/"
}
2015-10-16 09:37:17 +02:00
// Set the Dockerfile name
if len(vargs.File) == 0 {
2015-10-24 23:32:54 +02:00
vargs.File = "Dockerfile"
2015-10-16 09:37:17 +02:00
}
// Set the Context value
if len(vargs.Context) == 0 {
vargs.Context = "."
2015-05-15 08:20:26 +02:00
}
// Set the Tag value
2015-10-28 01:53:51 +01:00
if vargs.Tag.Len() == 0 {
vargs.Tag = StrSlice{[]string{"latest"}}
}
// Archive file can be both a relative or absolute path
if len(vargs.Archive.File) != 0 {
if ! filepath.IsAbs(vargs.Archive.File) {
vargs.Archive.File = filepath.Join(workspace.Path, vargs.Archive.File)
}
}
2015-05-15 08:20:26 +02:00
2015-05-15 07:12:50 +02:00
go func() {
args := []string{"-d"}
2015-05-15 08:20:26 +02:00
2015-09-04 21:14:09 +02:00
if len(vargs.Storage) != 0 {
args = append(args, "-s", vargs.Storage)
}
2015-09-03 07:14:57 +02:00
if vargs.Insecure && len(vargs.Registry) != 0 {
args = append(args, "--insecure-registry", vargs.Registry)
}
2015-09-04 03:17:51 +02:00
for _, value := range vargs.Dns {
args = append(args, "--dns", value)
}
cmd := exec.Command("/usr/bin/docker", args...)
2015-09-04 09:28:10 +02:00
if os.Getenv("DOCKER_LAUNCH_DEBUG") == "true" {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
} else {
cmd.Stdout = ioutil.Discard
cmd.Stderr = ioutil.Discard
}
2015-05-15 08:20:26 +02:00
trace(cmd)
2015-05-15 07:12:50 +02:00
cmd.Run()
}()
// ping Docker until available
for i := 0; i < 3; i++ {
cmd := exec.Command("/usr/bin/docker", "info")
cmd.Stdout = ioutil.Discard
cmd.Stderr = ioutil.Discard
err := cmd.Run()
if err == nil {
break
}
time.Sleep(time.Second * 5)
2015-05-15 07:12:50 +02:00
}
2015-05-15 18:56:27 +02:00
// Login to Docker
2015-09-03 07:14:57 +02:00
if len(vargs.Username) != 0 {
cmd := exec.Command("/usr/bin/docker", "login", "-u", vargs.Username, "-p", vargs.Password, "-e", vargs.Email, vargs.Registry)
2015-09-03 07:14:57 +02:00
cmd.Dir = workspace.Path
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
2015-09-04 22:01:18 +02:00
fmt.Println("Login failed.")
2015-09-03 07:14:57 +02:00
os.Exit(1)
}
} else {
fmt.Printf("A username was not specified. Assuming anoynmous publishing.\n")
2015-05-15 07:12:50 +02:00
}
2015-05-16 02:18:07 +02:00
// Docker environment info
cmd := exec.Command("/usr/bin/docker", "version")
2015-05-16 02:18:07 +02:00
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
trace(cmd)
cmd.Run()
cmd = exec.Command("/usr/bin/docker", "info")
2015-05-16 02:18:07 +02:00
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
trace(cmd)
cmd.Run()
// Load archived image if exists
if len(vargs.Archive.File) != 0 {
if _, err := os.Stat(vargs.Archive.File); err != nil {
fmt.Printf("Archive %s does not exist. Building from scratch.\n", vargs.Archive.File)
} else {
cmd := exec.Command("/usr/bin/docker", "load", "-i", vargs.Archive.File)
cmd.Dir = workspace.Path
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
trace(cmd)
err := cmd.Run()
if err != nil {
os.Exit(1)
}
}
}
2015-05-15 18:56:27 +02:00
// Build the container
2015-10-28 01:53:51 +01:00
name := fmt.Sprintf("%s:%s", vargs.Repo, vargs.Tag.Slice()[0])
cmd = exec.Command("/usr/bin/docker", "build", "--pull=true", "--rm=true", "-f", vargs.File, "-t", name, vargs.Context)
2015-09-03 00:30:42 +02:00
cmd.Dir = workspace.Path
2015-05-15 07:12:50 +02:00
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
2015-05-15 18:56:27 +02:00
trace(cmd)
2015-09-03 07:14:57 +02:00
err := cmd.Run()
2015-05-15 07:12:50 +02:00
if err != nil {
os.Exit(1)
}
2015-10-28 01:53:51 +01:00
// Creates image tags
for _, tag := range vargs.Tag.Slice()[1:] {
name_ := fmt.Sprintf("%s:%s", vargs.Repo, tag)
cmd = exec.Command("/usr/bin/docker", "tag", name, name_)
cmd.Dir = workspace.Path
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
trace(cmd)
err = cmd.Run()
if err != nil {
os.Exit(1)
}
2015-05-15 07:12:50 +02:00
}
2015-10-28 01:53:51 +01:00
// Push the image and tags to the registry
for _, tag := range vargs.Tag.Slice() {
name_ := fmt.Sprintf("%s:%s", vargs.Repo, tag)
cmd = exec.Command("/usr/bin/docker", "push", name_)
cmd.Dir = workspace.Path
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
trace(cmd)
err = cmd.Run()
if err != nil {
os.Exit(1)
}
}
// Save the image to the archive
if len(vargs.Archive.File) != 0 {
// if the path's directory does not exist, create it
dir := filepath.Dir(vargs.Archive.File)
os.MkdirAll(dir, 0755)
cmd = exec.Command("/usr/bin/docker", "save", "-o", vargs.Archive.File)
// Limit save command to the given tag(s)
if vargs.Archive.Tag.Len() != 0 {
for _, tag := range vargs.Archive.Tag.Slice() {
name_ := fmt.Sprintf("%s:%s", vargs.Repo, tag)
cmd.Args = append(cmd.Args, name_)
}
} else {
cmd.Args = append(cmd.Args, vargs.Repo)
}
cmd.Dir = workspace.Path
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
trace(cmd)
err := cmd.Run()
if err != nil {
os.Exit(1)
}
}
2015-05-15 07:12:50 +02:00
}
// Trace writes each command to standard error (preceded by a $ ) before it
// is executed. Used for debugging your build.
func trace(cmd *exec.Cmd) {
fmt.Println("$", strings.Join(cmd.Args, " "))
}
2015-05-16 02:18:07 +02:00
// authorize is a helper function that authorizes the Docker client
// by manually creating the Docker authentication file.
func authorize(d *Docker) error {
var path = "/root/.dockercfg" // TODO should probably use user.Home() for good measure
var data = fmt.Sprintf(dockerconf, d.Registry, d.Auth, d.Email)
return ioutil.WriteFile(path, []byte(data), 0644)
}
var dockerconf = `
{
"%s": {
"auth": "%s",
"email": "%s"
}
}
`