Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1198 from hashicorp/feature/registry-aware
Browse files Browse the repository at this point in the history
Expose `HasRegistry` bool to builder plugins, Docker doesn't pull if it doesn't have to
  • Loading branch information
mitchellh authored Mar 18, 2021
2 parents 463e39b + ea89721 commit eef49a9
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .changelog/1198.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
plugin/docker-pull: doesn't require Docker if no registry is configured and entrypoint injection is disabled
```
4 changes: 3 additions & 1 deletion builtin/docker/plugin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ message Image {
// If this is not set, it will be assumed that the image is in a local
// Docker daemon registry for backwards compatiblity reasons.
oneof location {
// registry is set if the image is in a remote registry.
// registry is set if the image is in a remote registry. This value
// might mean the image is local, too, but we never formally "pulled"
// it so we aren't sure. The image should be treated as remote.
google.protobuf.Empty registry = 3;

// docker is set if the image is in a local Docker daemon registry.
Expand Down
49 changes: 40 additions & 9 deletions builtin/docker/pull/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import (
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/registry"
"github.com/golang/protobuf/ptypes/empty"
"github.com/hashicorp/go-argmapper"
"github.com/hashicorp/go-hclog"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/hashicorp/waypoint-plugin-sdk/component"
"github.com/hashicorp/waypoint-plugin-sdk/docs"
"github.com/hashicorp/waypoint-plugin-sdk/terminal"
wpdocker "github.com/hashicorp/waypoint/builtin/docker"
Expand Down Expand Up @@ -58,7 +58,7 @@ func (b *Builder) Documentation() (*docs.Documentation, error) {
}

doc.Description(`
Use an existing, pre-built Docker image
Use an existing, pre-built Docker image.
This builder will automatically inject the Waypoint entrypoint. You
can disable this with the "disable_entrypoint" configuration.
Expand All @@ -69,6 +69,11 @@ push it to the specified registry.
If Docker isn't available (the Docker daemon isn't running or a DOCKER_HOST
isn't set), a daemonless solution will be used instead.
If "disable_entrypoint" is set to true and the Waypoint configuration
has no registry, this builder will not physically pull the image. This enables
Waypoint to work in environments where the image is built outside of Waypoint
(such as in a CI pipeline).
`)

doc.Example(`
Expand Down Expand Up @@ -125,16 +130,28 @@ func (b *Builder) Config() (interface{}, error) {
return &b.config, nil
}

// We use the struct form of arguments so that we can access named
// values (such as "HasRegistry").
type buildArgs struct {
argmapper.Struct

Ctx context.Context
UI terminal.UI
Log hclog.Logger
HasRegistry bool
}

