Relevant changes:
- buildkit#667 gateway: check for `ReadDir` and `StatFile` caps on client side
- buildkit#668 dockerfile: fix ssh required option
- buildkit#669 dockerfile: update default copy image
- buildkit#670 solver: specify SSH key ID in error message when required key was not forwarded
- buildkit#673 solver: fix possible nil dereference
- buildkit#672 fix setting uncompressed label on content
- buildkit#680 dockerfile: fix empty dest directory panic
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -26,7 +26,7 @@ github.com/imdario/mergo v0.3.6 |
| 26 | 26 |
golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca |
| 27 | 27 |
|
| 28 | 28 |
# buildkit |
| 29 |
-github.com/moby/buildkit 520201006c9dc676da9cf9655337ac711f7f127d |
|
| 29 |
+github.com/moby/buildkit c7bb575343df0cbfeab8b5b28149630b8153fcc6 |
|
| 30 | 30 |
github.com/tonistiigi/fsutil f567071bed2416e4d87d260d3162722651182317 |
| 31 | 31 |
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746 |
| 32 | 32 |
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7 |
| ... | ... |
@@ -35,7 +35,7 @@ const ( |
| 35 | 35 |
localNameContext = "context" |
| 36 | 36 |
historyComment = "buildkit.dockerfile.v0" |
| 37 | 37 |
|
| 38 |
- DefaultCopyImage = "tonistiigi/copy:v0.1.5@sha256:eab89b76ffbb3c807663a67a41e8be31b8a0e362d7fb074a55bddace563a28bb" |
|
| 38 |
+ DefaultCopyImage = "tonistiigi/copy:v0.1.7@sha256:9aab7d9ab369c6daf4831bf0653f7592110ab4b7e8a33fee2b9dca546e9d3089" |
|
| 39 | 39 |
) |
| 40 | 40 |
|
| 41 | 41 |
type ConvertOpt struct {
|
| ... | ... |
@@ -212,7 +212,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, |
| 212 | 212 |
eg.Go(func() error {
|
| 213 | 213 |
ref, err := reference.ParseNormalizedNamed(d.stage.BaseName) |
| 214 | 214 |
if err != nil {
|
| 215 |
- return err |
|
| 215 |
+ return errors.Wrapf(err, "failed to parse stage name %q", d.stage.BaseName) |
|
| 216 | 216 |
} |
| 217 | 217 |
platform := d.platform |
| 218 | 218 |
if platform == nil {
|
| ... | ... |
@@ -653,7 +653,7 @@ func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState l |
| 653 | 653 |
img := llb.Image(opt.copyImage, llb.MarkImageInternal, llb.Platform(opt.buildPlatforms[0]), WithInternalName("helper image for file operations"))
|
| 654 | 654 |
|
| 655 | 655 |
dest := path.Join(".", pathRelativeToWorkingDir(d.state, c.Dest()))
|
| 656 |
- if c.Dest() == "." || c.Dest()[len(c.Dest())-1] == filepath.Separator {
|
|
| 656 |
+ if c.Dest() == "." || c.Dest() == "" || c.Dest()[len(c.Dest())-1] == filepath.Separator {
|
|
| 657 | 657 |
dest += string(filepath.Separator) |
| 658 | 658 |
} |
| 659 | 659 |
args := []string{"copy"}
|
| ... | ... |
@@ -356,6 +356,9 @@ func (r *reference) ReadFile(ctx context.Context, req client.ReadRequest) ([]byt |
| 356 | 356 |
} |
| 357 | 357 |
|
| 358 | 358 |
func (r *reference) ReadDir(ctx context.Context, req client.ReadDirRequest) ([]*fstypes.Stat, error) {
|
| 359 |
+ if err := r.c.caps.Supports(pb.CapReadDir); err != nil {
|
|
| 360 |
+ return nil, err |
|
| 361 |
+ } |
|
| 359 | 362 |
rdr := &pb.ReadDirRequest{
|
| 360 | 363 |
DirPath: req.Path, |
| 361 | 364 |
IncludePattern: req.IncludePattern, |
| ... | ... |
@@ -369,6 +372,9 @@ func (r *reference) ReadDir(ctx context.Context, req client.ReadDirRequest) ([]* |
| 369 | 369 |
} |
| 370 | 370 |
|
| 371 | 371 |
func (r *reference) StatFile(ctx context.Context, req client.StatRequest) (*fstypes.Stat, error) {
|
| 372 |
+ if err := r.c.caps.Supports(pb.CapStatFile); err != nil {
|
|
| 373 |
+ return nil, err |
|
| 374 |
+ } |
|
| 372 | 375 |
rdr := &pb.StatFileRequest{
|
| 373 | 376 |
Path: req.Path, |
| 374 | 377 |
Ref: r.id, |
| ... | ... |
@@ -107,10 +107,21 @@ func (s *Snapshotter) GetBlob(ctx context.Context, key string) (digest.Digest, d |
| 107 | 107 |
// Checks that there is a blob in the content store. |
| 108 | 108 |
// If same blob has already been set then this is a noop. |
| 109 | 109 |
func (s *Snapshotter) SetBlob(ctx context.Context, key string, diffID, blobsum digest.Digest) error {
|
| 110 |
- _, err := s.opt.Content.Info(ctx, blobsum) |
|
| 110 |
+ info, err := s.opt.Content.Info(ctx, blobsum) |
|
| 111 | 111 |
if err != nil {
|
| 112 | 112 |
return err |
| 113 | 113 |
} |
| 114 |
+ if _, ok := info.Labels["containerd.io/uncompressed"]; !ok {
|
|
| 115 |
+ labels := map[string]string{
|
|
| 116 |
+ "containerd.io/uncompressed": diffID.String(), |
|
| 117 |
+ } |
|
| 118 |
+ if _, err := s.opt.Content.Update(ctx, content.Info{
|
|
| 119 |
+ Digest: blobsum, |
|
| 120 |
+ Labels: labels, |
|
| 121 |
+ }, "labels.containerd.io/uncompressed"); err != nil {
|
|
| 122 |
+ return err |
|
| 123 |
+ } |
|
| 124 |
+ } |
|
| 114 | 125 |
md, _ := s.opt.MetadataStore.Get(key) |
| 115 | 126 |
|
| 116 | 127 |
v, err := metadata.NewValue(DiffPair{DiffID: diffID, Blobsum: blobsum})
|
| ... | ... |
@@ -211,10 +211,12 @@ func (ei *edgeIndex) getAllMatches(k *CacheKey) []string {
|
| 211 | 211 |
for _, d := range dd {
|
| 212 | 212 |
ll := CacheInfoLink{Input: Index(i), Digest: k.Digest(), Output: k.Output(), Selector: d.Selector}
|
| 213 | 213 |
for _, ckID := range d.CacheKey.CacheKey.indexIDs {
|
| 214 |
- if l, ok := ei.items[ckID].links[ll]; ok {
|
|
| 215 |
- if _, ok := l[m]; ok {
|
|
| 216 |
- found = true |
|
| 217 |
- break |
|
| 214 |
+ if item, ok := ei.items[ckID]; ok {
|
|
| 215 |
+ if l, ok := item.links[ll]; ok {
|
|
| 216 |
+ if _, ok := l[m]; ok {
|
|
| 217 |
+ found = true |
|
| 218 |
+ break |
|
| 219 |
+ } |
|
| 218 | 220 |
} |
| 219 | 221 |
} |
| 220 | 222 |
} |
| ... | ... |
@@ -302,7 +302,7 @@ func (e *execOp) getSSHMountable(ctx context.Context, m *pb.Mount) (cache.Mounta |
| 302 | 302 |
return nil, nil |
| 303 | 303 |
} |
| 304 | 304 |
if st, ok := status.FromError(err); ok && st.Code() == codes.Unimplemented {
|
| 305 |
- return nil, errors.Errorf("no ssh forwarded from the client")
|
|
| 305 |
+ return nil, errors.Errorf("no SSH key %q forwarded from the client", m.SSHOpt.ID)
|
|
| 306 | 306 |
} |
| 307 | 307 |
return nil, err |
| 308 | 308 |
} |
| ... | ... |
@@ -3,11 +3,16 @@ package contentutil |
| 3 | 3 |
import ( |
| 4 | 4 |
"context" |
| 5 | 5 |
"net/http" |
| 6 |
+ "sync" |
|
| 6 | 7 |
|
| 7 | 8 |
"github.com/containerd/containerd/content" |
| 9 |
+ "github.com/containerd/containerd/errdefs" |
|
| 8 | 10 |
"github.com/containerd/containerd/remotes" |
| 9 | 11 |
"github.com/containerd/containerd/remotes/docker" |
| 12 |
+ "github.com/docker/docker/pkg/locker" |
|
| 13 |
+ digest "github.com/opencontainers/go-digest" |
|
| 10 | 14 |
ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| 15 |
+ "github.com/pkg/errors" |
|
| 11 | 16 |
) |
| 12 | 17 |
|
| 13 | 18 |
func ProviderFromRef(ref string) (ocispec.Descriptor, content.Provider, error) {
|
| ... | ... |
@@ -38,11 +43,13 @@ func IngesterFromRef(ref string) (content.Ingester, error) {
|
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 | 40 |
return &ingester{
|
| 41 |
+ locker: locker.New(), |
|
| 41 | 42 |
pusher: pusher, |
| 42 | 43 |
}, nil |
| 43 | 44 |
} |
| 44 | 45 |
|
| 45 | 46 |
type ingester struct {
|
| 47 |
+ locker *locker.Locker |
|
| 46 | 48 |
pusher remotes.Pusher |
| 47 | 49 |
} |
| 48 | 50 |
|
| ... | ... |
@@ -53,5 +60,38 @@ func (w *ingester) Writer(ctx context.Context, opts ...content.WriterOpt) (conte |
| 53 | 53 |
return nil, err |
| 54 | 54 |
} |
| 55 | 55 |
} |
| 56 |
- return w.pusher.Push(ctx, wo.Desc) |
|
| 56 |
+ if wo.Ref == "" {
|
|
| 57 |
+ return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty") |
|
| 58 |
+ } |
|
| 59 |
+ w.locker.Lock(wo.Ref) |
|
| 60 |
+ var once sync.Once |
|
| 61 |
+ unlock := func() {
|
|
| 62 |
+ once.Do(func() {
|
|
| 63 |
+ w.locker.Unlock(wo.Ref) |
|
| 64 |
+ }) |
|
| 65 |
+ } |
|
| 66 |
+ writer, err := w.pusher.Push(ctx, wo.Desc) |
|
| 67 |
+ if err != nil {
|
|
| 68 |
+ return nil, err |
|
| 69 |
+ } |
|
| 70 |
+ return &lockedWriter{unlock: unlock, Writer: writer}, nil
|
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+type lockedWriter struct {
|
|
| 74 |
+ unlock func() |
|
| 75 |
+ content.Writer |
|
| 76 |
+} |
|
| 77 |
+ |
|
| 78 |
+func (w *lockedWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
|
|
| 79 |
+ err := w.Writer.Commit(ctx, size, expected, opts...) |
|
| 80 |
+ if err == nil {
|
|
| 81 |
+ w.unlock() |
|
| 82 |
+ } |
|
| 83 |
+ return err |
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+func (w *lockedWriter) Close() error {
|
|
| 87 |
+ err := w.Writer.Close() |
|
| 88 |
+ w.unlock() |
|
| 89 |
+ return err |
|
| 57 | 90 |
} |