From 3e003391ae07d2c02fe2fd7cdd2bb81204a52610 Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Tue, 22 Oct 2019 16:00:56 -0700 Subject: [PATCH] ping docker daemon on startup [ci skip] --- command/daemon/daemon.go | 37 ++++++++++++++++++++++++++----------- engine/engine_impl.go | 29 ++++++++++++++++++----------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/command/daemon/daemon.go b/command/daemon/daemon.go index 91ad6f8..fcff330 100644 --- a/command/daemon/daemon.go +++ b/command/daemon/daemon.go @@ -51,6 +51,16 @@ func (c *daemonCommand) run(*kingpin.ParseContext) error { // setup the global logrus logger. setupLogger(config) + ctx, cancel := context.WithCancel(nocontext) + defer cancel() + + // listen for termination signals to gracefully shutdown + // the runner daemon. + ctx = signal.WithContextFunc(ctx, func() { + println("received signal, terminating process") + cancel() + }) + cli := client.New( config.Client.Address, config.Client.Secret, @@ -69,7 +79,22 @@ func (c *daemonCommand) run(*kingpin.ParseContext) error { engine, err := engine.NewEnv() if err != nil { - return err + logrus.WithError(err). + Fatalln("cannot load the docker engine") + } + for { + err := engine.Ping(ctx) + if err == context.Canceled { + break + } + if err != nil { + logrus.WithError(err). + Errorln("cannot ping the docker daemon") + time.Sleep(time.Second) + } else { + logrus.Debugln("successfully pinged the docker daemon") + break + } } remote := remote.New(cli) @@ -117,16 +142,6 @@ func (c *daemonCommand) run(*kingpin.ParseContext) error { }, } - ctx, cancel := context.WithCancel(nocontext) - defer cancel() - - // listen for termination signals to gracefully shutdown - // the runner daemon. - ctx = signal.WithContextFunc(ctx, func() { - println("received signal, terminating process") - cancel() - }) - var g errgroup.Group server := server.Server{ Addr: config.Server.Port, diff --git a/engine/engine_impl.go b/engine/engine_impl.go index 8298553..e8e8628 100644 --- a/engine/engine_impl.go +++ b/engine/engine_impl.go @@ -17,17 +17,18 @@ import ( "docker.io/go-docker/api/types/volume" ) -type engine struct { +// Docker implements a Docker pipeline engine. +type Docker struct { client docker.APIClient } // New returns a new engine. -func New(client docker.APIClient) Engine { - return &engine{client} +func New(client docker.APIClient) *Docker { + return &Docker{client} } // NewEnv returns a new Engine from the environment. -func NewEnv() (Engine, error) { +func NewEnv() (*Docker, error) { cli, err := docker.NewEnvClient() if err != nil { return nil, err @@ -35,8 +36,14 @@ func NewEnv() (Engine, error) { return New(cli), nil } +// Ping pings the Docker daemon. +func (e *Docker) Ping(ctx context.Context) error { + _, err := e.client.Ping(ctx) + return err +} + // Setup the pipeline environment. -func (e *engine) Setup(ctx context.Context, spec *Spec) error { +func (e *Docker) Setup(ctx context.Context, spec *Spec) error { // creates the default temporary (local) volumes // that are mounted into each container step. for _, vol := range spec.Volumes { @@ -68,7 +75,7 @@ func (e *engine) Setup(ctx context.Context, spec *Spec) error { } // Destroy the pipeline environment. -func (e *engine) Destroy(ctx context.Context, spec *Spec) error { +func (e *Docker) Destroy(ctx context.Context, spec *Spec) error { removeOpts := types.ContainerRemoveOptions{ Force: true, RemoveLinks: false, @@ -109,7 +116,7 @@ func (e *engine) Destroy(ctx context.Context, spec *Spec) error { } // Run runs the pipeline step. -func (e *engine) Run(ctx context.Context, spec *Spec, step *Step, output io.Writer) (*State, error) { +func (e *Docker) Run(ctx context.Context, spec *Spec, step *Step, output io.Writer) (*State, error) { // create the container err := e.create(ctx, spec, step, output) if err != nil { @@ -133,7 +140,7 @@ func (e *engine) Run(ctx context.Context, spec *Spec, step *Step, output io.Writ // emulate docker commands // -func (e *engine) create(ctx context.Context, spec *Spec, step *Step, output io.Writer) error { +func (e *Docker) create(ctx context.Context, spec *Spec, step *Step, output io.Writer) error { // parse the docker image name. We need to extract the // image domain name and match to registry credentials // stored in the .docker/config.json object. @@ -212,13 +219,13 @@ func (e *engine) create(ctx context.Context, spec *Spec, step *Step, output io.W } // helper function emulates the `docker start` command. -func (e *engine) start(ctx context.Context, id string) error { +func (e *Docker) start(ctx context.Context, id string) error { return e.client.ContainerStart(ctx, id, types.ContainerStartOptions{}) } // helper function emulates the `docker wait` command, blocking // until the container stops and returning the exit code. -func (e *engine) wait(ctx context.Context, id string) (*State, error) { +func (e *Docker) wait(ctx context.Context, id string) (*State, error) { wait, errc := e.client.ContainerWait(ctx, id, "") select { case <-wait: @@ -243,7 +250,7 @@ func (e *engine) wait(ctx context.Context, id string) (*State, error) { // helper function emulates the `docker logs -f` command, streaming // all container logs until the container stops. -func (e *engine) tail(ctx context.Context, id string, output io.Writer) error { +func (e *Docker) tail(ctx context.Context, id string, output io.Writer) error { opts := types.ContainerLogsOptions{ Follow: true, ShowStdout: true,