// Build
func (b *Builder) Build(
ctx context.Context,
ui terminal.UI,
src *component.Source,
log hclog.Logger,
) (*wpdocker.Image, error) {
func (b *Builder) Build(args buildArgs) (*wpdocker.Image, error) {
// Pull all the args out to top-level values. This is mostly done
// cause the struct was added later, but also because these are very common.
ctx := args.Ctx
ui := args.UI
log := args.Log

sg := ui.StepGroup()
defer sg.Wait()
step := sg.Add("Initializing Docker client...")
step := sg.Add("")
defer func() {
if step != nil {
step.Abort()
Expand All @@ -147,6 +164,20 @@ func (b *Builder) Build(
Location: &wpdocker.Image_Docker{Docker: &empty.Empty{}},
}

// If we aren't injected the entrypoint AND we don't have a registry
// defined, then we don't pull the image at all. We do this so that
// Waypoint can work in an environment where Docker doesn't exist, img
// doesn't work, and we're just using an image reference that was built
// outside of Waypoint.
if b.config.DisableCEB && !args.HasRegistry {
step.Update("Using Docker image in remote registry: %s", result.Name())
step.Done()

result.Location = &wpdocker.Image_Registry{Registry: &empty.Empty{}}
return result, nil
}

step.Update("Initializing Docker client...")
cli, err := wpdockerclient.NewClientWithOpts(client.FromEnv)
if err != nil {
return nil, status.Errorf(codes.FailedPrecondition, "unable to create Docker client: %s", err)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ require (
github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f
github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210217205040-c3ed2e9c4f02
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210318220236-523ecf021e01
github.com/imdario/mergo v0.3.11
github.com/improbable-eng/grpc-web v0.13.0
github.com/kevinburke/go-bindata v3.22.0+incompatible
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -753,8 +753,8 @@ github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef h1:YKouRHFf
github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef/go.mod h1:cAGI4nVnEfAyMeqt9oB+Mase8DNn3qA/LDNHURiwssY=
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9 h1:i9hzlv2SpmaNcQ8ZLGn01fp2Gqyejj0juVs7rYDgecE=
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9/go.mod h1:ObgQSWSX9rsNofh16kctm6XxLW2QW1Ay6/9ris6T6DU=
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210217205040-c3ed2e9c4f02 h1:f+50LLKCEvzEGSIGaJiZPdd3mXWOe5obHQ0bF4UJcO4=
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210217205040-c3ed2e9c4f02/go.mod h1:+T5ugu6Dxv3uSe3EM5xBQ7u4Y1Em6zhHC0KTutBst84=
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210318220236-523ecf021e01 h1:r4kQvzaDIzjuQBdE7ZQE0c468WRxKtNu6qqw2G48lr8=
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210318220236-523ecf021e01/go.mod h1:+T5ugu6Dxv3uSe3EM5xBQ7u4Y1Em6zhHC0KTutBst84=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20190923154419-df201c70410d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
Expand Down
7 changes: 6 additions & 1 deletion internal/core/app_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes/any"
"github.com/hashicorp/go-argmapper"
"github.com/hashicorp/go-hclog"

"github.com/hashicorp/waypoint-plugin-sdk/component"
Expand Down Expand Up @@ -33,7 +34,8 @@ func (a *App) Build(ctx context.Context, optFuncs ...BuildOption) (

// First we do the build
_, msg, err := a.doOperation(ctx, a.logger.Named("build"), &buildOperation{
Component: c,
Component: c,
HasRegistry: a.config.RegistryUse() != "",
})
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -91,6 +93,8 @@ func (opts *buildOptions) Validate() error {
type buildOperation struct {
Component *Component
Build *pb.Build

HasRegistry bool
}

func (op *buildOperation) Init(app *App) (proto.Message, error) {
Expand Down Expand Up @@ -130,6 +134,7 @@ func (op *buildOperation) Do(ctx context.Context, log hclog.Logger, app *App, _
(*component.Artifact)(nil),
op.Component,
op.Component.Value.(component.Builder).BuildFunc(),
argmapper.Named("HasRegistry", op.HasRegistry),
)
}

Expand Down
114 changes: 114 additions & 0 deletions internal/core/app_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"testing"

"github.com/hashicorp/go-argmapper"
"github.com/stretchr/testify/require"

"github.com/hashicorp/waypoint-plugin-sdk/component"
Expand Down Expand Up @@ -47,6 +48,101 @@ func TestAppBuild_happy(t *testing.T) {
}
}

// Test that we have an argument that lets us know there is a registry.
func TestAppBuild_hasRegistry(t *testing.T) {
t.Run("with registry", func(t *testing.T) {
require := require.New(t)

// Make our factory for platforms
mock := &componentmocks.Builder{}
factory := TestFactory(t, component.BuilderType)
TestFactoryRegister(t, factory, "test", mock)

// Make our app
app := TestApp(t, TestProject(t,
WithConfig(config.TestConfig(t, testBuildConfigWithRegistry)),
WithFactory(component.BuilderType, factory),
WithJobInfo(&component.JobInfo{Id: "hello"}),
), "test")

// Setup our value
var actualVal *bool
artifact := &componentmocks.Artifact{}
artifact.On("Labels").Return(map[string]string{"foo": "foo"})
mock.On("BuildFunc").Return(func(args struct {
argmapper.Struct

HasRegistry bool
}) component.Artifact {
actualVal = &args.HasRegistry
return artifact
})

{
// Build
build, _, err := app.Build(context.Background(), BuildWithPush(false))
require.NoError(err)

// Verify that we set the status properly
require.Equal("foo", build.Labels["foo"])
require.Contains(build.Labels, "waypoint/workspace")

// Verify we have the ID set
require.Equal("hello", build.JobId)

// Verify that we DID have a registry set
require.NotNil(actualVal)
require.True(*actualVal)
}
})

t.Run("with no registry", func(t *testing.T) {
require := require.New(t)

// Make our factory for platforms
mock := &componentmocks.Builder{}
factory := TestFactory(t, component.BuilderType)
TestFactoryRegister(t, factory, "test", mock)

// Make our app
app := TestApp(t, TestProject(t,
WithConfig(config.TestConfig(t, testBuildConfig)),
WithFactory(component.BuilderType, factory),
WithJobInfo(&component.JobInfo{Id: "hello"}),
), "test")

// Setup our value
var actualVal *bool
artifact := &componentmocks.Artifact{}
artifact.On("Labels").Return(map[string]string{"foo": "foo"})
mock.On("BuildFunc").Return(func(args struct {
argmapper.Struct

HasRegistry bool
}) component.Artifact {
actualVal = &args.HasRegistry
return artifact
})

{
// Build
build, _, err := app.Build(context.Background(), BuildWithPush(false))
require.NoError(err)

// Verify that we set the status properly
require.Equal("foo", build.Labels["foo"])
require.Contains(build.Labels, "waypoint/workspace")

// Verify we have the ID set
require.Equal("hello", build.JobId)

// Verify that we DID have a registry set
require.NotNil(actualVal)
require.False(*actualVal)
}
})
}

const testBuildConfig = `
project = "test"
Expand All @@ -60,3 +156,21 @@ app "test" {
}
}
`

const testBuildConfigWithRegistry = `
project = "test"
app "test" {
build {
use "test" {}
registry {
use "foo" {}
}
}
deploy {
use "test" {}
}
}
`

0 comments on commit eef49a9

Please sign in to comment.