Merge pull request #887 from tonistiigi/push-by-digest
exporter: allow push by digest in image exporterdocker-19.03
commit
9a9e755588
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue