support for image pull logs
This commit is contained in:
@@ -87,6 +87,7 @@ type Config struct {
|
|||||||
|
|
||||||
Docker struct {
|
Docker struct {
|
||||||
Config string `envconfig:"DRONE_DOCKER_CONFIG"`
|
Config string `envconfig:"DRONE_DOCKER_CONFIG"`
|
||||||
|
Stream bool `envconfig:"DRONE_DOCKER_STREAM_PULL" default:"true"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,10 @@ func (c *daemonCommand) run(*kingpin.ParseContext) error {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
engine, err := engine.NewEnv()
|
opts := engine.Opts{
|
||||||
|
HidePull: !config.Docker.Stream,
|
||||||
|
}
|
||||||
|
engine, err := engine.NewEnv(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).
|
logrus.WithError(err).
|
||||||
Fatalln("cannot load the docker engine")
|
Fatalln("cannot load the docker engine")
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ func (c *execCommand) run(*kingpin.ParseContext) error {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
engine, err := engine.NewEnv()
|
engine, err := engine.NewEnv(engine.Opts{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,6 +266,7 @@ func (c *Compiler) Compile(ctx context.Context, args Args) *engine.Spec {
|
|||||||
step.Envs = environ.Combine(envs, step.Envs)
|
step.Envs = environ.Combine(envs, step.Envs)
|
||||||
step.WorkingDir = full
|
step.WorkingDir = full
|
||||||
step.Labels = labels
|
step.Labels = labels
|
||||||
|
step.Pull = engine.PullIfNotExists
|
||||||
step.Volumes = append(step.Volumes, mount)
|
step.Volumes = append(step.Volumes, mount)
|
||||||
spec.Steps = append(spec.Steps, step)
|
spec.Steps = append(spec.Steps, step)
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/drone-runners/drone-runner-docker/internal/docker/image"
|
"github.com/drone-runners/drone-runner-docker/internal/docker/image"
|
||||||
|
"github.com/drone-runners/drone-runner-docker/internal/docker/jsonmessage"
|
||||||
"github.com/drone-runners/drone-runner-docker/internal/docker/stdcopy"
|
"github.com/drone-runners/drone-runner-docker/internal/docker/stdcopy"
|
||||||
"github.com/drone/runner-go/registry/auths"
|
"github.com/drone/runner-go/registry/auths"
|
||||||
|
|
||||||
@@ -18,23 +19,32 @@ import (
|
|||||||
"docker.io/go-docker/api/types/volume"
|
"docker.io/go-docker/api/types/volume"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Opts configures the Docker engine.
|
||||||
|
type Opts struct {
|
||||||
|
HidePull bool
|
||||||
|
}
|
||||||
|
|
||||||
// Docker implements a Docker pipeline engine.
|
// Docker implements a Docker pipeline engine.
|
||||||
type Docker struct {
|
type Docker struct {
|
||||||
client docker.APIClient
|
client docker.APIClient
|
||||||
|
hidePull bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new engine.
|
// New returns a new engine.
|
||||||
func New(client docker.APIClient) *Docker {
|
func New(client docker.APIClient, opts Opts) *Docker {
|
||||||
return &Docker{client}
|
return &Docker{
|
||||||
|
client: client,
|
||||||
|
hidePull: opts.HidePull,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEnv returns a new Engine from the environment.
|
// NewEnv returns a new Engine from the environment.
|
||||||
func NewEnv() (*Docker, error) {
|
func NewEnv(opts Opts) (*Docker, error) {
|
||||||
cli, err := docker.NewEnvClient()
|
cli, err := docker.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return New(cli), nil
|
return New(cli, opts), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ping pings the Docker daemon.
|
// Ping pings the Docker daemon.
|
||||||
@@ -157,7 +167,11 @@ func (e *Docker) create(ctx context.Context, spec *Spec, step *Step, output io.W
|
|||||||
(step.Pull == PullDefault && image.IsLatest(step.Image)) {
|
(step.Pull == PullDefault && image.IsLatest(step.Image)) {
|
||||||
rc, pullerr := e.client.ImagePull(ctx, step.Image, pullopts)
|
rc, pullerr := e.client.ImagePull(ctx, step.Image, pullopts)
|
||||||
if pullerr == nil {
|
if pullerr == nil {
|
||||||
io.Copy(ioutil.Discard, rc)
|
if e.hidePull {
|
||||||
|
io.Copy(ioutil.Discard, rc)
|
||||||
|
} else {
|
||||||
|
jsonmessage.Copy(rc, output)
|
||||||
|
}
|
||||||
rc.Close()
|
rc.Close()
|
||||||
}
|
}
|
||||||
if pullerr != nil {
|
if pullerr != nil {
|
||||||
@@ -179,7 +193,12 @@ func (e *Docker) create(ctx context.Context, spec *Spec, step *Step, output io.W
|
|||||||
if pullerr != nil {
|
if pullerr != nil {
|
||||||
return pullerr
|
return pullerr
|
||||||
}
|
}
|
||||||
io.Copy(ioutil.Discard, rc)
|
|
||||||
|
if e.hidePull {
|
||||||
|
io.Copy(ioutil.Discard, rc)
|
||||||
|
} else {
|
||||||
|
jsonmessage.Copy(rc, output)
|
||||||
|
}
|
||||||
rc.Close()
|
rc.Close()
|
||||||
|
|
||||||
// once the image is successfully pulled we attempt to
|
// once the image is successfully pulled we attempt to
|
||||||
|
|||||||
61
internal/docker/jsonmessage/jsonmessage.go
Normal file
61
internal/docker/jsonmessage/jsonmessage.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Polyform License
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package jsonmessage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jsonError struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *jsonError) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonMessage struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Error *jsonError `json:"errorDetail"`
|
||||||
|
Progress *jsonProgress `json:"progressDetail"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonProgress struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy copies a json message string to the io.Writer.
|
||||||
|
func Copy(in io.Reader, out io.Writer) error {
|
||||||
|
dec := json.NewDecoder(in)
|
||||||
|
for {
|
||||||
|
var jm jsonMessage
|
||||||
|
if err := dec.Decode(&jm); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if jm.Error != nil {
|
||||||
|
if jm.Error.Code == 401 {
|
||||||
|
return fmt.Errorf("authentication is required")
|
||||||
|
}
|
||||||
|
return jm.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if jm.Progress != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if jm.ID == "" {
|
||||||
|
fmt.Fprintf(out, "%s\n", jm.Status)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s: %s\n", jm.ID, jm.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
12
internal/docker/jsonmessage/testdata/alpine.json
vendored
Normal file
12
internal/docker/jsonmessage/testdata/alpine.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{"status":"Pulling from library/alpine","id":"3.6"}
|
||||||
|
{"status":"Pulling fs layer","progressDetail":{},"id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Downloading","progressDetail":{"current":21019,"total":2017774},"progress":"[\u003e ] 21.02kB/2.018MB","id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Downloading","progressDetail":{"current":1194721,"total":2017774},"progress":"[=============================\u003e ] 1.195MB/2.018MB","id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Verifying Checksum","progressDetail":{},"id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Download complete","progressDetail":{},"id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Extracting","progressDetail":{"current":32768,"total":2017774},"progress":"[\u003e ] 32.77kB/2.018MB","id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Extracting","progressDetail":{"current":786432,"total":2017774},"progress":"[===================\u003e ] 786.4kB/2.018MB","id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Extracting","progressDetail":{"current":2017774,"total":2017774},"progress":"[==================================================\u003e] 2.018MB/2.018MB","id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Pull complete","progressDetail":{},"id":"5a3ea8efae5d"}
|
||||||
|
{"status":"Digest: sha256:66790a2b79e1ea3e1dabac43990c54aca5d1ddf268d9a5a0285e4167c8b24475"}
|
||||||
|
{"status":"Status: Downloaded newer image for alpine:3.6"}
|
||||||
Reference in New Issue
Block a user