Skip to content

Commit

Permalink
Defer to builder run image mirror if not publishing (daemon case)
Browse files Browse the repository at this point in the history
* Refactor and add to Build tests

Signed-off-by: David Freilich <[email protected]>
  • Loading branch information
dfreilich committed Aug 10, 2020
1 parent 3a3bf28 commit f1097a4
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 54 deletions.
2 changes: 1 addition & 1 deletion build.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error {
return errors.Wrapf(err, "invalid builder '%s'", opts.Builder)
}

runImageName := c.resolveRunImage(opts.RunImage, imageRef.Context().RegistryStr(), bldr.Stack(), opts.AdditionalMirrors)
runImageName := c.resolveRunImage(opts.RunImage, imageRef.Context().RegistryStr(), builderRef.Context().RegistryStr(), bldr.Stack(), opts.AdditionalMirrors, opts.Publish)
runImage, err := c.validateRunImage(ctx, runImageName, opts.NoPull, opts.Publish, bldr.StackID)
if err != nil {
return errors.Wrapf(err, "invalid run-image '%s'", runImageName)
Expand Down
116 changes: 66 additions & 50 deletions build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,35 +407,53 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {

when("run image is not supplied", func() {
when("there are no locally configured mirrors", func() {
it("chooses the best mirror from the builder", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "some/app",
Builder: defaultBuilderName,
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "default/run")
})
when("Publish is true", func() {
it("chooses the run image mirror matching the local image", func() {
fakeImageFetcher.RemoteImages[fakeDefaultRunImage.Name()] = fakeDefaultRunImage

it("chooses the best mirror from the builder", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "registry1.example.com/some/app",
Builder: defaultBuilderName,
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "registry1.example.com/run/mirror")
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "some/app",
Builder: defaultBuilderName,
Publish: true,
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "default/run")
})

for _, registry := range []string{"registry1.example.com", "registry2.example.com"} {
it("chooses the run image mirror matching the built image", func() {
fakeImageFetcher.RemoteImages[registry+"/run/mirror"] = fakeDefaultRunImage
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: registry + "/some/app",
Builder: defaultBuilderName,
Publish: true,
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, registry+"/run/mirror")
})
}
})

it("chooses the best mirror from the builder", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "registry2.example.com/some/app",
Builder: defaultBuilderName,
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "registry2.example.com/run/mirror")
when("Publish is false", func() {
for _, img := range []string{"some/app",
"registry1.example.com/some/app",
"registry2.example.com/some/app"} {
it("chooses a mirror on the builder registry", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: img,
Builder: defaultBuilderName,
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "default/run")
})
}
})
})

when("there are locally configured mirrors", func() {
var (
fakeLocalMirror *fakes.Image
fakeLocalMirror1 *fakes.Image
mirrors = map[string][]string{
"default/run": {"local/mirror", "registry1.example.com/local/mirror"},
}
)

it.Before(func() {
Expand All @@ -457,39 +475,37 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {
fakeLocalMirror1.Cleanup()
})

it("prefers user provided mirrors", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "some/app",
Builder: defaultBuilderName,
AdditionalMirrors: map[string][]string{
"default/run": {"local/mirror", "registry1.example.com/local/mirror"},
},
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "local/mirror")
})

it("choose the correct user provided mirror for the registry", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "registry1.example.com/some/app",
Builder: defaultBuilderName,
AdditionalMirrors: map[string][]string{
"default/run": {"local/mirror", "registry1.example.com/local/mirror"},
},
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "registry1.example.com/local/mirror")
when("Publish is true", func() {
for _, registry := range []string{"", "registry1.example.com"} {
it("prefers user provided mirrors for registry "+registry, func() {
localMirror := "local/mirror"
if registry != "" {
registry = registry + "/"
}
fakeImageFetcher.RemoteImages[registry+localMirror] = fakeDefaultRunImage

h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: registry + "some/app",
Builder: defaultBuilderName,
AdditionalMirrors: mirrors,
Publish: true,
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, registry+localMirror)
})
}
})

when("there is no user provided mirror for the registry", func() {
it("chooses from builder mirrors", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "registry2.example.com/some/app",
Builder: defaultBuilderName,
AdditionalMirrors: map[string][]string{
"default/run": {"local/mirror", "registry1.example.com/local/mirror"},
},
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "registry2.example.com/run/mirror")
})
when("Publish is false", func() {
for _, registry := range []string{"", "registry1.example.com", "registry2.example.com"} {
it("prefers user provided mirrors", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: registry + "some/app",
Builder: defaultBuilderName,
AdditionalMirrors: mirrors,
}))
h.AssertEq(t, fakeLifecycle.Opts.RunImage, "local/mirror")
})
}
})
})
})
Expand Down
10 changes: 8 additions & 2 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@ func (c *Client) parseTagReference(imageName string) (name.Reference, error) {
return ref, nil
}

