Merge pull request #887 from tonistiigi/push-by-digest

exporter: allow push by digest in image exporter
docker-19.03
Tibor Vass 2019-03-20 19:13:09 -07:00 committed by GitHub
commit 9a9e755588
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 12 deletions

View File

@ -33,6 +33,7 @@ import (
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/secrets/secretsprovider"
"github.com/moby/buildkit/session/sshforward/sshprovider"
"github.com/moby/buildkit/util/contentutil"
"github.com/moby/buildkit/util/testutil"
"github.com/moby/buildkit/util/testutil/httpserver"
"github.com/moby/buildkit/util/testutil/integration"
@ -85,6 +86,7 @@ func TestClientIntegration(t *testing.T) {
testSSHMount,
testStdinClosed,
testHostnameLookup,
testPushByDigest,
testBasicInlineCacheImportExport,
testExportBusyboxLocal,
},
@ -373,6 +375,50 @@ func testNetworkMode(t *testing.T, sb integration.Sandbox) {
require.Contains(t, err.Error(), "network.host is not allowed")
}
func testPushByDigest(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
c, err := New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()
registry, err := sb.NewRegistry()
if errors.Cause(err) == integration.ErrorRequirements {
t.Skip(err.Error())
}
require.NoError(t, err)
st := llb.Scratch().File(llb.Mkfile("foo", 0600, []byte("data")))
def, err := st.Marshal()
require.NoError(t, err)
name := registry + "/foo/bar"
resp, err := c.Solve(context.TODO(), def, SolveOpt{
Exports: []ExportEntry{
{
Type: "image",
Attrs: map[string]string{
"name": name,
"push": "true",
"push-by-digest": "true",
},
},
},
}, nil)
require.NoError(t, err)
_, _, err = contentutil.ProviderFromRef(name + ":latest")
require.Error(t, err)
desc, _, err := contentutil.ProviderFromRef(name + "@" + resp.ExporterResponse["containerimage.digest"])
require.NoError(t, err)
require.Equal(t, resp.ExporterResponse["containerimage.digest"], desc.Digest.String())
require.Equal(t, images.MediaTypeDockerSchema2Manifest, desc.MediaType)
require.True(t, desc.Size > 0)
}
func testFrontendImageNaming(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
c, err := New(context.TODO(), sb.Address())

View File

@ -16,10 +16,11 @@ import (
)
const (
keyImageName = "name"
keyPush = "push"
keyInsecure = "registry.insecure"
ociTypes = "oci-mediatypes"
keyImageName = "name"
keyPush = "push"
keyPushByDigest = "push-by-digest"
keyInsecure = "registry.insecure"
ociTypes = "oci-mediatypes"
)
type Opt struct {
@ -58,6 +59,16 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp
return nil, errors.Wrapf(err, "non-bool value specified for %s", k)
}
i.push = b
case keyPushByDigest:
if v == "" {
i.pushByDigest = true
continue
}
b, err := strconv.ParseBool(v)
if err != nil {
return nil, errors.Wrapf(err, "non-bool value specified for %s", k)
}
i.pushByDigest = b
case keyInsecure:
if v == "" {
i.insecure = true
@ -90,11 +101,12 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp
type imageExporterInstance struct {
*imageExporter
targetName string
push bool
insecure bool
ociTypes bool
meta map[string][]byte
targetName string
push bool
pushByDigest bool
insecure bool
ociTypes bool
meta map[string][]byte
}
func (e *imageExporterInstance) Name() string {
@ -146,7 +158,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source)
tagDone(nil)
}
if e.push {
if err := push.Push(ctx, e.opt.SessionManager, e.opt.ImageWriter.ContentStore(), desc.Digest, targetName, e.insecure, e.opt.ResolverOpt); err != nil {
if err := push.Push(ctx, e.opt.SessionManager, e.opt.ImageWriter.ContentStore(), desc.Digest, targetName, e.insecure, e.opt.ResolverOpt, e.pushByDigest); err != nil {
return nil, err
}
}

View File

@ -19,6 +19,7 @@ import (
"github.com/moby/buildkit/util/resolver"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@ -40,7 +41,7 @@ func getCredentialsFunc(ctx context.Context, sm *session.Manager) func(string) (
}
}
func Push(ctx context.Context, sm *session.Manager, cs content.Provider, dgst digest.Digest, ref string, insecure bool, rfn resolver.ResolveOptionsFunc) error {
func Push(ctx context.Context, sm *session.Manager, cs content.Provider, dgst digest.Digest, ref string, insecure bool, rfn resolver.ResolveOptionsFunc, byDigest bool) error {
desc := ocispec.Descriptor{
Digest: dgst,
}
@ -48,7 +49,15 @@ func Push(ctx context.Context, sm *session.Manager, cs content.Provider, dgst di
if err != nil {
return err
}
ref = reference.TagNameOnly(parsed).String()
if byDigest && !reference.IsNameOnly(parsed) {
return errors.Errorf("can't push tagged ref %s by digest", parsed.String())
}
if byDigest {
ref = parsed.Name()
} else {
ref = reference.TagNameOnly(parsed).String()
}
opt := rfn(ref)
opt.Credentials = getCredentialsFunc(ctx, sm)