1
0
mirror of https://github.com/drone/drone-cli.git synced 2026-01-17 08:21:34 +01:00
drone-cli/drone/exec.go
2015-11-09 15:10:49 -08:00

253 lines
5.2 KiB
Go

package main
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/codegangsta/cli"
"github.com/drone/drone-exec/docker"
"github.com/drone/drone-go/drone"
"github.com/drone/drone/yaml/matrix"
"github.com/fatih/color"
"github.com/samalba/dockerclient"
)
var ExecCmd = cli.Command{
Name: "exec",
Usage: "executes a local build",
Action: func(c *cli.Context) {
if err := execCmd(c); err != nil {
fmt.Println(err)
os.Exit(1)
}
},
Flags: []cli.Flag{
cli.StringFlag{
EnvVar: "DOCKER_HOST",
Name: "docker-host",
Usage: "docker deamon address",
Value: "unix:///var/run/docker.sock",
},
cli.BoolFlag{
EnvVar: "DOCKER_TLS_VERIFY",
Name: "docker-tls-verify",
Usage: "docker daemon supports tlsverify",
},
cli.StringFlag{
EnvVar: "DOCKER_CERT_PATH",
Name: "docker-cert-path",
Usage: "docker certificate directory",
Value: "",
},
cli.StringFlag{
Name: "i",
Value: "",
Usage: "identify file injected in the container",
},
cli.BoolFlag{
Name: "trusted",
Usage: "enable elevated privilege",
},
cli.BoolFlag{
Name: "cache",
Usage: "execute cache steps",
},
cli.BoolFlag{
Name: "deploy",
Usage: "execute publish and deployment steps",
},
cli.BoolFlag{
Name: "notify",
Usage: "execute notification steps",
},
cli.BoolFlag{
Name: "pull",
Usage: "always pull the latest docker image",
},
cli.BoolTFlag{
Name: "debug",
Usage: "execute the build in debug mode",
},
},
}
func execCmd(c *cli.Context) error {
cert, _ := ioutil.ReadFile(filepath.Join(
c.String("docker-cert-path"),
"cert.pem",
))
key, _ := ioutil.ReadFile(filepath.Join(
c.String("docker-cert-path"),
"key.pem",
))
ca, _ := ioutil.ReadFile(filepath.Join(
c.String("docker-cert-path"),
"ca.pem",
))
if len(cert) == 0 || len(key) == 0 || len(ca) == 0 {
println("")
}
yml, err := ioutil.ReadFile(".drone.yml")
if err != nil {
return err
}
axes, err := matrix.Parse(string(yml))
if err != nil {
return err
}
if len(axes) == 0 {
axes = append(axes, matrix.Axis{})
}
cli, err := newDockerClient(c.String("docker-host"), cert, key, ca)
if err != nil {
return err
}
pwd, err := os.Getwd()
if err != nil {
return err
}
proj := resolvePath(pwd)
var exits []int
for i, axis := range axes {
color.Magenta("[DRONE] starting job #%d", i+1)
if len(axis) != 0 {
color.Magenta("[DRONE] export %s", axis)
}
payload := struct {
System drone.System `json:"system"`
Workspace drone.Workspace `json:"workspace"`
Repo drone.Repo `json:"repo"`
Build drone.Build `json:"build"`
Job drone.Job `json:"job"`
Config string `json:"config"`
}{
Repo: drone.Repo{
IsTrusted: c.Bool("trusted"),
IsPrivate: true,
},
Job: drone.Job{
Status: drone.StatusRunning,
Environment: axis,
},
Config: string(yml),
Build: drone.Build{
Status: drone.StatusRunning,
Commit: "0000000000", // hack
},
System: drone.System{
Globals: []string{},
Plugins: []string{"plugins/*", "*/*"},
},
}
// gets the ssh key if provided
if len(c.String("i")) != 0 {
key, err = ioutil.ReadFile(c.String("i"))
if err != nil {
return err
}
payload.Workspace.Keys = &drone.Key{
Private: string(key),
}
}
if len(proj) != 0 {
payload.Repo.Link = fmt.Sprintf("https://%s", proj)
}
out, _ := json.Marshal(payload)
exit, err := run(cli, pwd, string(out))
if err != nil {
return err
}
exits = append(exits, exit)
color.Magenta("[DRONE] finished job #%d", i+1)
color.Magenta("[DRONE] exit code %d", exit)
}
var passed = true
for i, _ := range axes {
exit := exits[i]
if exit == 0 {
color.Green("[DRONE] job #%d passed", i+1)
} else {
color.Red("[DRONE] job #%d failed", i+1)
passed = false
}
}
if passed {
color.Green("[DRONE] build passed")
} else {
color.Red("[DRONE] build failed")
os.Exit(1)
}
return nil
}
func run(client dockerclient.Client, mount, input string) (int, error) {
image := "drone/drone-exec:latest"
entrypoint := []string{"/bin/drone-exec"}
args := []string{"--build", "--debug", "--mount", mount, "--", input}
conf := &dockerclient.ContainerConfig{
Image: image,
Entrypoint: entrypoint,
Cmd: args,
HostConfig: dockerclient.HostConfig{
Binds: []string{"/var/run/docker.sock:/var/run/docker.sock"},
},
Volumes: map[string]struct{}{
"/var/run/docker.sock": struct{}{},
},
}
info, err := docker.Run(client, conf, false)
client.StopContainer(info.Id, 15)
client.RemoveContainer(info.Id, true, true)
return info.State.ExitCode, err
}
func newDockerClient(addr string, cert, key, ca []byte) (dockerclient.Client, error) {
var tlc *tls.Config
if len(cert) != 0 {
pem, err := tls.X509KeyPair(cert, key)
if err != nil {
return dockerclient.NewDockerClient(addr, nil)
}
tlc = &tls.Config{}
tlc.Certificates = []tls.Certificate{pem}
if len(ca) != 0 {
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(ca)
tlc.RootCAs = pool
} else {
tlc.InsecureSkipVerify = true
}
}
return dockerclient.NewDockerClient(addr, tlc)
}