func (c *Client) resolveRunImage(runImage, targetRegistry string, stackInfo builder.StackMetadata, additionalMirrors map[string][]string) string {
func (c *Client) resolveRunImage(runImage, imgRegistry, bldrRegistry string, stackInfo builder.StackMetadata, additionalMirrors map[string][]string, publish bool) string {
if runImage != "" {
c.logger.Debugf("Using provided run-image %s", style.Symbol(runImage))
return runImage
}

preferredRegistry := bldrRegistry
if publish || bldrRegistry == "" {
preferredRegistry = imgRegistry
}

runImageName := getBestRunMirror(
targetRegistry,
preferredRegistry,
stackInfo.RunImage.Image,
stackInfo.RunImage.Mirrors,
additionalMirrors[stackInfo.RunImage.Image],
Expand Down
119 changes: 119 additions & 0 deletions common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package pack

import (
"bytes"
"testing"

"github.com/heroku/color"
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"

"github.com/buildpacks/pack/internal/builder"
ilogging "github.com/buildpacks/pack/internal/logging"
"github.com/buildpacks/pack/logging"
h "github.com/buildpacks/pack/testhelpers"
)

func TestCommon(t *testing.T) {
color.Disable(true)
defer color.Disable(false)
spec.Run(t, "build", testCommon, spec.Report(report.Terminal{}))
}

func testCommon(t *testing.T, when spec.G, it spec.S) {
when("#resolveRunImage", func() {
var (
subject *Client
outBuf bytes.Buffer
logger logging.Logger
runImageName string
defaultRegistry string
defaultMirror string
gcrRegistry string
gcrRunMirror string
stackInfo builder.StackMetadata
)

it.Before(func() {
logger = ilogging.NewLogWithWriters(&outBuf, &outBuf)

var err error
subject, err = NewClient(WithLogger(logger))
h.AssertNil(t, err)

defaultRegistry = "default.registry.io"
runImageName = "stack/run"
defaultMirror = defaultRegistry + "/" + runImageName
gcrRegistry = "gcr.io"
gcrRunMirror = gcrRegistry + "/" + runImageName
stackInfo = builder.StackMetadata{
RunImage: builder.RunImageMetadata{
Image: runImageName,
Mirrors: []string{
defaultMirror, gcrRunMirror,
},
},
}
})

when("passed specific run image", func() {
it("selects that run image", func() {
runImgFlag := "flag/passed-run-image"
runImageName := subject.resolveRunImage(runImgFlag, defaultRegistry, "", stackInfo, nil, false)
h.AssertEq(t, runImageName, runImgFlag)
})
})

when("publish is true", func() {
it("defaults to run-image in registry publishing to", func() {
runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo, nil, true)
h.AssertEq(t, runImageName, gcrRunMirror)
})

it("prefers config defined run image mirror to stack defined run image mirror", func() {
configMirrors := map[string][]string{
runImageName: []string{defaultRegistry + "/unique-run-img"},
}
runImageName := subject.resolveRunImage("", defaultRegistry, "", stackInfo, configMirrors, true)
h.AssertNotEq(t, runImageName, defaultMirror)
h.AssertEq(t, runImageName, defaultRegistry+"/unique-run-img")
})

it("returns a config mirror if no match to target registry", func() {
configMirrors := map[string][]string{
runImageName: []string{defaultRegistry + "/unique-run-img"},
}
runImageName := subject.resolveRunImage("", "test.registry.io", "", stackInfo, configMirrors, true)
h.AssertNotEq(t, runImageName, defaultMirror)
h.AssertEq(t, runImageName, defaultRegistry+"/unique-run-img")
})
})

// If publish is false, we are using the local daemon, and want to match to the builder registry
when("publish is false", func() {
it("defaults to run-image in registry publishing to", func() {
runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo, nil, false)
h.AssertEq(t, runImageName, defaultMirror)
h.AssertNotEq(t, runImageName, gcrRunMirror)
})

it("prefers config defined run image mirror to stack defined run image mirror", func() {
configMirrors := map[string][]string{
runImageName: []string{defaultRegistry + "/unique-run-img"},
}
runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo, configMirrors, false)
h.AssertNotEq(t, runImageName, defaultMirror)
h.AssertEq(t, runImageName, defaultRegistry+"/unique-run-img")
})

it("returns a config mirror if no match to target registry", func() {
configMirrors := map[string][]string{
runImageName: []string{defaultRegistry + "/unique-run-img"},
}
runImageName := subject.resolveRunImage("", defaultRegistry, "test.registry.io", stackInfo, configMirrors, false)
h.AssertNotEq(t, runImageName, defaultMirror)
h.AssertEq(t, runImageName, defaultRegistry+"/unique-run-img")
})
})
})
}
4 changes: 3 additions & 1 deletion rebase.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@ func (c *Client) Rebase(ctx context.Context, opts RebaseOptions) error {
runImageName := c.resolveRunImage(
opts.RunImage,
imageRef.Context().RegistryStr(),
"",
builder.StackMetadata{
RunImage: builder.RunImageMetadata{
Image: md.Stack.RunImage.Image,
Mirrors: md.Stack.RunImage.Mirrors,
},
},
opts.AdditionalMirrors)
opts.AdditionalMirrors,
opts.Publish)

if runImageName == "" {
return errors.New("run image must be specified")
Expand Down

0 comments on commit f1097a4

Please sign in to comment.