Skip to content

Push once #2855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/moby/buildkit v0.3.3
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc v0.1.1 // indirect
github.com/pkg/errors v0.8.1
github.com/prometheus/procfs v0.0.4 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BU
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 h1:w3NnFcKR5241cfmQU5ZZAsf0xcpId6mWOupTvJlUX2U=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker-credential-helpers v0.6.1 h1:Dq4iIfcM7cNtddhLVWe9h4QDjsi4OER3Z8voPu/I52g=
github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
Expand Down
1 change: 1 addition & 0 deletions pkg/skaffold/build/local/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func TestDockerCLIBuild(t *testing.T) {
testutil.Run(t, test.description, func(t *testutil.T) {
t.NewTempDir().Chdir()
dockerfilePath, _ := filepath.Abs("Dockerfile")
t.Override(&docker.DefaultAuthHelper, testAuthHelper{})
t.Override(&util.DefaultExecCommand, testutil.CmdRunEnv(
"docker build . --file "+dockerfilePath+" -t tag --force-rm",
test.expectedEnv,
Expand Down
6 changes: 4 additions & 2 deletions pkg/skaffold/build/local/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestLocalRun(t *testing.T) {
artifacts []*latest.Artifact
expected []build.Artifact
expectedWarnings []string
expectedPushed []string
expectedPushed map[string]string
pushImages bool
shouldErr bool
}{
Expand Down Expand Up @@ -99,7 +99,9 @@ func TestLocalRun(t *testing.T) {
ImageName: "gcr.io/test/image",
Tag: "gcr.io/test/image:tag@sha256:51ae7fa00c92525c319404a3a6d400e52ff9372c5a39cb415e0486fe425f3165",
}},
expectedPushed: []string{"sha256:51ae7fa00c92525c319404a3a6d400e52ff9372c5a39cb415e0486fe425f3165"},
expectedPushed: map[string]string{
"gcr.io/test/image:tag": "sha256:51ae7fa00c92525c319404a3a6d400e52ff9372c5a39cb415e0486fe425f3165",
},
},
{
description: "error build",
Expand Down
33 changes: 33 additions & 0 deletions pkg/skaffold/docker/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ func (l *localDaemon) Push(ctx context.Context, out io.Writer, ref string) (stri
return "", errors.Wrapf(err, "getting auth config for %s", ref)
}

// Quick check if the image was already pushed (ignore any error).
if alreadyPushed, digest, err := l.isAlreadyPushed(ctx, ref, registryAuth); alreadyPushed && err == nil {
return digest, nil
}

rc, err := l.apiClient.ImagePush(ctx, ref, types.ImagePushOptions{
RegistryAuth: registryAuth,
})
Expand Down Expand Up @@ -256,6 +261,34 @@ func (l *localDaemon) Push(ctx context.Context, out io.Writer, ref string) (stri
return digest, nil
}

// isAlreadyPushed quickly checks if the local image has already been pushed.
func (l *localDaemon) isAlreadyPushed(ctx context.Context, ref, registryAuth string) (bool, string, error) {
localImage, _, err := l.apiClient.ImageInspectWithRaw(ctx, ref)
if err != nil {
return false, "", err
}

if len(localImage.RepoDigests) == 0 {
return false, "", nil
}

remoteImage, err := l.apiClient.DistributionInspect(ctx, ref, registryAuth)
if err != nil {
return false, "", err
}
digest := remoteImage.Descriptor.Digest.String()

for _, repoDigest := range localImage.RepoDigests {
if parsed, err := ParseReference(repoDigest); err == nil {
if parsed.Digest == digest {
return true, parsed.Digest, nil
}
}
}

return false, "", nil
}

// Pull pulls an image reference from a registry.
func (l *localDaemon) Pull(ctx context.Context, out io.Writer, ref string) error {
registryAuth, err := l.encodedRegistryAuth(ctx, DefaultAuthHelper, ref)
Expand Down
19 changes: 19 additions & 0 deletions pkg/skaffold/docker/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,25 @@ func TestPush(t *testing.T) {
}
}

func TestDontPushAlreadyPushed(t *testing.T) {
testutil.Run(t, "", func(t *testutil.T) {
t.Override(&DefaultAuthHelper, testAuthHelper{})

api := &testutil.FakeAPIClient{}
api.Add("image", "sha256:imageIDabcab")
localDocker := NewLocalDaemon(api, nil, false, nil)

digest, err := localDocker.Push(context.Background(), ioutil.Discard, "image")
t.CheckErrorAndDeepEqual(false, err, "sha256:bb1f952848763dd1f8fcf14231d7a4557775abf3c95e588561bc7a478c94e7e0", digest)

// Images already pushed don't need being pushed.
api.ErrImagePush = true

digest, err = localDocker.Push(context.Background(), ioutil.Discard, "image")
t.CheckErrorAndDeepEqual(false, err, "sha256:bb1f952848763dd1f8fcf14231d7a4557775abf3c95e588561bc7a478c94e7e0", digest)
})
}

func TestBuild(t *testing.T) {
tests := []struct {
description string
Expand Down
36 changes: 30 additions & 6 deletions testutil/fake_image_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ import (
"strings"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
"github.com/docker/docker/registry"
reg "github.com/docker/docker/registry"
digest "github.com/opencontainers/go-digest"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)

type FakeAPIClient struct {
Expand All @@ -40,7 +43,7 @@ type FakeAPIClient struct {
ErrStream bool

nextImageID int
Pushed []string
Pushed map[string]string
Built []types.ImageBuildOptions
}

Expand Down Expand Up @@ -105,15 +108,33 @@ func (f *FakeAPIClient) ImageInspectWithRaw(_ context.Context, ref string) (type
if tag == ref || imageID == ref {
rawConfig := []byte(fmt.Sprintf(`{"Config":{"Image":"%s"}}`, imageID))

var repoDigests []string
if digest, found := f.Pushed[ref]; found {
repoDigests = append(repoDigests, ref+"@"+digest)
}

return types.ImageInspect{
ID: imageID,
ID: imageID,
RepoDigests: repoDigests,
}, rawConfig, nil
}
}

return types.ImageInspect{}, nil, &notFoundError{}
}

func (f *FakeAPIClient) DistributionInspect(ctx context.Context, ref, encodedRegistryAuth string) (registry.DistributionInspect, error) {
if sha, found := f.Pushed[ref]; found {
return registry.DistributionInspect{
Descriptor: v1.Descriptor{
Digest: digest.Digest(sha),
},
}, nil
}

return registry.DistributionInspect{}, &notFoundError{}
}

func (f *FakeAPIClient) ImageTag(_ context.Context, image, ref string) error {
imageID, ok := f.tagToImageID[image]
if !ok {
Expand All @@ -135,12 +156,15 @@ func (f *FakeAPIClient) ImagePush(_ context.Context, ref string, _ types.ImagePu
}

digest := "sha256:" + fmt.Sprintf("%x", sha256Digester.Sum(nil))[0:64]
f.Pushed = append(f.Pushed, digest)
if f.Pushed == nil {
f.Pushed = make(map[string]string)
}
f.Pushed[ref] = digest

return f.body(digest), nil
}

func (f *FakeAPIClient) ImagePull(_ context.Context, ref string, _ types.ImagePullOptions) (io.ReadCloser, error) {
func (f *FakeAPIClient) ImagePull(context.Context, string, types.ImagePullOptions) (io.ReadCloser, error) {
if f.ErrImagePull {
return nil, fmt.Errorf("")
}
Expand All @@ -150,7 +174,7 @@ func (f *FakeAPIClient) ImagePull(_ context.Context, ref string, _ types.ImagePu

func (f *FakeAPIClient) Info(context.Context) (types.Info, error) {
return types.Info{
IndexServerAddress: registry.IndexServer,
IndexServerAddress: reg.IndexServer,
}, nil
}

Expand Down