feat: replace github.com/pkg/errors to errors
Signed-off-by: haoyun <yun.hao@daocloud.io> Co-authored-by: zounengren <zouyee1989@gmail.com>
This commit is contained in:
		@@ -19,6 +19,8 @@ package archive
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"archive/tar"
 | 
						"archive/tar"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
@@ -30,7 +32,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/containerd/continuity/fs"
 | 
						"github.com/containerd/continuity/fs"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var bufPool = &sync.Pool{
 | 
					var bufPool = &sync.Pool{
 | 
				
			||||||
@@ -76,7 +77,7 @@ func WriteDiff(ctx context.Context, w io.Writer, a, b string, opts ...WriteDiffO
 | 
				
			|||||||
	var options WriteDiffOptions
 | 
						var options WriteDiffOptions
 | 
				
			||||||
	for _, opt := range opts {
 | 
						for _, opt := range opts {
 | 
				
			||||||
		if err := opt(&options); err != nil {
 | 
							if err := opt(&options); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to apply option")
 | 
								return fmt.Errorf("failed to apply option: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if options.writeDiffFunc == nil {
 | 
						if options.writeDiffFunc == nil {
 | 
				
			||||||
@@ -97,7 +98,7 @@ func writeDiffNaive(ctx context.Context, w io.Writer, a, b string, _ WriteDiffOp
 | 
				
			|||||||
	cw := NewChangeWriter(w, b)
 | 
						cw := NewChangeWriter(w, b)
 | 
				
			||||||
	err := fs.Changes(ctx, a, b, cw.HandleChange)
 | 
						err := fs.Changes(ctx, a, b, cw.HandleChange)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create diff tar stream")
 | 
							return fmt.Errorf("failed to create diff tar stream: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return cw.Close()
 | 
						return cw.Close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -128,7 +129,7 @@ func Apply(ctx context.Context, root string, r io.Reader, opts ...ApplyOpt) (int
 | 
				
			|||||||
	var options ApplyOptions
 | 
						var options ApplyOptions
 | 
				
			||||||
	for _, opt := range opts {
 | 
						for _, opt := range opts {
 | 
				
			||||||
		if err := opt(&options); err != nil {
 | 
							if err := opt(&options); err != nil {
 | 
				
			||||||
			return 0, errors.Wrap(err, "failed to apply option")
 | 
								return 0, fmt.Errorf("failed to apply option: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if options.Filter == nil {
 | 
						if options.Filter == nil {
 | 
				
			||||||
@@ -236,7 +237,7 @@ func applyNaive(ctx context.Context, root string, r io.Reader, options ApplyOpti
 | 
				
			|||||||
		ppath, base := filepath.Split(hdr.Name)
 | 
							ppath, base := filepath.Split(hdr.Name)
 | 
				
			||||||
		ppath, err = fs.RootPath(root, ppath)
 | 
							ppath, err = fs.RootPath(root, ppath)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return 0, errors.Wrap(err, "failed to get root path")
 | 
								return 0, fmt.Errorf("failed to get root path: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Join to root before joining to parent path to ensure relative links are
 | 
							// Join to root before joining to parent path to ensure relative links are
 | 
				
			||||||
@@ -266,7 +267,7 @@ func applyNaive(ctx context.Context, root string, r io.Reader, options ApplyOpti
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		writeFile, err := convertWhiteout(hdr, path)
 | 
							writeFile, err := convertWhiteout(hdr, path)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return 0, errors.Wrapf(err, "failed to convert whiteout file %q", hdr.Name)
 | 
								return 0, fmt.Errorf("failed to convert whiteout file %q: %w", hdr.Name, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !writeFile {
 | 
							if !writeFile {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
@@ -373,7 +374,7 @@ func createTarFile(ctx context.Context, path, extractDir string, hdr *tar.Header
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return errors.Errorf("unhandled tar header type %d\n", hdr.Typeflag)
 | 
							return fmt.Errorf("unhandled tar header type %d", hdr.Typeflag)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Lchown is not supported on Windows.
 | 
						// Lchown is not supported on Windows.
 | 
				
			||||||
@@ -520,7 +521,7 @@ func (cw *ChangeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
 | 
				
			|||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := cw.tw.WriteHeader(hdr); err != nil {
 | 
							if err := cw.tw.WriteHeader(hdr); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to write whiteout header")
 | 
								return fmt.Errorf("failed to write whiteout header: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
@@ -555,12 +556,12 @@ func (cw *ChangeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
 | 
				
			|||||||
		if strings.HasPrefix(name, string(filepath.Separator)) {
 | 
							if strings.HasPrefix(name, string(filepath.Separator)) {
 | 
				
			||||||
			name, err = filepath.Rel(string(filepath.Separator), name)
 | 
								name, err = filepath.Rel(string(filepath.Separator), name)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "failed to make path relative")
 | 
									return fmt.Errorf("failed to make path relative: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		name, err = tarName(name)
 | 
							name, err = tarName(name)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "cannot canonicalize path")
 | 
								return fmt.Errorf("cannot canonicalize path: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// suffix with '/' for directories
 | 
							// suffix with '/' for directories
 | 
				
			||||||
		if f.IsDir() && !strings.HasSuffix(name, "/") {
 | 
							if f.IsDir() && !strings.HasSuffix(name, "/") {
 | 
				
			||||||
@@ -569,7 +570,7 @@ func (cw *ChangeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
 | 
				
			|||||||
		hdr.Name = name
 | 
							hdr.Name = name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := setHeaderForSpecialDevice(hdr, name, f); err != nil {
 | 
							if err := setHeaderForSpecialDevice(hdr, name, f); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to set device headers")
 | 
								return fmt.Errorf("failed to set device headers: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// additionalLinks stores file names which must be linked to
 | 
							// additionalLinks stores file names which must be linked to
 | 
				
			||||||
@@ -597,7 +598,7 @@ func (cw *ChangeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if capability, err := getxattr(source, "security.capability"); err != nil {
 | 
							if capability, err := getxattr(source, "security.capability"); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to get capabilities xattr")
 | 
								return fmt.Errorf("failed to get capabilities xattr: %w", err)
 | 
				
			||||||
		} else if len(capability) > 0 {
 | 
							} else if len(capability) > 0 {
 | 
				
			||||||
			if hdr.PAXRecords == nil {
 | 
								if hdr.PAXRecords == nil {
 | 
				
			||||||
				hdr.PAXRecords = map[string]string{}
 | 
									hdr.PAXRecords = map[string]string{}
 | 
				
			||||||
@@ -609,19 +610,19 @@ func (cw *ChangeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
 | 
				
			|||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := cw.tw.WriteHeader(hdr); err != nil {
 | 
							if err := cw.tw.WriteHeader(hdr); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to write file header")
 | 
								return fmt.Errorf("failed to write file header: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
 | 
							if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
 | 
				
			||||||
			file, err := open(source)
 | 
								file, err := open(source)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrapf(err, "failed to open path: %v", source)
 | 
									return fmt.Errorf("failed to open path: %v: %w", source, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			defer file.Close()
 | 
								defer file.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			n, err := copyBuffered(context.TODO(), cw.tw, file)
 | 
								n, err := copyBuffered(context.TODO(), cw.tw, file)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "failed to copy")
 | 
									return fmt.Errorf("failed to copy: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if n != hdr.Size {
 | 
								if n != hdr.Size {
 | 
				
			||||||
				return errors.New("short write copying file")
 | 
									return errors.New("short write copying file")
 | 
				
			||||||
@@ -640,7 +641,7 @@ func (cw *ChangeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
 | 
				
			|||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if err := cw.tw.WriteHeader(hdr); err != nil {
 | 
									if err := cw.tw.WriteHeader(hdr); err != nil {
 | 
				
			||||||
					return errors.Wrap(err, "failed to write file header")
 | 
										return fmt.Errorf("failed to write file header: %w", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -651,7 +652,7 @@ func (cw *ChangeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
 | 
				
			|||||||
// Close closes this writer.
 | 
					// Close closes this writer.
 | 
				
			||||||
func (cw *ChangeWriter) Close() error {
 | 
					func (cw *ChangeWriter) Close() error {
 | 
				
			||||||
	if err := cw.tw.Close(); err != nil {
 | 
						if err := cw.tw.Close(); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to close tar writer")
 | 
							return fmt.Errorf("failed to close tar writer: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -764,7 +765,7 @@ func validateWhiteout(path string) error {
 | 
				
			|||||||
			dir += string(filepath.Separator)
 | 
								dir += string(filepath.Separator)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !strings.HasPrefix(originalPath, dir) {
 | 
							if !strings.HasPrefix(originalPath, dir) {
 | 
				
			||||||
			return errors.Wrapf(errInvalidArchive, "invalid whiteout name: %v", base)
 | 
								return fmt.Errorf("invalid whiteout name: %v: %w", base, errInvalidArchive)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/snapshots/overlay/overlayutils"
 | 
						"github.com/containerd/containerd/snapshots/overlay/overlayutils"
 | 
				
			||||||
	"github.com/containerd/continuity/fs"
 | 
						"github.com/containerd/continuity/fs"
 | 
				
			||||||
	"github.com/containerd/continuity/fs/fstest"
 | 
						"github.com/containerd/continuity/fs/fstest"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestOverlayApply(t *testing.T) {
 | 
					func TestOverlayApply(t *testing.T) {
 | 
				
			||||||
@@ -72,7 +71,7 @@ func TestOverlayApplyNoParents(t *testing.T) {
 | 
				
			|||||||
			cw.addedDirs = nil
 | 
								cw.addedDirs = nil
 | 
				
			||||||
			err := fs.Changes(ctx, a, b, cw.HandleChange)
 | 
								err := fs.Changes(ctx, a, b, cw.HandleChange)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "failed to create diff tar stream")
 | 
									return fmt.Errorf("failed to create diff tar stream: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return cw.Close()
 | 
								return cw.Close()
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -97,7 +96,7 @@ type contextKey struct{}
 | 
				
			|||||||
func (d overlayDiffApplier) TestContext(ctx context.Context) (context.Context, func(), error) {
 | 
					func (d overlayDiffApplier) TestContext(ctx context.Context) (context.Context, func(), error) {
 | 
				
			||||||
	merged, err := os.MkdirTemp(d.tmp, "merged")
 | 
						merged, err := os.MkdirTemp(d.tmp, "merged")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return ctx, nil, errors.Wrap(err, "failed to make merged dir")
 | 
							return ctx, nil, fmt.Errorf("failed to make merged dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	oc := &overlayContext{
 | 
						oc := &overlayContext{
 | 
				
			||||||
@@ -118,7 +117,7 @@ func (d overlayDiffApplier) Apply(ctx context.Context, a fstest.Applier) (string
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	applyCopy, err := os.MkdirTemp(d.tmp, "apply-copy-")
 | 
						applyCopy, err := os.MkdirTemp(d.tmp, "apply-copy-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to create temp dir")
 | 
							return "", nil, fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer os.RemoveAll(applyCopy)
 | 
						defer os.RemoveAll(applyCopy)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -128,33 +127,33 @@ func (d overlayDiffApplier) Apply(ctx context.Context, a fstest.Applier) (string
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = fs.CopyDir(applyCopy, base); err != nil {
 | 
						if err = fs.CopyDir(applyCopy, base); err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to copy base")
 | 
							return "", nil, fmt.Errorf("failed to copy base: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := a.Apply(applyCopy); err != nil {
 | 
						if err := a.Apply(applyCopy); err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to apply changes to copy of base")
 | 
							return "", nil, fmt.Errorf("failed to apply changes to copy of base: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf := bytes.NewBuffer(nil)
 | 
						buf := bytes.NewBuffer(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := d.diff(ctx, buf, base, applyCopy); err != nil {
 | 
						if err := d.diff(ctx, buf, base, applyCopy); err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to create diff")
 | 
							return "", nil, fmt.Errorf("failed to create diff: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if oc.mounted {
 | 
						if oc.mounted {
 | 
				
			||||||
		if err := mount.Unmount(oc.merged, 0); err != nil {
 | 
							if err := mount.Unmount(oc.merged, 0); err != nil {
 | 
				
			||||||
			return "", nil, errors.Wrap(err, "failed to unmount")
 | 
								return "", nil, fmt.Errorf("failed to unmount: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		oc.mounted = false
 | 
							oc.mounted = false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	next, err := os.MkdirTemp(d.tmp, "lower-")
 | 
						next, err := os.MkdirTemp(d.tmp, "lower-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to create temp dir")
 | 
							return "", nil, fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err = Apply(ctx, next, buf, WithConvertWhiteout(OverlayConvertWhiteout), WithParents(oc.lowers)); err != nil {
 | 
						if _, err = Apply(ctx, next, buf, WithConvertWhiteout(OverlayConvertWhiteout), WithParents(oc.lowers)); err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to apply tar stream")
 | 
							return "", nil, fmt.Errorf("failed to apply tar stream: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	oc.lowers = append([]string{next}, oc.lowers...)
 | 
						oc.lowers = append([]string{next}, oc.lowers...)
 | 
				
			||||||
@@ -172,7 +171,7 @@ func (d overlayDiffApplier) Apply(ctx context.Context, a fstest.Applier) (string
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := m.Mount(oc.merged); err != nil {
 | 
						if err := m.Mount(oc.merged); err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrapf(err, "failed to mount: %v", m)
 | 
							return "", nil, fmt.Errorf("failed to mount: %v: %w", m, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	oc.mounted = true
 | 
						oc.mounted = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ import (
 | 
				
			|||||||
	"archive/tar"
 | 
						"archive/tar"
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -36,7 +37,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/pkg/testutil"
 | 
						"github.com/containerd/containerd/pkg/testutil"
 | 
				
			||||||
	"github.com/containerd/continuity/fs"
 | 
						"github.com/containerd/continuity/fs"
 | 
				
			||||||
	"github.com/containerd/continuity/fs/fstest"
 | 
						"github.com/containerd/continuity/fs/fstest"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -235,10 +235,10 @@ func TestBreakouts(t *testing.T) {
 | 
				
			|||||||
	unbrokenCheck := func(root string) error {
 | 
						unbrokenCheck := func(root string) error {
 | 
				
			||||||
		b, err := os.ReadFile(filepath.Join(root, "etc", "unbroken"))
 | 
							b, err := os.ReadFile(filepath.Join(root, "etc", "unbroken"))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to read unbroken")
 | 
								return fmt.Errorf("failed to read unbroken: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if string(b) != expected {
 | 
							if string(b) != expected {
 | 
				
			||||||
			return errors.Errorf("/etc/unbroken: unexpected value %s, expected %s", b, expected)
 | 
								return fmt.Errorf("/etc/unbroken: unexpected value %s, expected %s", b, expected)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -257,7 +257,7 @@ func TestBreakouts(t *testing.T) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if got := fi.Mode() & os.ModeSymlink; got != os.ModeSymlink {
 | 
								if got := fi.Mode() & os.ModeSymlink; got != os.ModeSymlink {
 | 
				
			||||||
				return errors.Errorf("%s should be symlink", fi.Name())
 | 
									return fmt.Errorf("%s should be symlink", fi.Name())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -285,7 +285,7 @@ func TestBreakouts(t *testing.T) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if t1 != t2 {
 | 
								if t1 != t2 {
 | 
				
			||||||
				return errors.Wrapf(errFileDiff, "%#v and %#v", t1, t2)
 | 
									return fmt.Errorf("%#v and %#v: %w", t1, t2, errFileDiff)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -310,7 +310,7 @@ func TestBreakouts(t *testing.T) {
 | 
				
			|||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if !os.SameFile(s1, s2) {
 | 
								if !os.SameFile(s1, s2) {
 | 
				
			||||||
				return errors.Wrapf(errFileDiff, "%#v and %#v", s1, s2)
 | 
									return fmt.Errorf("%#v and %#v: %w", s1, s2, errFileDiff)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -335,7 +335,7 @@ func TestBreakouts(t *testing.T) {
 | 
				
			|||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if !bytes.Equal(b, content) {
 | 
								if !bytes.Equal(b, content) {
 | 
				
			||||||
				return errors.Errorf("content differs: expected %v, got %v", content, b)
 | 
									return fmt.Errorf("content differs: expected %v, got %v", content, b)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -422,7 +422,7 @@ func TestBreakouts(t *testing.T) {
 | 
				
			|||||||
			validator: func(root string) error {
 | 
								validator: func(root string) error {
 | 
				
			||||||
				b, err := os.ReadFile(filepath.Join(root, "etc", "emptied"))
 | 
									b, err := os.ReadFile(filepath.Join(root, "etc", "emptied"))
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return errors.Wrap(err, "failed to read unbroken")
 | 
										return fmt.Errorf("failed to read unbroken: %w", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if len(b) > 0 {
 | 
									if len(b) > 0 {
 | 
				
			||||||
					return errors.New("/etc/emptied: non-empty")
 | 
										return errors.New("/etc/emptied: non-empty")
 | 
				
			||||||
@@ -774,7 +774,7 @@ func TestBreakouts(t *testing.T) {
 | 
				
			|||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if perm := fi.Mode() & os.ModePerm; perm != 0400 {
 | 
									if perm := fi.Mode() & os.ModePerm; perm != 0400 {
 | 
				
			||||||
					return errors.Errorf("%s perm changed from 0400 to %04o", p, perm)
 | 
										return fmt.Errorf("%s perm changed from 0400 to %04o", p, perm)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return nil
 | 
									return nil
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -800,7 +800,7 @@ func TestApplyTar(t *testing.T) {
 | 
				
			|||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if _, err := os.Stat(p); err != nil {
 | 
									if _, err := os.Stat(p); err != nil {
 | 
				
			||||||
					return errors.Wrapf(err, "failure checking existence for %v", d)
 | 
										return fmt.Errorf("failure checking existence for %v: %w", d, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
@@ -844,23 +844,23 @@ func TestApplyTar(t *testing.T) {
 | 
				
			|||||||
func testApply(a fstest.Applier) error {
 | 
					func testApply(a fstest.Applier) error {
 | 
				
			||||||
	td, err := os.MkdirTemp("", "test-apply-")
 | 
						td, err := os.MkdirTemp("", "test-apply-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create temp dir")
 | 
							return fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer os.RemoveAll(td)
 | 
						defer os.RemoveAll(td)
 | 
				
			||||||
	dest, err := os.MkdirTemp("", "test-apply-dest-")
 | 
						dest, err := os.MkdirTemp("", "test-apply-dest-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create temp dir")
 | 
							return fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer os.RemoveAll(dest)
 | 
						defer os.RemoveAll(dest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := a.Apply(td); err != nil {
 | 
						if err := a.Apply(td); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to apply filesystem changes")
 | 
							return fmt.Errorf("failed to apply filesystem changes: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tarArgs := []string{"c", "-C", td}
 | 
						tarArgs := []string{"c", "-C", td}
 | 
				
			||||||
	names, err := readDirNames(td)
 | 
						names, err := readDirNames(td)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to read directory names")
 | 
							return fmt.Errorf("failed to read directory names: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tarArgs = append(tarArgs, names...)
 | 
						tarArgs = append(tarArgs, names...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -868,15 +868,15 @@ func testApply(a fstest.Applier) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	arch, err := cmd.StdoutPipe()
 | 
						arch, err := cmd.StdoutPipe()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create stdout pipe")
 | 
							return fmt.Errorf("failed to create stdout pipe: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := cmd.Start(); err != nil {
 | 
						if err := cmd.Start(); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to start command")
 | 
							return fmt.Errorf("failed to start command: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := Apply(context.Background(), dest, arch); err != nil {
 | 
						if _, err := Apply(context.Background(), dest, arch); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to apply tar stream")
 | 
							return fmt.Errorf("failed to apply tar stream: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fstest.CheckDirectoryEqual(td, dest)
 | 
						return fstest.CheckDirectoryEqual(td, dest)
 | 
				
			||||||
@@ -885,17 +885,17 @@ func testApply(a fstest.Applier) error {
 | 
				
			|||||||
func testBaseDiff(a fstest.Applier) error {
 | 
					func testBaseDiff(a fstest.Applier) error {
 | 
				
			||||||
	td, err := os.MkdirTemp("", "test-base-diff-")
 | 
						td, err := os.MkdirTemp("", "test-base-diff-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create temp dir")
 | 
							return fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer os.RemoveAll(td)
 | 
						defer os.RemoveAll(td)
 | 
				
			||||||
	dest, err := os.MkdirTemp("", "test-base-diff-dest-")
 | 
						dest, err := os.MkdirTemp("", "test-base-diff-dest-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create temp dir")
 | 
							return fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer os.RemoveAll(dest)
 | 
						defer os.RemoveAll(dest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := a.Apply(td); err != nil {
 | 
						if err := a.Apply(td); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to apply filesystem changes")
 | 
							return fmt.Errorf("failed to apply filesystem changes: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	arch := Diff(context.Background(), "", td)
 | 
						arch := Diff(context.Background(), "", td)
 | 
				
			||||||
@@ -903,7 +903,7 @@ func testBaseDiff(a fstest.Applier) error {
 | 
				
			|||||||
	cmd := exec.Command(tarCmd, "x", "-C", dest)
 | 
						cmd := exec.Command(tarCmd, "x", "-C", dest)
 | 
				
			||||||
	cmd.Stdin = arch
 | 
						cmd.Stdin = arch
 | 
				
			||||||
	if err := cmd.Run(); err != nil {
 | 
						if err := cmd.Run(); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "tar command failed")
 | 
							return fmt.Errorf("tar command failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fstest.CheckDirectoryEqual(td, dest)
 | 
						return fstest.CheckDirectoryEqual(td, dest)
 | 
				
			||||||
@@ -912,18 +912,18 @@ func testBaseDiff(a fstest.Applier) error {
 | 
				
			|||||||
func testDiffApply(appliers ...fstest.Applier) error {
 | 
					func testDiffApply(appliers ...fstest.Applier) error {
 | 
				
			||||||
	td, err := os.MkdirTemp("", "test-diff-apply-")
 | 
						td, err := os.MkdirTemp("", "test-diff-apply-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create temp dir")
 | 
							return fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer os.RemoveAll(td)
 | 
						defer os.RemoveAll(td)
 | 
				
			||||||
	dest, err := os.MkdirTemp("", "test-diff-apply-dest-")
 | 
						dest, err := os.MkdirTemp("", "test-diff-apply-dest-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create temp dir")
 | 
							return fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer os.RemoveAll(dest)
 | 
						defer os.RemoveAll(dest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, a := range appliers {
 | 
						for _, a := range appliers {
 | 
				
			||||||
		if err := a.Apply(td); err != nil {
 | 
							if err := a.Apply(td); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to apply filesystem changes")
 | 
								return fmt.Errorf("failed to apply filesystem changes: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -931,18 +931,18 @@ func testDiffApply(appliers ...fstest.Applier) error {
 | 
				
			|||||||
	if len(appliers) > 1 {
 | 
						if len(appliers) > 1 {
 | 
				
			||||||
		for _, a := range appliers[:len(appliers)-1] {
 | 
							for _, a := range appliers[:len(appliers)-1] {
 | 
				
			||||||
			if err := a.Apply(dest); err != nil {
 | 
								if err := a.Apply(dest); err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "failed to apply base filesystem changes")
 | 
									return fmt.Errorf("failed to apply base filesystem changes: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	diffBytes, err := io.ReadAll(Diff(context.Background(), dest, td))
 | 
						diffBytes, err := io.ReadAll(Diff(context.Background(), dest, td))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create diff")
 | 
							return fmt.Errorf("failed to create diff: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := Apply(context.Background(), dest, bytes.NewReader(diffBytes)); err != nil {
 | 
						if _, err := Apply(context.Background(), dest, bytes.NewReader(diffBytes)); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to apply tar stream")
 | 
							return fmt.Errorf("failed to apply tar stream: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fstest.CheckDirectoryEqual(td, dest)
 | 
						return fstest.CheckDirectoryEqual(td, dest)
 | 
				
			||||||
@@ -1194,10 +1194,10 @@ func dirEntry(name string, mode int) tarEntryValidator {
 | 
				
			|||||||
			return errors.New("not directory type")
 | 
								return errors.New("not directory type")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if hdr.Name != name {
 | 
							if hdr.Name != name {
 | 
				
			||||||
			return errors.Errorf("wrong name %q, expected %q", hdr.Name, name)
 | 
								return fmt.Errorf("wrong name %q, expected %q", hdr.Name, name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if hdr.Mode != int64(mode) {
 | 
							if hdr.Mode != int64(mode) {
 | 
				
			||||||
			return errors.Errorf("wrong mode %o, expected %o", hdr.Mode, mode)
 | 
								return fmt.Errorf("wrong mode %o, expected %o", hdr.Mode, mode)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1209,10 +1209,10 @@ func fileEntry(name string, expected []byte, mode int) tarEntryValidator {
 | 
				
			|||||||
			return errors.New("not file type")
 | 
								return errors.New("not file type")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if hdr.Name != name {
 | 
							if hdr.Name != name {
 | 
				
			||||||
			return errors.Errorf("wrong name %q, expected %q", hdr.Name, name)
 | 
								return fmt.Errorf("wrong name %q, expected %q", hdr.Name, name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if hdr.Mode != int64(mode) {
 | 
							if hdr.Mode != int64(mode) {
 | 
				
			||||||
			return errors.Errorf("wrong mode %o, expected %o", hdr.Mode, mode)
 | 
								return fmt.Errorf("wrong mode %o, expected %o", hdr.Mode, mode)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !bytes.Equal(b, expected) {
 | 
							if !bytes.Equal(b, expected) {
 | 
				
			||||||
			return errors.New("different file content")
 | 
								return errors.New("different file content")
 | 
				
			||||||
@@ -1227,10 +1227,10 @@ func linkEntry(name, link string) tarEntryValidator {
 | 
				
			|||||||
			return errors.New("not link type")
 | 
								return errors.New("not link type")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if hdr.Name != name {
 | 
							if hdr.Name != name {
 | 
				
			||||||
			return errors.Errorf("wrong name %q, expected %q", hdr.Name, name)
 | 
								return fmt.Errorf("wrong name %q, expected %q", hdr.Name, name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if hdr.Linkname != link {
 | 
							if hdr.Linkname != link {
 | 
				
			||||||
			return errors.Errorf("wrong link %q, expected %q", hdr.Linkname, link)
 | 
								return fmt.Errorf("wrong link %q, expected %q", hdr.Linkname, link)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1243,10 +1243,10 @@ func whiteoutEntry(name string) tarEntryValidator {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return func(hdr *tar.Header, b []byte) error {
 | 
						return func(hdr *tar.Header, b []byte) error {
 | 
				
			||||||
		if hdr.Typeflag != tar.TypeReg {
 | 
							if hdr.Typeflag != tar.TypeReg {
 | 
				
			||||||
			return errors.Errorf("not file type: %q", hdr.Typeflag)
 | 
								return fmt.Errorf("not file type: %q", hdr.Typeflag)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if hdr.Name != whiteOut {
 | 
							if hdr.Name != whiteOut {
 | 
				
			||||||
			return errors.Errorf("wrong name %q, expected whiteout %q", hdr.Name, name)
 | 
								return fmt.Errorf("wrong name %q, expected whiteout %q", hdr.Name, name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1309,7 +1309,7 @@ type diffApplier struct{}
 | 
				
			|||||||
func (d diffApplier) TestContext(ctx context.Context) (context.Context, func(), error) {
 | 
					func (d diffApplier) TestContext(ctx context.Context) (context.Context, func(), error) {
 | 
				
			||||||
	base, err := os.MkdirTemp("", "test-diff-apply-")
 | 
						base, err := os.MkdirTemp("", "test-diff-apply-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return ctx, nil, errors.Wrap(err, "failed to create temp dir")
 | 
							return ctx, nil, fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return context.WithValue(ctx, d, base), func() {
 | 
						return context.WithValue(ctx, d, base), func() {
 | 
				
			||||||
		os.RemoveAll(base)
 | 
							os.RemoveAll(base)
 | 
				
			||||||
@@ -1321,23 +1321,23 @@ func (d diffApplier) Apply(ctx context.Context, a fstest.Applier) (string, func(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	applyCopy, err := os.MkdirTemp("", "test-diffapply-apply-copy-")
 | 
						applyCopy, err := os.MkdirTemp("", "test-diffapply-apply-copy-")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to create temp dir")
 | 
							return "", nil, fmt.Errorf("failed to create temp dir: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer os.RemoveAll(applyCopy)
 | 
						defer os.RemoveAll(applyCopy)
 | 
				
			||||||
	if err = fs.CopyDir(applyCopy, base); err != nil {
 | 
						if err = fs.CopyDir(applyCopy, base); err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to copy base")
 | 
							return "", nil, fmt.Errorf("failed to copy base: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := a.Apply(applyCopy); err != nil {
 | 
						if err := a.Apply(applyCopy); err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to apply changes to copy of base")
 | 
							return "", nil, fmt.Errorf("failed to apply changes to copy of base: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	diffBytes, err := io.ReadAll(Diff(ctx, base, applyCopy))
 | 
						diffBytes, err := io.ReadAll(Diff(ctx, base, applyCopy))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to create diff")
 | 
							return "", nil, fmt.Errorf("failed to create diff: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err = Apply(ctx, base, bytes.NewReader(diffBytes)); err != nil {
 | 
						if _, err = Apply(ctx, base, bytes.NewReader(diffBytes)); err != nil {
 | 
				
			||||||
		return "", nil, errors.Wrap(err, "failed to apply tar stream")
 | 
							return "", nil, fmt.Errorf("failed to apply tar stream: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return base, nil, nil
 | 
						return base, nil, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,8 @@ package archive
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"archive/tar"
 | 
						"archive/tar"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -29,7 +31,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/pkg/userns"
 | 
						"github.com/containerd/containerd/pkg/userns"
 | 
				
			||||||
	"github.com/containerd/continuity/fs"
 | 
						"github.com/containerd/continuity/fs"
 | 
				
			||||||
	"github.com/containerd/continuity/sysx"
 | 
						"github.com/containerd/continuity/sysx"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"golang.org/x/sys/unix"
 | 
						"golang.org/x/sys/unix"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -139,7 +140,7 @@ func getxattr(path, attr string) ([]byte, error) {
 | 
				
			|||||||
func setxattr(path, key, value string) error {
 | 
					func setxattr(path, key, value string) error {
 | 
				
			||||||
	// Do not set trusted attributes
 | 
						// Do not set trusted attributes
 | 
				
			||||||
	if strings.HasPrefix(key, "trusted.") {
 | 
						if strings.HasPrefix(key, "trusted.") {
 | 
				
			||||||
		return errors.Wrap(unix.ENOTSUP, "admin attributes from archive not supported")
 | 
							return fmt.Errorf("admin attributes from archive not supported: %w", unix.ENOTSUP)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return unix.Lsetxattr(path, key, []byte(value), 0)
 | 
						return unix.Lsetxattr(path, key, []byte(value), 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -159,12 +160,12 @@ func copyDirInfo(fi os.FileInfo, path string) error {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to chown %s", path)
 | 
								return fmt.Errorf("failed to chown %s: %w", path, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := os.Chmod(path, fi.Mode()); err != nil {
 | 
						if err := os.Chmod(path, fi.Mode()); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "failed to chmod %s", path)
 | 
							return fmt.Errorf("failed to chmod %s: %w", path, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	timespec := []unix.Timespec{
 | 
						timespec := []unix.Timespec{
 | 
				
			||||||
@@ -172,7 +173,7 @@ func copyDirInfo(fi os.FileInfo, path string) error {
 | 
				
			|||||||
		unix.NsecToTimespec(syscall.TimespecToNsec(fs.StatMtime(st))),
 | 
							unix.NsecToTimespec(syscall.TimespecToNsec(fs.StatMtime(st))),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
 | 
						if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "failed to utime %s", path)
 | 
							return fmt.Errorf("failed to utime %s: %w", path, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
@@ -184,7 +185,7 @@ func copyUpXAttrs(dst, src string) error {
 | 
				
			|||||||
		if err == unix.ENOTSUP || err == sysx.ENODATA {
 | 
							if err == unix.ENOTSUP || err == sysx.ENODATA {
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return errors.Wrapf(err, "failed to list xattrs on %s", src)
 | 
							return fmt.Errorf("failed to list xattrs on %s: %w", src, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, xattr := range xattrKeys {
 | 
						for _, xattr := range xattrKeys {
 | 
				
			||||||
		// Do not copy up trusted attributes
 | 
							// Do not copy up trusted attributes
 | 
				
			||||||
@@ -196,10 +197,10 @@ func copyUpXAttrs(dst, src string) error {
 | 
				
			|||||||
			if err == unix.ENOTSUP || err == sysx.ENODATA {
 | 
								if err == unix.ENOTSUP || err == sysx.ENODATA {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
 | 
								return fmt.Errorf("failed to get xattr %q on %s: %w", xattr, src, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := lsetxattrCreate(dst, xattr, data); err != nil {
 | 
							if err := lsetxattrCreate(dst, xattr, data); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
 | 
								return fmt.Errorf("failed to set xattr %q on %s: %w", xattr, dst, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,12 +18,12 @@ package archive
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"archive/tar"
 | 
						"archive/tar"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/sys"
 | 
						"github.com/containerd/containerd/sys"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// tarName returns platform-specific filepath
 | 
					// tarName returns platform-specific filepath
 | 
				
			||||||
@@ -112,7 +112,7 @@ func setxattr(path, key, value string) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func copyDirInfo(fi os.FileInfo, path string) error {
 | 
					func copyDirInfo(fi os.FileInfo, path string) error {
 | 
				
			||||||
	if err := os.Chmod(path, fi.Mode()); err != nil {
 | 
						if err := os.Chmod(path, fi.Mode()); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "failed to chmod %s", path)
 | 
							return fmt.Errorf("failed to chmod %s: %w", path, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,11 +20,10 @@
 | 
				
			|||||||
package archive
 | 
					package archive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"golang.org/x/sys/unix"
 | 
						"golang.org/x/sys/unix"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func chtimes(path string, atime, mtime time.Time) error {
 | 
					func chtimes(path string, atime, mtime time.Time) error {
 | 
				
			||||||
@@ -33,7 +32,7 @@ func chtimes(path string, atime, mtime time.Time) error {
 | 
				
			|||||||
	utimes[1] = unix.NsecToTimespec(mtime.UnixNano())
 | 
						utimes[1] = unix.NsecToTimespec(mtime.UnixNano())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
 | 
						if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "failed call to UtimesNanoAt for %s", path)
 | 
							return fmt.Errorf("failed call to UtimesNanoAt for %s: %w", path, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ package cio
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
@@ -28,7 +29,6 @@ import (
 | 
				
			|||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/fifo"
 | 
						"github.com/containerd/fifo"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewFIFOSetInDir returns a new FIFOSet with paths in a temporary directory under root
 | 
					// NewFIFOSetInDir returns a new FIFOSet with paths in a temporary directory under root
 | 
				
			||||||
@@ -112,7 +112,7 @@ func openFifos(ctx context.Context, fifos *FIFOSet) (f pipes, retErr error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if fifos.Stdin != "" {
 | 
						if fifos.Stdin != "" {
 | 
				
			||||||
		if f.Stdin, retErr = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
 | 
							if f.Stdin, retErr = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
 | 
				
			||||||
			return f, errors.Wrapf(retErr, "failed to open stdin fifo")
 | 
								return f, fmt.Errorf("failed to open stdin fifo: %w", retErr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer func() {
 | 
							defer func() {
 | 
				
			||||||
			if retErr != nil && f.Stdin != nil {
 | 
								if retErr != nil && f.Stdin != nil {
 | 
				
			||||||
@@ -122,7 +122,7 @@ func openFifos(ctx context.Context, fifos *FIFOSet) (f pipes, retErr error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if fifos.Stdout != "" {
 | 
						if fifos.Stdout != "" {
 | 
				
			||||||
		if f.Stdout, retErr = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
 | 
							if f.Stdout, retErr = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
 | 
				
			||||||
			return f, errors.Wrapf(retErr, "failed to open stdout fifo")
 | 
								return f, fmt.Errorf("failed to open stdout fifo: %w", retErr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer func() {
 | 
							defer func() {
 | 
				
			||||||
			if retErr != nil && f.Stdout != nil {
 | 
								if retErr != nil && f.Stdout != nil {
 | 
				
			||||||
@@ -132,7 +132,7 @@ func openFifos(ctx context.Context, fifos *FIFOSet) (f pipes, retErr error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if !fifos.Terminal && fifos.Stderr != "" {
 | 
						if !fifos.Terminal && fifos.Stderr != "" {
 | 
				
			||||||
		if f.Stderr, retErr = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
 | 
							if f.Stderr, retErr = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
 | 
				
			||||||
			return f, errors.Wrapf(retErr, "failed to open stderr fifo")
 | 
								return f, fmt.Errorf("failed to open stderr fifo: %w", retErr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return f, nil
 | 
						return f, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	winio "github.com/Microsoft/go-winio"
 | 
						winio "github.com/Microsoft/go-winio"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const pipeRoot = `\\.\pipe`
 | 
					const pipeRoot = `\\.\pipe`
 | 
				
			||||||
@@ -54,7 +53,7 @@ func copyIO(fifos *FIFOSet, ioset *Streams) (_ *cio, retErr error) {
 | 
				
			|||||||
	if fifos.Stdin != "" {
 | 
						if fifos.Stdin != "" {
 | 
				
			||||||
		l, err := winio.ListenPipe(fifos.Stdin, nil)
 | 
							l, err := winio.ListenPipe(fifos.Stdin, nil)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Stdin)
 | 
								return nil, fmt.Errorf("failed to create stdin pipe %s: %w", fifos.Stdin, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		cios.closers = append(cios.closers, l)
 | 
							cios.closers = append(cios.closers, l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -77,7 +76,7 @@ func copyIO(fifos *FIFOSet, ioset *Streams) (_ *cio, retErr error) {
 | 
				
			|||||||
	if fifos.Stdout != "" {
 | 
						if fifos.Stdout != "" {
 | 
				
			||||||
		l, err := winio.ListenPipe(fifos.Stdout, nil)
 | 
							l, err := winio.ListenPipe(fifos.Stdout, nil)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "failed to create stdout pipe %s", fifos.Stdout)
 | 
								return nil, fmt.Errorf("failed to create stdout pipe %s: %w", fifos.Stdout, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		cios.closers = append(cios.closers, l)
 | 
							cios.closers = append(cios.closers, l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,7 +99,7 @@ func copyIO(fifos *FIFOSet, ioset *Streams) (_ *cio, retErr error) {
 | 
				
			|||||||
	if fifos.Stderr != "" {
 | 
						if fifos.Stderr != "" {
 | 
				
			||||||
		l, err := winio.ListenPipe(fifos.Stderr, nil)
 | 
							l, err := winio.ListenPipe(fifos.Stderr, nil)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Stderr)
 | 
								return nil, fmt.Errorf("failed to create stderr pipe %s: %w", fifos.Stderr, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		cios.closers = append(cios.closers, l)
 | 
							cios.closers = append(cios.closers, l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								client.go
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								client.go
									
									
									
									
									
								
							@@ -61,7 +61,6 @@ import (
 | 
				
			|||||||
	ptypes "github.com/gogo/protobuf/types"
 | 
						ptypes "github.com/gogo/protobuf/types"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
 | 
						"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
 | 
				
			||||||
	"golang.org/x/sync/semaphore"
 | 
						"golang.org/x/sync/semaphore"
 | 
				
			||||||
	"google.golang.org/grpc"
 | 
						"google.golang.org/grpc"
 | 
				
			||||||
@@ -152,7 +151,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
 | 
				
			|||||||
			defer cancel()
 | 
								defer cancel()
 | 
				
			||||||
			conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
 | 
								conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, errors.Wrapf(err, "failed to dial %q", address)
 | 
									return nil, fmt.Errorf("failed to dial %q: %w", address, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return conn, nil
 | 
								return conn, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -163,7 +162,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
 | 
				
			|||||||
		c.conn, c.connector = conn, connector
 | 
							c.conn, c.connector = conn, connector
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if copts.services == nil && c.conn == nil {
 | 
						if copts.services == nil && c.conn == nil {
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection or services is available")
 | 
							return nil, fmt.Errorf("no grpc connection or services is available: %w", errdefs.ErrUnavailable)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// check namespace labels for default runtime
 | 
						// check namespace labels for default runtime
 | 
				
			||||||
@@ -223,7 +222,7 @@ type Client struct {
 | 
				
			|||||||
// Reconnect re-establishes the GRPC connection to the containerd daemon
 | 
					// Reconnect re-establishes the GRPC connection to the containerd daemon
 | 
				
			||||||
func (c *Client) Reconnect() error {
 | 
					func (c *Client) Reconnect() error {
 | 
				
			||||||
	if c.connector == nil {
 | 
						if c.connector == nil {
 | 
				
			||||||
		return errors.Wrap(errdefs.ErrUnavailable, "unable to reconnect to containerd, no connector available")
 | 
							return fmt.Errorf("unable to reconnect to containerd, no connector available: %w", errdefs.ErrUnavailable)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.connMu.Lock()
 | 
						c.connMu.Lock()
 | 
				
			||||||
	defer c.connMu.Unlock()
 | 
						defer c.connMu.Unlock()
 | 
				
			||||||
@@ -251,7 +250,7 @@ func (c *Client) IsServing(ctx context.Context) (bool, error) {
 | 
				
			|||||||
	c.connMu.Lock()
 | 
						c.connMu.Lock()
 | 
				
			||||||
	if c.conn == nil {
 | 
						if c.conn == nil {
 | 
				
			||||||
		c.connMu.Unlock()
 | 
							c.connMu.Unlock()
 | 
				
			||||||
		return false, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available")
 | 
							return false, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.connMu.Unlock()
 | 
						c.connMu.Unlock()
 | 
				
			||||||
	r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.WaitForReady(true))
 | 
						r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.WaitForReady(true))
 | 
				
			||||||
@@ -393,7 +392,7 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if fetchCtx.Unpack {
 | 
						if fetchCtx.Unpack {
 | 
				
			||||||
		return images.Image{}, errors.Wrap(errdefs.ErrNotImplemented, "unpack on fetch not supported, try pull")
 | 
							return images.Image{}, fmt.Errorf("unpack on fetch not supported, try pull: %w", errdefs.ErrNotImplemented)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if fetchCtx.PlatformMatcher == nil {
 | 
						if fetchCtx.PlatformMatcher == nil {
 | 
				
			||||||
@@ -404,7 +403,7 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag
 | 
				
			|||||||
			for _, s := range fetchCtx.Platforms {
 | 
								for _, s := range fetchCtx.Platforms {
 | 
				
			||||||
				p, err := platforms.Parse(s)
 | 
									p, err := platforms.Parse(s)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return images.Image{}, errors.Wrapf(err, "invalid platform %s", s)
 | 
										return images.Image{}, fmt.Errorf("invalid platform %s: %w", s, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				ps = append(ps, p)
 | 
									ps = append(ps, p)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -440,7 +439,7 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor,
 | 
				
			|||||||
			for _, platform := range pushCtx.Platforms {
 | 
								for _, platform := range pushCtx.Platforms {
 | 
				
			||||||
				p, err := platforms.Parse(platform)
 | 
									p, err := platforms.Parse(platform)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return errors.Wrapf(err, "invalid platform %s", platform)
 | 
										return fmt.Errorf("invalid platform %s: %w", platform, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				ps = append(ps, p)
 | 
									ps = append(ps, p)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -723,7 +722,7 @@ func (c *Client) Version(ctx context.Context) (Version, error) {
 | 
				
			|||||||
	c.connMu.Lock()
 | 
						c.connMu.Lock()
 | 
				
			||||||
	if c.conn == nil {
 | 
						if c.conn == nil {
 | 
				
			||||||
		c.connMu.Unlock()
 | 
							c.connMu.Unlock()
 | 
				
			||||||
		return Version{}, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available")
 | 
							return Version{}, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.connMu.Unlock()
 | 
						c.connMu.Unlock()
 | 
				
			||||||
	response, err := c.VersionService().Version(ctx, &ptypes.Empty{})
 | 
						response, err := c.VersionService().Version(ctx, &ptypes.Empty{})
 | 
				
			||||||
@@ -746,7 +745,7 @@ func (c *Client) Server(ctx context.Context) (ServerInfo, error) {
 | 
				
			|||||||
	c.connMu.Lock()
 | 
						c.connMu.Lock()
 | 
				
			||||||
	if c.conn == nil {
 | 
						if c.conn == nil {
 | 
				
			||||||
		c.connMu.Unlock()
 | 
							c.connMu.Unlock()
 | 
				
			||||||
		return ServerInfo{}, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available")
 | 
							return ServerInfo{}, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.connMu.Unlock()
 | 
						c.connMu.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -784,7 +783,7 @@ func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Sna
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	s := c.SnapshotService(name)
 | 
						s := c.SnapshotService(name)
 | 
				
			||||||
	if s == nil {
 | 
						if s == nil {
 | 
				
			||||||
		return nil, errors.Wrapf(errdefs.ErrNotFound, "snapshotter %s was not found", name)
 | 
							return nil, fmt.Errorf("snapshotter %s was not found: %w", name, errdefs.ErrNotFound)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return s, nil
 | 
						return s, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/ttrpc"
 | 
						"github.com/containerd/ttrpc"
 | 
				
			||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	ptypes "github.com/gogo/protobuf/types"
 | 
						ptypes "github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
	"golang.org/x/sys/unix"
 | 
						"golang.org/x/sys/unix"
 | 
				
			||||||
@@ -154,7 +153,7 @@ func executeShim() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	server, err := newServer()
 | 
						server, err := newServer()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed creating server")
 | 
							return fmt.Errorf("failed creating server: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sv, err := shim.NewService(
 | 
						sv, err := shim.NewService(
 | 
				
			||||||
		shim.Config{
 | 
							shim.Config{
 | 
				
			||||||
@@ -212,7 +211,7 @@ func serve(ctx context.Context, server *ttrpc.Server, path string) error {
 | 
				
			|||||||
			p = abstractSocketPrefix + p
 | 
								p = abstractSocketPrefix + p
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(p) > socketPathLimit {
 | 
							if len(p) > socketPathLimit {
 | 
				
			||||||
			return errors.Errorf("%q: unix socket path too long (> %d)", p, socketPathLimit)
 | 
								return fmt.Errorf("%q: unix socket path too long (> %d)", p, socketPathLimit)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		l, err = net.Listen("unix", p)
 | 
							l, err = net.Listen("unix", p)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -310,10 +309,10 @@ func (l *remoteEventsPublisher) Publish(ctx context.Context, topic string, event
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	status, err := reaper.Default.WaitTimeout(cmd, c, 30*time.Second)
 | 
						status, err := reaper.Default.WaitTimeout(cmd, c, 30*time.Second)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "failed to publish event: %s", b.String())
 | 
							return fmt.Errorf("failed to publish event: %s: %w", b.String(), err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if status != 0 {
 | 
						if status != 0 {
 | 
				
			||||||
		return errors.Errorf("failed to publish event: %s", b.String())
 | 
							return fmt.Errorf("failed to publish event: %s", b.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/sys"
 | 
						"github.com/containerd/containerd/sys"
 | 
				
			||||||
	"github.com/containerd/containerd/tracing"
 | 
						"github.com/containerd/containerd/tracing"
 | 
				
			||||||
	"github.com/containerd/containerd/version"
 | 
						"github.com/containerd/containerd/version"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
	"google.golang.org/grpc/grpclog"
 | 
						"google.golang.org/grpc/grpclog"
 | 
				
			||||||
@@ -155,7 +154,7 @@ can be used and modified as necessary as a custom configuration.`
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// cleanup temp mounts
 | 
							// cleanup temp mounts
 | 
				
			||||||
		if err := mount.SetTempMountLocation(filepath.Join(config.Root, "tmpmounts")); err != nil {
 | 
							if err := mount.SetTempMountLocation(filepath.Join(config.Root, "tmpmounts")); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "creating temp mount location")
 | 
								return fmt.Errorf("creating temp mount location: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// unmount all temp mounts on boot for the server
 | 
							// unmount all temp mounts on boot for the server
 | 
				
			||||||
		warnings, err := mount.CleanupTempMounts(0)
 | 
							warnings, err := mount.CleanupTempMounts(0)
 | 
				
			||||||
@@ -167,7 +166,7 @@ can be used and modified as necessary as a custom configuration.`
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if config.GRPC.Address == "" {
 | 
							if config.GRPC.Address == "" {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrInvalidArgument, "grpc address cannot be empty")
 | 
								return fmt.Errorf("grpc address cannot be empty: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if config.TTRPC.Address == "" {
 | 
							if config.TTRPC.Address == "" {
 | 
				
			||||||
			// If TTRPC was not explicitly configured, use defaults based on GRPC.
 | 
								// If TTRPC was not explicitly configured, use defaults based on GRPC.
 | 
				
			||||||
@@ -235,11 +234,11 @@ can be used and modified as necessary as a custom configuration.`
 | 
				
			|||||||
			var l net.Listener
 | 
								var l net.Listener
 | 
				
			||||||
			if isLocalAddress(config.Debug.Address) {
 | 
								if isLocalAddress(config.Debug.Address) {
 | 
				
			||||||
				if l, err = sys.GetLocalListener(config.Debug.Address, config.Debug.UID, config.Debug.GID); err != nil {
 | 
									if l, err = sys.GetLocalListener(config.Debug.Address, config.Debug.UID, config.Debug.GID); err != nil {
 | 
				
			||||||
					return errors.Wrapf(err, "failed to get listener for debug endpoint")
 | 
										return fmt.Errorf("failed to get listener for debug endpoint: %w", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				if l, err = net.Listen("tcp", config.Debug.Address); err != nil {
 | 
									if l, err = net.Listen("tcp", config.Debug.Address); err != nil {
 | 
				
			||||||
					return errors.Wrapf(err, "failed to get listener for debug endpoint")
 | 
										return fmt.Errorf("failed to get listener for debug endpoint: %w", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			serve(ctx, l, server.ServeDebug)
 | 
								serve(ctx, l, server.ServeDebug)
 | 
				
			||||||
@@ -247,28 +246,28 @@ can be used and modified as necessary as a custom configuration.`
 | 
				
			|||||||
		if config.Metrics.Address != "" {
 | 
							if config.Metrics.Address != "" {
 | 
				
			||||||
			l, err := net.Listen("tcp", config.Metrics.Address)
 | 
								l, err := net.Listen("tcp", config.Metrics.Address)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrapf(err, "failed to get listener for metrics endpoint")
 | 
									return fmt.Errorf("failed to get listener for metrics endpoint: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			serve(ctx, l, server.ServeMetrics)
 | 
								serve(ctx, l, server.ServeMetrics)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// setup the ttrpc endpoint
 | 
							// setup the ttrpc endpoint
 | 
				
			||||||
		tl, err := sys.GetLocalListener(config.TTRPC.Address, config.TTRPC.UID, config.TTRPC.GID)
 | 
							tl, err := sys.GetLocalListener(config.TTRPC.Address, config.TTRPC.UID, config.TTRPC.GID)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to get listener for main ttrpc endpoint")
 | 
								return fmt.Errorf("failed to get listener for main ttrpc endpoint: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		serve(ctx, tl, server.ServeTTRPC)
 | 
							serve(ctx, tl, server.ServeTTRPC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if config.GRPC.TCPAddress != "" {
 | 
							if config.GRPC.TCPAddress != "" {
 | 
				
			||||||
			l, err := net.Listen("tcp", config.GRPC.TCPAddress)
 | 
								l, err := net.Listen("tcp", config.GRPC.TCPAddress)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrapf(err, "failed to get listener for TCP grpc endpoint")
 | 
									return fmt.Errorf("failed to get listener for TCP grpc endpoint: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			serve(ctx, l, server.ServeTCP)
 | 
								serve(ctx, l, server.ServeTCP)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// setup the main grpc endpoint
 | 
							// setup the main grpc endpoint
 | 
				
			||||||
		l, err := sys.GetLocalListener(config.GRPC.Address, config.GRPC.UID, config.GRPC.GID)
 | 
							l, err := sys.GetLocalListener(config.GRPC.Address, config.GRPC.UID, config.GRPC.GID)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to get listener for main endpoint")
 | 
								return fmt.Errorf("failed to get listener for main endpoint: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		serve(ctx, l, server.ServeGRPC)
 | 
							serve(ctx, l, server.ServeGRPC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -364,7 +363,7 @@ func setLogFormat(config *srvconfig.Config) error {
 | 
				
			|||||||
			TimestampFormat: log.RFC3339NanoFixed,
 | 
								TimestampFormat: log.RFC3339NanoFixed,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return errors.Errorf("unknown log format: %s", f)
 | 
							return fmt.Errorf("unknown log format: %s", f)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package command
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -28,7 +29,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/namespaces"
 | 
						"github.com/containerd/containerd/namespaces"
 | 
				
			||||||
	"github.com/containerd/containerd/pkg/dialer"
 | 
						"github.com/containerd/containerd/pkg/dialer"
 | 
				
			||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
	"google.golang.org/grpc"
 | 
						"google.golang.org/grpc"
 | 
				
			||||||
	"google.golang.org/grpc/backoff"
 | 
						"google.golang.org/grpc/backoff"
 | 
				
			||||||
@@ -52,7 +52,7 @@ var publishCommand = cli.Command{
 | 
				
			|||||||
		ctx := namespaces.WithNamespace(gocontext.Background(), context.String("namespace"))
 | 
							ctx := namespaces.WithNamespace(gocontext.Background(), context.String("namespace"))
 | 
				
			||||||
		topic := context.String("topic")
 | 
							topic := context.String("topic")
 | 
				
			||||||
		if topic == "" {
 | 
							if topic == "" {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrInvalidArgument, "topic required to publish event")
 | 
								return fmt.Errorf("topic required to publish event: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		payload, err := getEventPayload(os.Stdin)
 | 
							payload, err := getEventPayload(os.Stdin)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -87,7 +87,7 @@ func getEventPayload(r io.Reader) (*types.Any, error) {
 | 
				
			|||||||
func connectEvents(address string) (eventsapi.EventsClient, error) {
 | 
					func connectEvents(address string) (eventsapi.EventsClient, error) {
 | 
				
			||||||
	conn, err := connect(address, dialer.ContextDialer)
 | 
						conn, err := connect(address, dialer.ContextDialer)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrapf(err, "failed to dial %q", address)
 | 
							return nil, fmt.Errorf("failed to dial %q: %w", address, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return eventsapi.NewEventsClient(conn), nil
 | 
						return eventsapi.NewEventsClient(conn), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -109,7 +109,7 @@ func connect(address string, d func(gocontext.Context, string) (net.Conn, error)
 | 
				
			|||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
	conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
 | 
						conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrapf(err, "failed to dial %q", address)
 | 
							return nil, fmt.Errorf("failed to dial %q: %w", address, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return conn, nil
 | 
						return conn, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/services/server"
 | 
						"github.com/containerd/containerd/services/server"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
@@ -218,7 +217,7 @@ func registerUnregisterService(root string) (bool, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if unregisterServiceFlag {
 | 
						if unregisterServiceFlag {
 | 
				
			||||||
		if registerServiceFlag {
 | 
							if registerServiceFlag {
 | 
				
			||||||
			return true, errors.Wrap(errdefs.ErrInvalidArgument, "--register-service and --unregister-service cannot be used together")
 | 
								return true, fmt.Errorf("--register-service and --unregister-service cannot be used together: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return true, unregisterService()
 | 
							return true, unregisterService()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -242,7 +241,7 @@ func registerUnregisterService(root string) (bool, error) {
 | 
				
			|||||||
		// and we want to make sure stderr goes to the panic file.
 | 
							// and we want to make sure stderr goes to the panic file.
 | 
				
			||||||
		r, _, err := allocConsole.Call()
 | 
							r, _, err := allocConsole.Call()
 | 
				
			||||||
		if r == 0 && err != nil {
 | 
							if r == 0 && err != nil {
 | 
				
			||||||
			return true, fmt.Errorf("error allocating conhost: %s", err)
 | 
								return true, fmt.Errorf("error allocating conhost: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := initPanicFile(filepath.Join(root, "panic.log")); err != nil {
 | 
							if err := initPanicFile(filepath.Join(root, "panic.log")); err != nil {
 | 
				
			||||||
@@ -253,7 +252,7 @@ func registerUnregisterService(root string) (bool, error) {
 | 
				
			|||||||
		if logFileFlag != "" {
 | 
							if logFileFlag != "" {
 | 
				
			||||||
			f, err := os.OpenFile(logFileFlag, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 | 
								f, err := os.OpenFile(logFileFlag, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return true, errors.Wrapf(err, "open log file %q", logFileFlag)
 | 
									return true, fmt.Errorf("open log file %q: %w", logFileFlag, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			logOutput = f
 | 
								logOutput = f
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,12 +17,12 @@
 | 
				
			|||||||
package containers
 | 
					package containers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,7 +88,7 @@ var checkpointCommand = cli.Command{
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			defer func() {
 | 
								defer func() {
 | 
				
			||||||
				if err := task.Resume(ctx); err != nil {
 | 
									if err := task.Resume(ctx); err != nil {
 | 
				
			||||||
					fmt.Println(errors.Wrap(err, "error resuming task"))
 | 
										fmt.Println(fmt.Errorf("error resuming task: %w", err))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}()
 | 
								}()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,17 +65,17 @@ var createCommand = cli.Command{
 | 
				
			|||||||
		if config {
 | 
							if config {
 | 
				
			||||||
			id = context.Args().First()
 | 
								id = context.Args().First()
 | 
				
			||||||
			if context.NArg() > 1 {
 | 
								if context.NArg() > 1 {
 | 
				
			||||||
				return errors.Wrap(errdefs.ErrInvalidArgument, "with spec config file, only container id should be provided")
 | 
									return fmt.Errorf("with spec config file, only container id should be provided: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			id = context.Args().Get(1)
 | 
								id = context.Args().Get(1)
 | 
				
			||||||
			ref = context.Args().First()
 | 
								ref = context.Args().First()
 | 
				
			||||||
			if ref == "" {
 | 
								if ref == "" {
 | 
				
			||||||
				return errors.Wrap(errdefs.ErrInvalidArgument, "image ref must be provided")
 | 
									return fmt.Errorf("image ref must be provided: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if id == "" {
 | 
							if id == "" {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrInvalidArgument, "container id must be provided")
 | 
								return fmt.Errorf("container id must be provided: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		client, ctx, cancel, err := commands.NewClient(context)
 | 
							client, ctx, cancel, err := commands.NewClient(context)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -169,7 +168,7 @@ var deleteCommand = cli.Command{
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if context.NArg() == 0 {
 | 
							if context.NArg() == 0 {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrInvalidArgument, "must specify at least one container to delete")
 | 
								return fmt.Errorf("must specify at least one container to delete: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, arg := range context.Args() {
 | 
							for _, arg := range context.Args() {
 | 
				
			||||||
			if err := deleteContainer(ctx, client, arg, deleteOpts...); err != nil {
 | 
								if err := deleteContainer(ctx, client, arg, deleteOpts...); err != nil {
 | 
				
			||||||
@@ -215,7 +214,7 @@ var setLabelsCommand = cli.Command{
 | 
				
			|||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		containerID, labels := commands.ObjectWithLabelArgs(context)
 | 
							containerID, labels := commands.ObjectWithLabelArgs(context)
 | 
				
			||||||
		if containerID == "" {
 | 
							if containerID == "" {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrInvalidArgument, "container id must be provided")
 | 
								return fmt.Errorf("container id must be provided: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		client, ctx, cancel, err := commands.NewClient(context)
 | 
							client, ctx, cancel, err := commands.NewClient(context)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -257,7 +256,7 @@ var infoCommand = cli.Command{
 | 
				
			|||||||
	Action: func(context *cli.Context) error {
 | 
						Action: func(context *cli.Context) error {
 | 
				
			||||||
		id := context.Args().First()
 | 
							id := context.Args().First()
 | 
				
			||||||
		if id == "" {
 | 
							if id == "" {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrInvalidArgument, "container id must be provided")
 | 
								return fmt.Errorf("container id must be provided: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		client, ctx, cancel, err := commands.NewClient(context)
 | 
							client, ctx, cancel, err := commands.NewClient(context)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,12 @@
 | 
				
			|||||||
package containers
 | 
					package containers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/cio"
 | 
						"github.com/containerd/containerd/cio"
 | 
				
			||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
package content
 | 
					package content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -31,7 +32,6 @@ import (
 | 
				
			|||||||
	units "github.com/docker/go-units"
 | 
						units "github.com/docker/go-units"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
package images
 | 
					package images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
@@ -24,7 +25,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/images/converter/uncompress"
 | 
						"github.com/containerd/containerd/images/converter/uncompress"
 | 
				
			||||||
	"github.com/containerd/containerd/platforms"
 | 
						"github.com/containerd/containerd/platforms"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -74,7 +74,7 @@ When '--all-platforms' is given all images in a manifest list must be available.
 | 
				
			|||||||
				for _, ps := range pss {
 | 
									for _, ps := range pss {
 | 
				
			||||||
					p, err := platforms.Parse(ps)
 | 
										p, err := platforms.Parse(ps)
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						return errors.Wrapf(err, "invalid platform %q", ps)
 | 
											return fmt.Errorf("invalid platform %q: %w", ps, err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					all = append(all, p)
 | 
										all = append(all, p)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,8 @@
 | 
				
			|||||||
package images
 | 
					package images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,7 +26,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/images/archive"
 | 
						"github.com/containerd/containerd/images/archive"
 | 
				
			||||||
	"github.com/containerd/containerd/platforms"
 | 
						"github.com/containerd/containerd/platforms"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -73,7 +74,7 @@ When '--all-platforms' is given all images in a manifest list must be available.
 | 
				
			|||||||
			for _, ps := range pss {
 | 
								for _, ps := range pss {
 | 
				
			||||||
				p, err := platforms.Parse(ps)
 | 
									p, err := platforms.Parse(ps)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return errors.Wrapf(err, "invalid platform %q", ps)
 | 
										return fmt.Errorf("invalid platform %q: %w", ps, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				all = append(all, p)
 | 
									all = append(all, p)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
package images
 | 
					package images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
@@ -29,7 +30,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/containerd/containerd/pkg/progress"
 | 
						"github.com/containerd/containerd/pkg/progress"
 | 
				
			||||||
	"github.com/containerd/containerd/platforms"
 | 
						"github.com/containerd/containerd/platforms"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -82,7 +82,7 @@ var listCommand = cli.Command{
 | 
				
			|||||||
		)
 | 
							)
 | 
				
			||||||
		imageList, err := imageStore.List(ctx, filters...)
 | 
							imageList, err := imageStore.List(ctx, filters...)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to list images")
 | 
								return fmt.Errorf("failed to list images: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if quiet {
 | 
							if quiet {
 | 
				
			||||||
			for _, image := range imageList {
 | 
								for _, image := range imageList {
 | 
				
			||||||
@@ -224,7 +224,7 @@ var checkCommand = cli.Command{
 | 
				
			|||||||
		args := []string(context.Args())
 | 
							args := []string(context.Args())
 | 
				
			||||||
		imageList, err := client.ListImages(ctx, args...)
 | 
							imageList, err := client.ListImages(ctx, args...)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed listing images")
 | 
								return fmt.Errorf("failed listing images: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(imageList) == 0 {
 | 
							if len(imageList) == 0 {
 | 
				
			||||||
			log.G(ctx).Debugf("no images found")
 | 
								log.G(ctx).Debugf("no images found")
 | 
				
			||||||
@@ -248,7 +248,7 @@ var checkCommand = cli.Command{
 | 
				
			|||||||
			available, required, present, missing, err := images.Check(ctx, contentStore, image.Target(), platforms.Default())
 | 
								available, required, present, missing, err := images.Check(ctx, contentStore, image.Target(), platforms.Default())
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				if exitErr == nil {
 | 
									if exitErr == nil {
 | 
				
			||||||
					exitErr = errors.Wrapf(err, "unable to check %v", image.Name())
 | 
										exitErr = fmt.Errorf("unable to check %v: %w", image.Name(), err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				log.G(ctx).WithError(err).Errorf("unable to check %v", image.Name())
 | 
									log.G(ctx).WithError(err).Errorf("unable to check %v", image.Name())
 | 
				
			||||||
				status = "error"
 | 
									status = "error"
 | 
				
			||||||
@@ -284,7 +284,7 @@ var checkCommand = cli.Command{
 | 
				
			|||||||
			unpacked, err := image.IsUnpacked(ctx, context.String("snapshotter"))
 | 
								unpacked, err := image.IsUnpacked(ctx, context.String("snapshotter"))
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				if exitErr == nil {
 | 
									if exitErr == nil {
 | 
				
			||||||
					exitErr = errors.Wrapf(err, "unable to check unpack for %v", image.Name())
 | 
										exitErr = fmt.Errorf("unable to check unpack for %v: %w", image.Name(), err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				log.G(ctx).WithError(err).Errorf("unable to check unpack for %v", image.Name())
 | 
									log.G(ctx).WithError(err).Errorf("unable to check unpack for %v", image.Name())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -340,7 +340,7 @@ var removeCommand = cli.Command{
 | 
				
			|||||||
			if err := imageStore.Delete(ctx, target, opts...); err != nil {
 | 
								if err := imageStore.Delete(ctx, target, opts...); err != nil {
 | 
				
			||||||
				if !errdefs.IsNotFound(err) {
 | 
									if !errdefs.IsNotFound(err) {
 | 
				
			||||||
					if exitErr == nil {
 | 
										if exitErr == nil {
 | 
				
			||||||
						exitErr = errors.Wrapf(err, "unable to delete %v", target)
 | 
											exitErr = fmt.Errorf("unable to delete %v: %w", target, err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					log.G(ctx).WithError(err).Errorf("unable to delete %v", target)
 | 
										log.G(ctx).WithError(err).Errorf("unable to delete %v", target)
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/mount"
 | 
						"github.com/containerd/containerd/mount"
 | 
				
			||||||
	"github.com/containerd/containerd/platforms"
 | 
						"github.com/containerd/containerd/platforms"
 | 
				
			||||||
	"github.com/opencontainers/image-spec/identity"
 | 
						"github.com/opencontainers/image-spec/identity"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,7 +92,7 @@ When you are done, use the unmount command.
 | 
				
			|||||||
		ps := context.String("platform")
 | 
							ps := context.String("platform")
 | 
				
			||||||
		p, err := platforms.Parse(ps)
 | 
							p, err := platforms.Parse(ps)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "unable to parse platform %s", ps)
 | 
								return fmt.Errorf("unable to parse platform %s: %w", ps, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		img, err := client.ImageService().Get(ctx, ref)
 | 
							img, err := client.ImageService().Get(ctx, ref)
 | 
				
			||||||
@@ -103,7 +102,7 @@ When you are done, use the unmount command.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		i := containerd.NewImageWithPlatform(client, img, platforms.Only(p))
 | 
							i := containerd.NewImageWithPlatform(client, img, platforms.Only(p))
 | 
				
			||||||
		if err := i.Unpack(ctx, snapshotter); err != nil {
 | 
							if err := i.Unpack(ctx, snapshotter); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "error unpacking image")
 | 
								return fmt.Errorf("error unpacking image: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		diffIDs, err := i.RootFS(ctx)
 | 
							diffIDs, err := i.RootFS(ctx)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/platforms"
 | 
						"github.com/containerd/containerd/platforms"
 | 
				
			||||||
	"github.com/opencontainers/image-spec/identity"
 | 
						"github.com/opencontainers/image-spec/identity"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -106,13 +105,13 @@ command. As part of this process, we do the following:
 | 
				
			|||||||
		if context.Bool("all-platforms") {
 | 
							if context.Bool("all-platforms") {
 | 
				
			||||||
			p, err = images.Platforms(ctx, client.ContentStore(), img.Target)
 | 
								p, err = images.Platforms(ctx, client.ContentStore(), img.Target)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "unable to resolve image platforms")
 | 
									return fmt.Errorf("unable to resolve image platforms: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			for _, s := range context.StringSlice("platform") {
 | 
								for _, s := range context.StringSlice("platform") {
 | 
				
			||||||
				ps, err := platforms.Parse(s)
 | 
									ps, err := platforms.Parse(s)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return errors.Wrapf(err, "unable to parse platform %s", s)
 | 
										return fmt.Errorf("unable to parse platform %s: %w", s, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				p = append(p, ps)
 | 
									p = append(p, ps)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@ package images
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http/httptrace"
 | 
						"net/http/httptrace"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -35,7 +37,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/remotes/docker"
 | 
						"github.com/containerd/containerd/remotes/docker"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
	"golang.org/x/sync/errgroup"
 | 
						"golang.org/x/sync/errgroup"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -88,7 +89,7 @@ var pushCommand = cli.Command{
 | 
				
			|||||||
		if manifest := context.String("manifest"); manifest != "" {
 | 
							if manifest := context.String("manifest"); manifest != "" {
 | 
				
			||||||
			desc.Digest, err = digest.Parse(manifest)
 | 
								desc.Digest, err = digest.Parse(manifest)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "invalid manifest digest")
 | 
									return fmt.Errorf("invalid manifest digest: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			desc.MediaType = context.String("manifest-type")
 | 
								desc.MediaType = context.String("manifest-type")
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@@ -97,14 +98,14 @@ var pushCommand = cli.Command{
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			img, err := client.ImageService().Get(ctx, local)
 | 
								img, err := client.ImageService().Get(ctx, local)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "unable to resolve image to manifest")
 | 
									return fmt.Errorf("unable to resolve image to manifest: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			desc = img.Target
 | 
								desc = img.Target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if pss := context.StringSlice("platform"); len(pss) == 1 {
 | 
								if pss := context.StringSlice("platform"); len(pss) == 1 {
 | 
				
			||||||
				p, err := platforms.Parse(pss[0])
 | 
									p, err := platforms.Parse(pss[0])
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return errors.Wrapf(err, "invalid platform %q", pss[0])
 | 
										return fmt.Errorf("invalid platform %q: %w", pss[0], err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				cs := client.ContentStore()
 | 
									cs := client.ContentStore()
 | 
				
			||||||
@@ -113,7 +114,7 @@ var pushCommand = cli.Command{
 | 
				
			|||||||
					for _, manifest := range manifests {
 | 
										for _, manifest := range manifests {
 | 
				
			||||||
						if manifest.Platform != nil && matcher.Match(*manifest.Platform) {
 | 
											if manifest.Platform != nil && matcher.Match(*manifest.Platform) {
 | 
				
			||||||
							if _, err := images.Children(ctx, cs, manifest); err != nil {
 | 
												if _, err := images.Children(ctx, cs, manifest); err != nil {
 | 
				
			||||||
								return errors.Wrap(err, "no matching manifest")
 | 
													return fmt.Errorf("no matching manifest: %w", err)
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
							desc = manifest
 | 
												desc = manifest
 | 
				
			||||||
							break
 | 
												break
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/leases"
 | 
						"github.com/containerd/containerd/leases"
 | 
				
			||||||
	"github.com/containerd/containerd/mount"
 | 
						"github.com/containerd/containerd/mount"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,10 +59,10 @@ var unmountCommand = cli.Command{
 | 
				
			|||||||
			snapshotter := context.String("snapshotter")
 | 
								snapshotter := context.String("snapshotter")
 | 
				
			||||||
			s := client.SnapshotService(snapshotter)
 | 
								s := client.SnapshotService(snapshotter)
 | 
				
			||||||
			if err := client.LeasesService().Delete(ctx, leases.Lease{ID: target}); err != nil && !errdefs.IsNotFound(err) {
 | 
								if err := client.LeasesService().Delete(ctx, leases.Lease{ID: target}); err != nil && !errdefs.IsNotFound(err) {
 | 
				
			||||||
				return errors.Wrap(err, "error deleting lease")
 | 
									return fmt.Errorf("error deleting lease: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if err := s.Remove(ctx, target); err != nil && !errdefs.IsNotFound(err) {
 | 
								if err := s.Remove(ctx, target); err != nil && !errdefs.IsNotFound(err) {
 | 
				
			||||||
				return errors.Wrap(err, "error removing snapshot")
 | 
									return fmt.Errorf("error removing snapshot: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
	"github.com/containerd/containerd/leases"
 | 
						"github.com/containerd/containerd/leases"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,7 +68,7 @@ var listCommand = cli.Command{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		leaseList, err := ls.List(ctx, filters...)
 | 
							leaseList, err := ls.List(ctx, filters...)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to list leases")
 | 
								return fmt.Errorf("failed to list leases: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if quiet {
 | 
							if quiet {
 | 
				
			||||||
			for _, l := range leaseList {
 | 
								for _, l := range leaseList {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
package namespaces
 | 
					package namespaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
@@ -26,7 +27,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -167,7 +167,7 @@ var removeCommand = cli.Command{
 | 
				
			|||||||
			if err := namespaces.Delete(ctx, target, opts...); err != nil {
 | 
								if err := namespaces.Delete(ctx, target, opts...); err != nil {
 | 
				
			||||||
				if !errdefs.IsNotFound(err) {
 | 
									if !errdefs.IsNotFound(err) {
 | 
				
			||||||
					if exitErr == nil {
 | 
										if exitErr == nil {
 | 
				
			||||||
						exitErr = errors.Wrapf(err, "unable to delete %v", target)
 | 
											exitErr = fmt.Errorf("unable to delete %v: %w", target, err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					log.G(ctx).WithError(err).Errorf("unable to delete %v", target)
 | 
										log.G(ctx).WithError(err).Errorf("unable to delete %v", target)
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,8 @@
 | 
				
			|||||||
package oci
 | 
					package oci
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
@@ -43,7 +44,7 @@ var defaultSpecCommand = cli.Command{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		spec, err := oci.GenerateSpec(ctx, nil, &containers.Container{})
 | 
							spec, err := oci.GenerateSpec(ctx, nil, &containers.Container{})
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to generate spec")
 | 
								return fmt.Errorf("failed to generate spec: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		commands.PrintAsJSON(spec)
 | 
							commands.PrintAsJSON(spec)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,6 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/defaults"
 | 
						"github.com/containerd/containerd/defaults"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -183,7 +182,7 @@ func httpGetRequest(client *http.Client, request string) (io.ReadCloser, error)
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if resp.StatusCode != 200 {
 | 
						if resp.StatusCode != 200 {
 | 
				
			||||||
		return nil, errors.Errorf("http get failed with status: %s", resp.Status)
 | 
							return nil, fmt.Errorf("http get failed with status: %s", resp.Status)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return resp.Body, nil
 | 
						return resp.Body, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ import (
 | 
				
			|||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
	"crypto/tls"
 | 
						"crypto/tls"
 | 
				
			||||||
	"crypto/x509"
 | 
						"crypto/x509"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
@@ -34,7 +35,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/remotes"
 | 
						"github.com/containerd/containerd/remotes"
 | 
				
			||||||
	"github.com/containerd/containerd/remotes/docker"
 | 
						"github.com/containerd/containerd/remotes/docker"
 | 
				
			||||||
	"github.com/containerd/containerd/remotes/docker/config"
 | 
						"github.com/containerd/containerd/remotes/docker/config"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,12 +46,12 @@ func passwordPrompt() (string, error) {
 | 
				
			|||||||
	defer c.Reset()
 | 
						defer c.Reset()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := c.DisableEcho(); err != nil {
 | 
						if err := c.DisableEcho(); err != nil {
 | 
				
			||||||
		return "", errors.Wrap(err, "failed to disable echo")
 | 
							return "", fmt.Errorf("failed to disable echo: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	line, _, err := bufio.NewReader(c).ReadLine()
 | 
						line, _, err := bufio.NewReader(c).ReadLine()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", errors.Wrap(err, "failed to read line")
 | 
							return "", fmt.Errorf("failed to read line: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return string(line), nil
 | 
						return string(line), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -126,7 +126,7 @@ func resolverDefaultTLS(clicontext *cli.Context) (*tls.Config, error) {
 | 
				
			|||||||
	if tlsRootPath := clicontext.String("tlscacert"); tlsRootPath != "" {
 | 
						if tlsRootPath := clicontext.String("tlscacert"); tlsRootPath != "" {
 | 
				
			||||||
		tlsRootData, err := os.ReadFile(tlsRootPath)
 | 
							tlsRootData, err := os.ReadFile(tlsRootPath)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "failed to read %q", tlsRootPath)
 | 
								return nil, fmt.Errorf("failed to read %q: %w", tlsRootPath, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		config.RootCAs = x509.NewCertPool()
 | 
							config.RootCAs = x509.NewCertPool()
 | 
				
			||||||
@@ -143,7 +143,7 @@ func resolverDefaultTLS(clicontext *cli.Context) (*tls.Config, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		keyPair, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath)
 | 
							keyPair, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "failed to load TLS client credentials (cert=%q, key=%q)", tlsCertPath, tlsKeyPath)
 | 
								return nil, fmt.Errorf("failed to load TLS client credentials (cert=%q, key=%q): %w", tlsCertPath, tlsKeyPath, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		config.Certificates = []tls.Certificate{keyPair}
 | 
							config.Certificates = []tls.Certificate{keyPair}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -161,7 +161,7 @@ type DebugTransport struct {
 | 
				
			|||||||
func (t DebugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
					func (t DebugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
	in, err := httputil.DumpRequest(req, true)
 | 
						in, err := httputil.DumpRequest(req, true)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to dump request")
 | 
							return nil, fmt.Errorf("failed to dump request: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := t.writer.Write(in); err != nil {
 | 
						if _, err := t.writer.Write(in); err != nil {
 | 
				
			||||||
@@ -175,7 +175,7 @@ func (t DebugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	out, err := httputil.DumpResponse(resp, true)
 | 
						out, err := httputil.DumpResponse(resp, true)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to dump response")
 | 
							return nil, fmt.Errorf("failed to dump response: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := t.writer.Write(out); err != nil {
 | 
						if _, err := t.writer.Write(out); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
	"encoding/csv"
 | 
						"encoding/csv"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,7 +35,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/oci"
 | 
						"github.com/containerd/containerd/oci"
 | 
				
			||||||
	gocni "github.com/containerd/go-cni"
 | 
						gocni "github.com/containerd/go-cni"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ package run
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
@@ -39,7 +40,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/runtime/v2/runc/options"
 | 
						"github.com/containerd/containerd/runtime/v2/runc/options"
 | 
				
			||||||
	"github.com/containerd/containerd/snapshots"
 | 
						"github.com/containerd/containerd/snapshots"
 | 
				
			||||||
	"github.com/opencontainers/runtime-spec/specs-go"
 | 
						"github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -204,7 +204,7 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
 | 
				
			|||||||
		if context.Bool("net-host") {
 | 
							if context.Bool("net-host") {
 | 
				
			||||||
			hostname, err := os.Hostname()
 | 
								hostname, err := os.Hostname()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, errors.Wrap(err, "get hostname")
 | 
									return nil, fmt.Errorf("get hostname: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			opts = append(opts,
 | 
								opts = append(opts,
 | 
				
			||||||
				oci.WithHostNamespace(specs.NetworkNamespace),
 | 
									oci.WithHostNamespace(specs.NetworkNamespace),
 | 
				
			||||||
@@ -417,15 +417,15 @@ func parseIDMapping(mapping string) (specs.LinuxIDMapping, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	cID, err := strconv.ParseUint(parts[0], 0, 32)
 | 
						cID, err := strconv.ParseUint(parts[0], 0, 32)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid container id for user namespace remapping")
 | 
							return specs.LinuxIDMapping{}, fmt.Errorf("invalid container id for user namespace remapping: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	hID, err := strconv.ParseUint(parts[1], 0, 32)
 | 
						hID, err := strconv.ParseUint(parts[1], 0, 32)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid host id for user namespace remapping")
 | 
							return specs.LinuxIDMapping{}, fmt.Errorf("invalid host id for user namespace remapping: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	size, err := strconv.ParseUint(parts[2], 0, 32)
 | 
						size, err := strconv.ParseUint(parts[2], 0, 32)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid size for user namespace remapping")
 | 
							return specs.LinuxIDMapping{}, fmt.Errorf("invalid size for user namespace remapping: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return specs.LinuxIDMapping{
 | 
						return specs.LinuxIDMapping{
 | 
				
			||||||
		ContainerID: uint32(cID),
 | 
							ContainerID: uint32(cID),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package run
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
 | 
						"github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
 | 
				
			||||||
	"github.com/containerd/console"
 | 
						"github.com/containerd/console"
 | 
				
			||||||
@@ -26,7 +27,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/oci"
 | 
						"github.com/containerd/containerd/oci"
 | 
				
			||||||
	"github.com/containerd/containerd/pkg/netns"
 | 
						"github.com/containerd/containerd/pkg/netns"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ package shim
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -36,7 +37,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	ptypes "github.com/gogo/protobuf/types"
 | 
						ptypes "github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/opencontainers/runtime-spec/specs-go"
 | 
						"github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package snapshots
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -35,7 +36,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/snapshots"
 | 
						"github.com/containerd/containerd/snapshots"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -262,7 +262,7 @@ var removeCommand = cli.Command{
 | 
				
			|||||||
		for _, key := range context.Args() {
 | 
							for _, key := range context.Args() {
 | 
				
			||||||
			err = snapshotter.Remove(ctx, key)
 | 
								err = snapshotter.Remove(ctx, key)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrapf(err, "failed to remove %q", key)
 | 
									return fmt.Errorf("failed to remove %q: %w", key, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
package tasks
 | 
					package tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
@@ -24,7 +25,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/plugin"
 | 
						"github.com/containerd/containerd/plugin"
 | 
				
			||||||
	"github.com/containerd/containerd/runtime/linux/runctypes"
 | 
						"github.com/containerd/containerd/runtime/linux/runctypes"
 | 
				
			||||||
	"github.com/containerd/containerd/runtime/v2/runc/options"
 | 
						"github.com/containerd/containerd/runtime/v2/runc/options"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,10 +17,11 @@
 | 
				
			|||||||
package tasks
 | 
					package tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
	"github.com/moby/sys/signal"
 | 
						"github.com/moby/sys/signal"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,13 +17,13 @@
 | 
				
			|||||||
package tasks
 | 
					package tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"text/tabwriter"
 | 
						"text/tabwriter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,12 @@
 | 
				
			|||||||
package tasks
 | 
					package tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/console"
 | 
						"github.com/containerd/console"
 | 
				
			||||||
	"github.com/containerd/containerd"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/cio"
 | 
						"github.com/containerd/containerd/cio"
 | 
				
			||||||
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						"github.com/containerd/containerd/cmd/ctr/commands"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ package tasks
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/signal"
 | 
						"os/signal"
 | 
				
			||||||
@@ -29,7 +30,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/cio"
 | 
						"github.com/containerd/containerd/cio"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
	"golang.org/x/sys/unix"
 | 
						"golang.org/x/sys/unix"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package tasks
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	gocontext "context"
 | 
						gocontext "context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +26,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/cio"
 | 
						"github.com/containerd/containerd/cio"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								container.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								container.go
									
									
									
									
									
								
							@@ -19,6 +19,7 @@ package containerd
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -38,7 +39,6 @@ import (
 | 
				
			|||||||
	ver "github.com/opencontainers/image-spec/specs-go"
 | 
						ver "github.com/opencontainers/image-spec/specs-go"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/opencontainers/selinux/go-selinux/label"
 | 
						"github.com/opencontainers/selinux/go-selinux/label"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -173,7 +173,7 @@ func (c *container) Spec(ctx context.Context) (*oci.Spec, error) {
 | 
				
			|||||||
// an error is returned if the container has running tasks
 | 
					// an error is returned if the container has running tasks
 | 
				
			||||||
func (c *container) Delete(ctx context.Context, opts ...DeleteOpts) error {
 | 
					func (c *container) Delete(ctx context.Context, opts ...DeleteOpts) error {
 | 
				
			||||||
	if _, err := c.loadTask(ctx, nil); err == nil {
 | 
						if _, err := c.loadTask(ctx, nil); err == nil {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrFailedPrecondition, "cannot delete running task %v", c.id)
 | 
							return fmt.Errorf("cannot delete running task %v: %w", c.id, errdefs.ErrFailedPrecondition)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r, err := c.get(ctx)
 | 
						r, err := c.get(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -198,11 +198,11 @@ func (c *container) Image(ctx context.Context) (Image, error) {
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if r.Image == "" {
 | 
						if r.Image == "" {
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrNotFound, "container not created from an image")
 | 
							return nil, fmt.Errorf("container not created from an image: %w", errdefs.ErrNotFound)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	i, err := c.client.ImageService().Get(ctx, r.Image)
 | 
						i, err := c.client.ImageService().Get(ctx, r.Image)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrapf(err, "failed to get image %s for container", r.Image)
 | 
							return nil, fmt.Errorf("failed to get image %s for container: %w", r.Image, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NewImage(c.client, i), nil
 | 
						return NewImage(c.client, i), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -232,7 +232,7 @@ func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...N
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if r.SnapshotKey != "" {
 | 
						if r.SnapshotKey != "" {
 | 
				
			||||||
		if r.Snapshotter == "" {
 | 
							if r.Snapshotter == "" {
 | 
				
			||||||
			return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "unable to resolve rootfs mounts without snapshotter on container")
 | 
								return nil, fmt.Errorf("unable to resolve rootfs mounts without snapshotter on container: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// get the rootfs from the snapshotter and add it to the request
 | 
							// get the rootfs from the snapshotter and add it to the request
 | 
				
			||||||
@@ -391,7 +391,7 @@ func (c *container) loadTask(ctx context.Context, ioAttach cio.Attach) (Task, er
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		err = errdefs.FromGRPC(err)
 | 
							err = errdefs.FromGRPC(err)
 | 
				
			||||||
		if errdefs.IsNotFound(err) {
 | 
							if errdefs.IsNotFound(err) {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "no running task found")
 | 
								return nil, fmt.Errorf("no running task found: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package containerd
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,7 +32,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/runtime/v2/runc/options"
 | 
						"github.com/containerd/containerd/runtime/v2/runc/options"
 | 
				
			||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	imagespec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						imagespec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package containerd
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/containers"
 | 
						"github.com/containerd/containerd/containers"
 | 
				
			||||||
@@ -31,7 +32,6 @@ import (
 | 
				
			|||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/opencontainers/image-spec/identity"
 | 
						"github.com/opencontainers/image-spec/identity"
 | 
				
			||||||
	v1 "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						v1 "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DeleteOpts allows the caller to set options for the deletion of a container
 | 
					// DeleteOpts allows the caller to set options for the deletion of a container
 | 
				
			||||||
@@ -227,7 +227,7 @@ func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts
 | 
				
			|||||||
func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Container) error {
 | 
					func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Container) error {
 | 
				
			||||||
	if c.SnapshotKey != "" {
 | 
						if c.SnapshotKey != "" {
 | 
				
			||||||
		if c.Snapshotter == "" {
 | 
							if c.Snapshotter == "" {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs snapshot")
 | 
								return fmt.Errorf("container.Snapshotter must be set to cleanup rootfs snapshot: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		s, err := client.getSnapshotter(ctx, c.Snapshotter)
 | 
							s, err := client.getSnapshotter(ctx, c.Snapshotter)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -276,15 +276,15 @@ func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainer
 | 
				
			|||||||
func WithContainerExtension(name string, extension interface{}) NewContainerOpts {
 | 
					func WithContainerExtension(name string, extension interface{}) NewContainerOpts {
 | 
				
			||||||
	return func(ctx context.Context, client *Client, c *containers.Container) error {
 | 
						return func(ctx context.Context, client *Client, c *containers.Container) error {
 | 
				
			||||||
		if name == "" {
 | 
							if name == "" {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrInvalidArgument, "extension key must not be zero-length")
 | 
								return fmt.Errorf("extension key must not be zero-length: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		any, err := typeurl.MarshalAny(extension)
 | 
							any, err := typeurl.MarshalAny(extension)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			if errors.Is(err, typeurl.ErrNotFound) {
 | 
								if errors.Is(err, typeurl.ErrNotFound) {
 | 
				
			||||||
				return errors.Wrapf(err, "extension %q is not registered with the typeurl package, see `typeurl.Register`", name)
 | 
									return fmt.Errorf("extension %q is not registered with the typeurl package, see `typeurl.Register`: %w", name, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return errors.Wrap(err, "error marshalling extension")
 | 
								return fmt.Errorf("error marshalling extension: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if c.Extensions == nil {
 | 
							if c.Extensions == nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@ package containerd
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/containers"
 | 
						"github.com/containerd/containerd/containers"
 | 
				
			||||||
	"github.com/containerd/containerd/content"
 | 
						"github.com/containerd/containerd/content"
 | 
				
			||||||
@@ -26,7 +28,6 @@ import (
 | 
				
			|||||||
	ptypes "github.com/gogo/protobuf/types"
 | 
						ptypes "github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/opencontainers/image-spec/identity"
 | 
						"github.com/opencontainers/image-spec/identity"
 | 
				
			||||||
	imagespec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						imagespec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -92,7 +93,7 @@ func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoi
 | 
				
			|||||||
			store := client.ContentStore()
 | 
								store := client.ContentStore()
 | 
				
			||||||
			data, err := content.ReadBlob(ctx, store, *m)
 | 
								data, err := content.ReadBlob(ctx, store, *m)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "unable to read checkpoint runtime")
 | 
									return fmt.Errorf("unable to read checkpoint runtime: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if err := proto.Unmarshal(data, &options); err != nil {
 | 
								if err := proto.Unmarshal(data, &options); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
@@ -117,7 +118,7 @@ func WithRestoreSpec(ctx context.Context, id string, client *Client, checkpoint
 | 
				
			|||||||
		store := client.ContentStore()
 | 
							store := client.ContentStore()
 | 
				
			||||||
		data, err := content.ReadBlob(ctx, store, *m)
 | 
							data, err := content.ReadBlob(ctx, store, *m)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "unable to read checkpoint config")
 | 
								return fmt.Errorf("unable to read checkpoint config: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		var any ptypes.Any
 | 
							var any ptypes.Any
 | 
				
			||||||
		if err := proto.Unmarshal(data, &any); err != nil {
 | 
							if err := proto.Unmarshal(data, &any); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@ package content
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -26,7 +28,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/opencontainers/go-digest"
 | 
						"github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var bufPool = sync.Pool{
 | 
					var bufPool = sync.Pool{
 | 
				
			||||||
@@ -76,7 +77,7 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, desc o
 | 
				
			|||||||
	cw, err := OpenWriter(ctx, cs, WithRef(ref), WithDescriptor(desc))
 | 
						cw, err := OpenWriter(ctx, cs, WithRef(ref), WithDescriptor(desc))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if !errdefs.IsAlreadyExists(err) {
 | 
							if !errdefs.IsAlreadyExists(err) {
 | 
				
			||||||
			return errors.Wrap(err, "failed to open writer")
 | 
								return fmt.Errorf("failed to open writer: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil // all ready present
 | 
							return nil // all ready present
 | 
				
			||||||
@@ -133,28 +134,28 @@ func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, er
 | 
				
			|||||||
func Copy(ctx context.Context, cw Writer, r io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
 | 
					func Copy(ctx context.Context, cw Writer, r io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
 | 
				
			||||||
	ws, err := cw.Status()
 | 
						ws, err := cw.Status()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to get status")
 | 
							return fmt.Errorf("failed to get status: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ws.Offset > 0 {
 | 
						if ws.Offset > 0 {
 | 
				
			||||||
		r, err = seekReader(r, ws.Offset, size)
 | 
							r, err = seekReader(r, ws.Offset, size)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "unable to resume write to %v", ws.Ref)
 | 
								return fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	copied, err := copyWithBuffer(cw, r)
 | 
						copied, err := copyWithBuffer(cw, r)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to copy")
 | 
							return fmt.Errorf("failed to copy: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if size != 0 && copied < size-ws.Offset {
 | 
						if size != 0 && copied < size-ws.Offset {
 | 
				
			||||||
		// Short writes would return its own error, this indicates a read failure
 | 
							// Short writes would return its own error, this indicates a read failure
 | 
				
			||||||
		return errors.Wrapf(io.ErrUnexpectedEOF, "failed to read expected number of bytes")
 | 
							return fmt.Errorf("failed to read expected number of bytes: %w", io.ErrUnexpectedEOF)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := cw.Commit(ctx, size, expected, opts...); err != nil {
 | 
						if err := cw.Commit(ctx, size, expected, opts...); err != nil {
 | 
				
			||||||
		if !errdefs.IsAlreadyExists(err) {
 | 
							if !errdefs.IsAlreadyExists(err) {
 | 
				
			||||||
			return errors.Wrapf(err, "failed commit on ref %q", ws.Ref)
 | 
								return fmt.Errorf("failed commit on ref %q: %w", ws.Ref, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -171,11 +172,11 @@ func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	copied, err := copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n))
 | 
						copied, err := copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to copy")
 | 
							return fmt.Errorf("failed to copy: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if copied < n {
 | 
						if copied < n {
 | 
				
			||||||
		// Short writes would return its own error, this indicates a read failure
 | 
							// Short writes would return its own error, this indicates a read failure
 | 
				
			||||||
		return errors.Wrap(io.ErrUnexpectedEOF, "failed to read expected number of bytes")
 | 
							return fmt.Errorf("failed to read expected number of bytes: %w", io.ErrUnexpectedEOF)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -189,13 +190,13 @@ func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error {
 | 
				
			|||||||
func CopyReader(cw Writer, r io.Reader) (int64, error) {
 | 
					func CopyReader(cw Writer, r io.Reader) (int64, error) {
 | 
				
			||||||
	ws, err := cw.Status()
 | 
						ws, err := cw.Status()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, errors.Wrap(err, "failed to get status")
 | 
							return 0, fmt.Errorf("failed to get status: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ws.Offset > 0 {
 | 
						if ws.Offset > 0 {
 | 
				
			||||||
		r, err = seekReader(r, ws.Offset, 0)
 | 
							r, err = seekReader(r, ws.Offset, 0)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return 0, errors.Wrapf(err, "unable to resume write to %v", ws.Ref)
 | 
								return 0, fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -211,7 +212,7 @@ func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
 | 
				
			|||||||
	if ok {
 | 
						if ok {
 | 
				
			||||||
		nn, err := seeker.Seek(offset, io.SeekStart)
 | 
							nn, err := seeker.Seek(offset, io.SeekStart)
 | 
				
			||||||
		if nn != offset {
 | 
							if nn != offset {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "failed to seek to offset %v", offset)
 | 
								return nil, fmt.Errorf("failed to seek to offset %v: %w", offset, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -231,7 +232,7 @@ func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
 | 
				
			|||||||
	// well then, let's just discard up to the offset
 | 
						// well then, let's just discard up to the offset
 | 
				
			||||||
	n, err := copyWithBuffer(io.Discard, io.LimitReader(r, offset))
 | 
						n, err := copyWithBuffer(io.Discard, io.LimitReader(r, offset))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to discard to offset")
 | 
							return nil, fmt.Errorf("failed to discard to offset: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if n != offset {
 | 
						if n != offset {
 | 
				
			||||||
		return nil, errors.New("unable to discard to offset")
 | 
							return nil, errors.New("unable to discard to offset")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,11 @@
 | 
				
			|||||||
package local
 | 
					package local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Handles locking references
 | 
					// Handles locking references
 | 
				
			||||||
@@ -44,9 +44,9 @@ func tryLock(ref string) error {
 | 
				
			|||||||
		// Returning the duration may help developers distinguish dead locks (long duration) from
 | 
							// Returning the duration may help developers distinguish dead locks (long duration) from
 | 
				
			||||||
		// lock contentions (short duration).
 | 
							// lock contentions (short duration).
 | 
				
			||||||
		now := time.Now()
 | 
							now := time.Now()
 | 
				
			||||||
		return errors.Wrapf(
 | 
							return fmt.Errorf(
 | 
				
			||||||
 | 
								"ref %s locked for %s (since %s): %w", ref, now.Sub(v.since), v.since,
 | 
				
			||||||
			errdefs.ErrUnavailable,
 | 
								errdefs.ErrUnavailable,
 | 
				
			||||||
			"ref %s locked for %s (since %s)", ref, now.Sub(v.since), v.since,
 | 
					 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,10 +17,9 @@
 | 
				
			|||||||
package local
 | 
					package local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd/content"
 | 
						"github.com/containerd/containerd/content"
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -40,7 +39,7 @@ func OpenReader(p string) (content.ReaderAt, error) {
 | 
				
			|||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrNotFound, "blob not found")
 | 
							return nil, fmt.Errorf("blob not found: %w", errdefs.ErrNotFound)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fp, err := os.Open(p)
 | 
						fp, err := os.Open(p)
 | 
				
			||||||
@@ -49,7 +48,7 @@ func OpenReader(p string) (content.ReaderAt, error) {
 | 
				
			|||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrNotFound, "blob not found")
 | 
							return nil, fmt.Errorf("blob not found: %w", errdefs.ErrNotFound)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sizeReaderAt{size: fi.Size(), fp: fp}, nil
 | 
						return sizeReaderAt{size: fi.Size(), fp: fp}, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,7 +36,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var bufPool = sync.Pool{
 | 
					var bufPool = sync.Pool{
 | 
				
			||||||
@@ -93,13 +92,13 @@ func NewLabeledStore(root string, ls LabelStore) (content.Store, error) {
 | 
				
			|||||||
func (s *store) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
 | 
					func (s *store) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
 | 
				
			||||||
	p, err := s.blobPath(dgst)
 | 
						p, err := s.blobPath(dgst)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return content.Info{}, errors.Wrapf(err, "calculating blob info path")
 | 
							return content.Info{}, fmt.Errorf("calculating blob info path: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fi, err := os.Stat(p)
 | 
						fi, err := os.Stat(p)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
			err = errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
 | 
								err = fmt.Errorf("content %v: %w", dgst, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return content.Info{}, err
 | 
							return content.Info{}, err
 | 
				
			||||||
@@ -128,12 +127,12 @@ func (s *store) info(dgst digest.Digest, fi os.FileInfo, labels map[string]strin
 | 
				
			|||||||
func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
 | 
					func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
 | 
				
			||||||
	p, err := s.blobPath(desc.Digest)
 | 
						p, err := s.blobPath(desc.Digest)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrapf(err, "calculating blob path for ReaderAt")
 | 
							return nil, fmt.Errorf("calculating blob path for ReaderAt: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reader, err := OpenReader(p)
 | 
						reader, err := OpenReader(p)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrapf(err, "blob %s expected at %s", desc.Digest, p)
 | 
							return nil, fmt.Errorf("blob %s expected at %s: %w", desc.Digest, p, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return reader, nil
 | 
						return reader, nil
 | 
				
			||||||
@@ -146,7 +145,7 @@ func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.
 | 
				
			|||||||
func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
 | 
					func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
 | 
				
			||||||
	bp, err := s.blobPath(dgst)
 | 
						bp, err := s.blobPath(dgst)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "calculating blob path for delete")
 | 
							return fmt.Errorf("calculating blob path for delete: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := os.RemoveAll(bp); err != nil {
 | 
						if err := os.RemoveAll(bp); err != nil {
 | 
				
			||||||
@@ -154,7 +153,7 @@ func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
 | 
				
			|||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
 | 
							return fmt.Errorf("content %v: %w", dgst, errdefs.ErrNotFound)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
@@ -162,18 +161,18 @@ func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (s *store) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
 | 
					func (s *store) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
 | 
				
			||||||
	if s.ls == nil {
 | 
						if s.ls == nil {
 | 
				
			||||||
		return content.Info{}, errors.Wrapf(errdefs.ErrFailedPrecondition, "update not supported on immutable content store")
 | 
							return content.Info{}, fmt.Errorf("update not supported on immutable content store: %w", errdefs.ErrFailedPrecondition)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p, err := s.blobPath(info.Digest)
 | 
						p, err := s.blobPath(info.Digest)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return content.Info{}, errors.Wrapf(err, "calculating blob path for update")
 | 
							return content.Info{}, fmt.Errorf("calculating blob path for update: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fi, err := os.Stat(p)
 | 
						fi, err := os.Stat(p)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
			err = errors.Wrapf(errdefs.ErrNotFound, "content %v", info.Digest)
 | 
								err = fmt.Errorf("content %v: %w", info.Digest, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return content.Info{}, err
 | 
							return content.Info{}, err
 | 
				
			||||||
@@ -200,7 +199,7 @@ func (s *store) Update(ctx context.Context, info content.Info, fieldpaths ...str
 | 
				
			|||||||
				all = true
 | 
									all = true
 | 
				
			||||||
				labels = info.Labels
 | 
									labels = info.Labels
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return content.Info{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on content info %q", path, info.Digest)
 | 
									return content.Info{}, fmt.Errorf("cannot update %q field on content info %q: %w", path, info.Digest, errdefs.ErrInvalidArgument)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -377,7 +376,7 @@ func (s *store) status(ingestPath string) (content.Status, error) {
 | 
				
			|||||||
	fi, err := os.Stat(dp)
 | 
						fi, err := os.Stat(dp)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
			err = errors.Wrap(errdefs.ErrNotFound, err.Error())
 | 
								err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return content.Status{}, err
 | 
							return content.Status{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -385,19 +384,19 @@ func (s *store) status(ingestPath string) (content.Status, error) {
 | 
				
			|||||||
	ref, err := readFileString(filepath.Join(ingestPath, "ref"))
 | 
						ref, err := readFileString(filepath.Join(ingestPath, "ref"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
			err = errors.Wrap(errdefs.ErrNotFound, err.Error())
 | 
								err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return content.Status{}, err
 | 
							return content.Status{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	startedAt, err := readFileTimestamp(filepath.Join(ingestPath, "startedat"))
 | 
						startedAt, err := readFileTimestamp(filepath.Join(ingestPath, "startedat"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return content.Status{}, errors.Wrapf(err, "could not read startedat")
 | 
							return content.Status{}, fmt.Errorf("could not read startedat: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	updatedAt, err := readFileTimestamp(filepath.Join(ingestPath, "updatedat"))
 | 
						updatedAt, err := readFileTimestamp(filepath.Join(ingestPath, "updatedat"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return content.Status{}, errors.Wrapf(err, "could not read updatedat")
 | 
							return content.Status{}, fmt.Errorf("could not read updatedat: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// because we don't write updatedat on every write, the mod time may
 | 
						// because we don't write updatedat on every write, the mod time may
 | 
				
			||||||
@@ -460,7 +459,7 @@ func (s *store) Writer(ctx context.Context, opts ...content.WriterOpt) (content.
 | 
				
			|||||||
	// TODO(AkihiroSuda): we could create a random string or one calculated based on the context
 | 
						// TODO(AkihiroSuda): we could create a random string or one calculated based on the context
 | 
				
			||||||
	// https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
 | 
						// https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
 | 
				
			||||||
	if wOpts.Ref == "" {
 | 
						if wOpts.Ref == "" {
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty")
 | 
							return nil, fmt.Errorf("ref must not be empty: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var lockErr error
 | 
						var lockErr error
 | 
				
			||||||
	for count := uint64(0); count < 10; count++ {
 | 
						for count := uint64(0); count < 10; count++ {
 | 
				
			||||||
@@ -494,16 +493,16 @@ func (s *store) resumeStatus(ref string, total int64, digester digest.Digester)
 | 
				
			|||||||
	path, _, data := s.ingestPaths(ref)
 | 
						path, _, data := s.ingestPaths(ref)
 | 
				
			||||||
	status, err := s.status(path)
 | 
						status, err := s.status(path)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return status, errors.Wrap(err, "failed reading status of resume write")
 | 
							return status, fmt.Errorf("failed reading status of resume write: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ref != status.Ref {
 | 
						if ref != status.Ref {
 | 
				
			||||||
		// NOTE(stevvooe): This is fairly catastrophic. Either we have some
 | 
							// NOTE(stevvooe): This is fairly catastrophic. Either we have some
 | 
				
			||||||
		// layout corruption or a hash collision for the ref key.
 | 
							// layout corruption or a hash collision for the ref key.
 | 
				
			||||||
		return status, errors.Errorf("ref key does not match: %v != %v", ref, status.Ref)
 | 
							return status, fmt.Errorf("ref key does not match: %v != %v", ref, status.Ref)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if total > 0 && status.Total > 0 && total != status.Total {
 | 
						if total > 0 && status.Total > 0 && total != status.Total {
 | 
				
			||||||
		return status, errors.Errorf("provided total differs from status: %v != %v", total, status.Total)
 | 
							return status, fmt.Errorf("provided total differs from status: %v != %v", total, status.Total)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO(stevvooe): slow slow slow!!, send to goroutine or use resumable hashes
 | 
						// TODO(stevvooe): slow slow slow!!, send to goroutine or use resumable hashes
 | 
				
			||||||
@@ -527,10 +526,10 @@ func (s *store) writer(ctx context.Context, ref string, total int64, expected di
 | 
				
			|||||||
	if expected != "" {
 | 
						if expected != "" {
 | 
				
			||||||
		p, err := s.blobPath(expected)
 | 
							p, err := s.blobPath(expected)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrap(err, "calculating expected blob path for writer")
 | 
								return nil, fmt.Errorf("calculating expected blob path for writer: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := os.Stat(p); err == nil {
 | 
							if _, err := os.Stat(p); err == nil {
 | 
				
			||||||
			return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", expected)
 | 
								return nil, fmt.Errorf("content %v: %w", expected, errdefs.ErrAlreadyExists)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -588,12 +587,12 @@ func (s *store) writer(ctx context.Context, ref string, total int64, expected di
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fp, err := os.OpenFile(data, os.O_WRONLY|os.O_CREATE, 0666)
 | 
						fp, err := os.OpenFile(data, os.O_WRONLY|os.O_CREATE, 0666)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to open data file")
 | 
							return nil, fmt.Errorf("failed to open data file: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := fp.Seek(offset, io.SeekStart); err != nil {
 | 
						if _, err := fp.Seek(offset, io.SeekStart); err != nil {
 | 
				
			||||||
		fp.Close()
 | 
							fp.Close()
 | 
				
			||||||
		return nil, errors.Wrap(err, "could not seek to current write offset")
 | 
							return nil, fmt.Errorf("could not seek to current write offset: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &writer{
 | 
						return &writer{
 | 
				
			||||||
@@ -615,7 +614,7 @@ func (s *store) Abort(ctx context.Context, ref string) error {
 | 
				
			|||||||
	root := s.ingestRoot(ref)
 | 
						root := s.ingestRoot(ref)
 | 
				
			||||||
	if err := os.RemoveAll(root); err != nil {
 | 
						if err := os.RemoveAll(root); err != nil {
 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "ingest ref %q", ref)
 | 
								return fmt.Errorf("ingest ref %q: %w", ref, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -626,7 +625,7 @@ func (s *store) Abort(ctx context.Context, ref string) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (s *store) blobPath(dgst digest.Digest) (string, error) {
 | 
					func (s *store) blobPath(dgst digest.Digest) (string, error) {
 | 
				
			||||||
	if err := dgst.Validate(); err != nil {
 | 
						if err := dgst.Validate(); err != nil {
 | 
				
			||||||
		return "", errors.Wrapf(errdefs.ErrInvalidArgument, "cannot calculate blob path from invalid digest: %v", err)
 | 
							return "", fmt.Errorf("cannot calculate blob path from invalid digest: %v: %w", err, errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return filepath.Join(s.root, "blobs", dgst.Algorithm().String(), dgst.Hex()), nil
 | 
						return filepath.Join(s.root, "blobs", dgst.Algorithm().String(), dgst.Hex()), nil
 | 
				
			||||||
@@ -665,14 +664,14 @@ func readFileTimestamp(p string) (time.Time, error) {
 | 
				
			|||||||
	b, err := os.ReadFile(p)
 | 
						b, err := os.ReadFile(p)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
			err = errors.Wrap(errdefs.ErrNotFound, err.Error())
 | 
								err = fmt.Errorf("%s: %w", err.Error(), errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return time.Time{}, err
 | 
							return time.Time{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var t time.Time
 | 
						var t time.Time
 | 
				
			||||||
	if err := t.UnmarshalText(b); err != nil {
 | 
						if err := t.UnmarshalText(b); err != nil {
 | 
				
			||||||
		return time.Time{}, errors.Wrapf(err, "could not parse timestamp file %v", p)
 | 
							return time.Time{}, fmt.Errorf("could not parse timestamp file %v: %w", p, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return t, nil
 | 
						return t, nil
 | 
				
			||||||
@@ -690,16 +689,16 @@ func writeToCompletion(path string, data []byte, mode os.FileMode) error {
 | 
				
			|||||||
	tmp := fmt.Sprintf("%s.tmp", path)
 | 
						tmp := fmt.Sprintf("%s.tmp", path)
 | 
				
			||||||
	f, err := os.OpenFile(tmp, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, mode)
 | 
						f, err := os.OpenFile(tmp, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, mode)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "create tmp file")
 | 
							return fmt.Errorf("create tmp file: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_, err = f.Write(data)
 | 
						_, err = f.Write(data)
 | 
				
			||||||
	f.Close()
 | 
						f.Close()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "write tmp file")
 | 
							return fmt.Errorf("write tmp file: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = os.Rename(tmp, path)
 | 
						err = os.Rename(tmp, path)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "rename tmp file")
 | 
							return fmt.Errorf("rename tmp file: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@ package local
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
@@ -28,7 +30,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/opencontainers/go-digest"
 | 
						"github.com/opencontainers/go-digest"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// writer represents a write transaction against the blob store.
 | 
					// writer represents a write transaction against the blob store.
 | 
				
			||||||
@@ -88,30 +89,30 @@ func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest,
 | 
				
			|||||||
	w.fp = nil
 | 
						w.fp = nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if fp == nil {
 | 
						if fp == nil {
 | 
				
			||||||
		return errors.Wrap(errdefs.ErrFailedPrecondition, "cannot commit on closed writer")
 | 
							return fmt.Errorf("cannot commit on closed writer: %w", errdefs.ErrFailedPrecondition)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := fp.Sync(); err != nil {
 | 
						if err := fp.Sync(); err != nil {
 | 
				
			||||||
		fp.Close()
 | 
							fp.Close()
 | 
				
			||||||
		return errors.Wrap(err, "sync failed")
 | 
							return fmt.Errorf("sync failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fi, err := fp.Stat()
 | 
						fi, err := fp.Stat()
 | 
				
			||||||
	closeErr := fp.Close()
 | 
						closeErr := fp.Close()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "stat on ingest file failed")
 | 
							return fmt.Errorf("stat on ingest file failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if closeErr != nil {
 | 
						if closeErr != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to close ingest file")
 | 
							return fmt.Errorf("failed to close ingest file: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if size > 0 && size != fi.Size() {
 | 
						if size > 0 && size != fi.Size() {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrFailedPrecondition, "unexpected commit size %d, expected %d", fi.Size(), size)
 | 
							return fmt.Errorf("unexpected commit size %d, expected %d: %w", fi.Size(), size, errdefs.ErrFailedPrecondition)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dgst := w.digester.Digest()
 | 
						dgst := w.digester.Digest()
 | 
				
			||||||
	if expected != "" && expected != dgst {
 | 
						if expected != "" && expected != dgst {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrFailedPrecondition, "unexpected commit digest %s, expected %s", dgst, expected)
 | 
							return fmt.Errorf("unexpected commit digest %s, expected %s: %w", dgst, expected, errdefs.ErrFailedPrecondition)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
@@ -129,7 +130,7 @@ func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest,
 | 
				
			|||||||
		if err := os.RemoveAll(w.path); err != nil {
 | 
							if err := os.RemoveAll(w.path); err != nil {
 | 
				
			||||||
			log.G(ctx).WithField("ref", w.ref).WithField("path", w.path).Error("failed to remove ingest directory")
 | 
								log.G(ctx).WithField("ref", w.ref).WithField("path", w.path).Error("failed to remove ingest directory")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", dgst)
 | 
							return fmt.Errorf("content %v: %w", dgst, errdefs.ErrAlreadyExists)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := os.Rename(ingest, target); err != nil {
 | 
						if err := os.Rename(ingest, target); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,13 +18,13 @@ package proxy
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	contentapi "github.com/containerd/containerd/api/services/content/v1"
 | 
						contentapi "github.com/containerd/containerd/api/services/content/v1"
 | 
				
			||||||
	"github.com/containerd/containerd/content"
 | 
						"github.com/containerd/containerd/content"
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type remoteWriter struct {
 | 
					type remoteWriter struct {
 | 
				
			||||||
@@ -57,7 +57,7 @@ func (rw *remoteWriter) Status() (content.Status, error) {
 | 
				
			|||||||
		Action: contentapi.WriteActionStat,
 | 
							Action: contentapi.WriteActionStat,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return content.Status{}, errors.Wrap(errdefs.FromGRPC(err), "error getting writer status")
 | 
							return content.Status{}, fmt.Errorf("error getting writer status: %w", errdefs.FromGRPC(err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return content.Status{
 | 
						return content.Status{
 | 
				
			||||||
@@ -82,7 +82,7 @@ func (rw *remoteWriter) Write(p []byte) (n int, err error) {
 | 
				
			|||||||
		Data:   p,
 | 
							Data:   p,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, errors.Wrap(errdefs.FromGRPC(err), "failed to send write")
 | 
							return 0, fmt.Errorf("failed to send write: %w", errdefs.FromGRPC(err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	n = int(resp.Offset - offset)
 | 
						n = int(resp.Offset - offset)
 | 
				
			||||||
@@ -119,15 +119,15 @@ func (rw *remoteWriter) Commit(ctx context.Context, size int64, expected digest.
 | 
				
			|||||||
		Labels:   base.Labels,
 | 
							Labels:   base.Labels,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(errdefs.FromGRPC(err), "commit failed")
 | 
							return fmt.Errorf("commit failed: %w", errdefs.FromGRPC(err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if size != 0 && resp.Offset != size {
 | 
						if size != 0 && resp.Offset != size {
 | 
				
			||||||
		return errors.Errorf("unexpected size: %v != %v", resp.Offset, size)
 | 
							return fmt.Errorf("unexpected size: %v != %v", resp.Offset, size)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if expected != "" && resp.Digest != expected {
 | 
						if expected != "" && resp.Digest != expected {
 | 
				
			||||||
		return errors.Errorf("unexpected digest: %v != %v", resp.Digest, expected)
 | 
							return fmt.Errorf("unexpected digest: %v != %v", resp.Digest, expected)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rw.digest = resp.Digest
 | 
						rw.digest = resp.Digest
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/pkg/testutil"
 | 
						"github.com/containerd/containerd/pkg/testutil"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"gotest.tools/v3/assert"
 | 
						"gotest.tools/v3/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -712,35 +711,47 @@ func checkResume(rf func(context.Context, content.Writer, []byte, int64, int64,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func resumeTruncate(ctx context.Context, w content.Writer, b []byte, written, size int64, dgst digest.Digest) error {
 | 
					func resumeTruncate(ctx context.Context, w content.Writer, b []byte, written, size int64, dgst digest.Digest) error {
 | 
				
			||||||
	if err := w.Truncate(0); err != nil {
 | 
						if err := w.Truncate(0); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "truncate failed")
 | 
							return fmt.Errorf("truncate failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := io.CopyBuffer(w, bytes.NewReader(b), make([]byte, 1024)); err != nil {
 | 
						if _, err := io.CopyBuffer(w, bytes.NewReader(b), make([]byte, 1024)); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "write failed")
 | 
							return fmt.Errorf("write failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err := w.Commit(ctx, size, dgst); err != nil {
 | 
				
			||||||
	return errors.Wrap(w.Commit(ctx, size, dgst), "commit failed")
 | 
							return fmt.Errorf("commit failed: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func resumeDiscard(ctx context.Context, w content.Writer, b []byte, written, size int64, dgst digest.Digest) error {
 | 
					func resumeDiscard(ctx context.Context, w content.Writer, b []byte, written, size int64, dgst digest.Digest) error {
 | 
				
			||||||
	if _, err := io.CopyBuffer(w, bytes.NewReader(b[written:]), make([]byte, 1024)); err != nil {
 | 
						if _, err := io.CopyBuffer(w, bytes.NewReader(b[written:]), make([]byte, 1024)); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "write failed")
 | 
							return fmt.Errorf("write failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return errors.Wrap(w.Commit(ctx, size, dgst), "commit failed")
 | 
						if err := w.Commit(ctx, size, dgst); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("commit failed: %w", err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func resumeCopy(ctx context.Context, w content.Writer, b []byte, _, size int64, dgst digest.Digest) error {
 | 
					func resumeCopy(ctx context.Context, w content.Writer, b []byte, _, size int64, dgst digest.Digest) error {
 | 
				
			||||||
	r := struct {
 | 
						r := struct {
 | 
				
			||||||
		io.Reader
 | 
							io.Reader
 | 
				
			||||||
	}{bytes.NewReader(b)}
 | 
						}{bytes.NewReader(b)}
 | 
				
			||||||
	return errors.Wrap(content.Copy(ctx, w, r, size, dgst), "copy failed")
 | 
						if err := content.Copy(ctx, w, r, size, dgst); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("copy failed: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func resumeCopySeeker(ctx context.Context, w content.Writer, b []byte, _, size int64, dgst digest.Digest) error {
 | 
					func resumeCopySeeker(ctx context.Context, w content.Writer, b []byte, _, size int64, dgst digest.Digest) error {
 | 
				
			||||||
	r := struct {
 | 
						r := struct {
 | 
				
			||||||
		io.ReadSeeker
 | 
							io.ReadSeeker
 | 
				
			||||||
	}{bytes.NewReader(b)}
 | 
						}{bytes.NewReader(b)}
 | 
				
			||||||
	return errors.Wrap(content.Copy(ctx, w, r, size, dgst), "copy failed")
 | 
						if err := content.Copy(ctx, w, r, size, dgst); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("copy failed: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func resumeCopyReaderAt(ctx context.Context, w content.Writer, b []byte, _, size int64, dgst digest.Digest) error {
 | 
					func resumeCopyReaderAt(ctx context.Context, w content.Writer, b []byte, _, size int64, dgst digest.Digest) error {
 | 
				
			||||||
@@ -751,7 +762,10 @@ func resumeCopyReaderAt(ctx context.Context, w content.Writer, b []byte, _, size
 | 
				
			|||||||
	r := struct {
 | 
						r := struct {
 | 
				
			||||||
		readerAt
 | 
							readerAt
 | 
				
			||||||
	}{bytes.NewReader(b)}
 | 
						}{bytes.NewReader(b)}
 | 
				
			||||||
	return errors.Wrap(content.Copy(ctx, w, r, size, dgst), "copy failed")
 | 
						if err := content.Copy(ctx, w, r, size, dgst); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("copy failed: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// checkSmallBlob tests reading a blob which is smaller than the read size.
 | 
					// checkSmallBlob tests reading a blob which is smaller than the read size.
 | 
				
			||||||
@@ -1018,35 +1032,35 @@ func checkNewlyCreated(t *testing.T, w content.Writer, preStart, postStart, preU
 | 
				
			|||||||
func checkInfo(ctx context.Context, cs content.Store, d digest.Digest, expected content.Info, c1, c2, u1, u2 time.Time) error {
 | 
					func checkInfo(ctx context.Context, cs content.Store, d digest.Digest, expected content.Info, c1, c2, u1, u2 time.Time) error {
 | 
				
			||||||
	info, err := cs.Info(ctx, d)
 | 
						info, err := cs.Info(ctx, d)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to get info")
 | 
							return fmt.Errorf("failed to get info: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if info.Digest != d {
 | 
						if info.Digest != d {
 | 
				
			||||||
		return errors.Errorf("unexpected info digest %s, expected %s", info.Digest, d)
 | 
							return fmt.Errorf("unexpected info digest %s, expected %s", info.Digest, d)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if info.Size != expected.Size {
 | 
						if info.Size != expected.Size {
 | 
				
			||||||
		return errors.Errorf("unexpected info size %d, expected %d", info.Size, expected.Size)
 | 
							return fmt.Errorf("unexpected info size %d, expected %d", info.Size, expected.Size)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if info.CreatedAt.After(c2) || info.CreatedAt.Before(c1) {
 | 
						if info.CreatedAt.After(c2) || info.CreatedAt.Before(c1) {
 | 
				
			||||||
		return errors.Errorf("unexpected created at time %s, expected between %s and %s", info.CreatedAt, c1, c2)
 | 
							return fmt.Errorf("unexpected created at time %s, expected between %s and %s", info.CreatedAt, c1, c2)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// FIXME: broken on windows: unexpected updated at time 2017-11-14 13:43:22.178013 -0800 PST,
 | 
						// FIXME: broken on windows: unexpected updated at time 2017-11-14 13:43:22.178013 -0800 PST,
 | 
				
			||||||
	// expected between 2017-11-14 13:43:22.1790195 -0800 PST m=+1.022137300 and
 | 
						// expected between 2017-11-14 13:43:22.1790195 -0800 PST m=+1.022137300 and
 | 
				
			||||||
	// 2017-11-14 13:43:22.1790195 -0800 PST m=+1.022137300
 | 
						// 2017-11-14 13:43:22.1790195 -0800 PST m=+1.022137300
 | 
				
			||||||
	if runtime.GOOS != "windows" && (info.UpdatedAt.After(u2) || info.UpdatedAt.Before(u1)) {
 | 
						if runtime.GOOS != "windows" && (info.UpdatedAt.After(u2) || info.UpdatedAt.Before(u1)) {
 | 
				
			||||||
		return errors.Errorf("unexpected updated at time %s, expected between %s and %s", info.UpdatedAt, u1, u2)
 | 
							return fmt.Errorf("unexpected updated at time %s, expected between %s and %s", info.UpdatedAt, u1, u2)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(info.Labels) != len(expected.Labels) {
 | 
						if len(info.Labels) != len(expected.Labels) {
 | 
				
			||||||
		return errors.Errorf("mismatched number of labels\ngot:\n%#v\nexpected:\n%#v", info.Labels, expected.Labels)
 | 
							return fmt.Errorf("mismatched number of labels\ngot:\n%#v\nexpected:\n%#v", info.Labels, expected.Labels)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range expected.Labels {
 | 
						for k, v := range expected.Labels {
 | 
				
			||||||
		actual := info.Labels[k]
 | 
							actual := info.Labels[k]
 | 
				
			||||||
		if v != actual {
 | 
							if v != actual {
 | 
				
			||||||
			return errors.Errorf("unexpected value for label %q: %q, expected %q", k, actual, v)
 | 
								return fmt.Errorf("unexpected value for label %q: %q, expected %q", k, actual, v)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1059,16 +1073,16 @@ func checkContent(ctx context.Context, cs content.Store, d digest.Digest, expect
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	b, err := content.ReadBlob(ctx, cs, ocispec.Descriptor{Digest: d})
 | 
						b, err := content.ReadBlob(ctx, cs, ocispec.Descriptor{Digest: d})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to read blob")
 | 
							return fmt.Errorf("failed to read blob: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if int64(len(b)) != expected.Size {
 | 
						if int64(len(b)) != expected.Size {
 | 
				
			||||||
		return errors.Errorf("wrong blob size %d, expected %d", len(b), expected.Size)
 | 
							return fmt.Errorf("wrong blob size %d, expected %d", len(b), expected.Size)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	actual := digest.FromBytes(b)
 | 
						actual := digest.FromBytes(b)
 | 
				
			||||||
	if actual != d {
 | 
						if actual != d {
 | 
				
			||||||
		return errors.Errorf("wrong digest %s, expected %s", actual, d)
 | 
							return fmt.Errorf("wrong digest %s, expected %s", actual, d)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,12 +22,12 @@ package apparmor
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/containers"
 | 
						"github.com/containerd/containerd/containers"
 | 
				
			||||||
	"github.com/containerd/containerd/oci"
 | 
						"github.com/containerd/containerd/oci"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WithProfile sets the provided apparmor profile to the spec
 | 
					// WithProfile sets the provided apparmor profile to the spec
 | 
				
			||||||
@@ -76,7 +76,7 @@ func LoadDefaultProfile(name string) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := load(path); err != nil {
 | 
						if err := load(path); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "load apparmor profile %s", path)
 | 
							return fmt.Errorf("load apparmor profile %s: %w", path, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,11 +21,11 @@ package apparmor
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/containers"
 | 
						"github.com/containerd/containerd/containers"
 | 
				
			||||||
	"github.com/containerd/containerd/oci"
 | 
						"github.com/containerd/containerd/oci"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WithProfile sets the provided apparmor profile to the spec
 | 
					// WithProfile sets the provided apparmor profile to the spec
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"text/template"
 | 
						"text/template"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,7 +124,7 @@ func loadData(name string) (*data, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	ver, err := getVersion()
 | 
						ver, err := getVersion()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "get apparmor_parser version")
 | 
							return nil, fmt.Errorf("get apparmor_parser version: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.Version = ver
 | 
						p.Version = ver
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,7 +151,7 @@ func generate(p *data, o io.Writer) error {
 | 
				
			|||||||
func load(path string) error {
 | 
					func load(path string) error {
 | 
				
			||||||
	out, err := aaParser("-Kr", path)
 | 
						out, err := aaParser("-Kr", path)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Errorf("%s: %s", err, out)
 | 
							return fmt.Errorf("%s: %s", err, out)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package apply
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -27,7 +28,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/mount"
 | 
						"github.com/containerd/containerd/mount"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,13 +64,13 @@ func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [
 | 
				
			|||||||
	var config diff.ApplyConfig
 | 
						var config diff.ApplyConfig
 | 
				
			||||||
	for _, o := range opts {
 | 
						for _, o := range opts {
 | 
				
			||||||
		if err := o(ctx, desc, &config); err != nil {
 | 
							if err := o(ctx, desc, &config); err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrap(err, "failed to apply config opt")
 | 
								return emptyDesc, fmt.Errorf("failed to apply config opt: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ra, err := s.store.ReaderAt(ctx, desc)
 | 
						ra, err := s.store.ReaderAt(ctx, desc)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return emptyDesc, errors.Wrap(err, "failed to get reader from content store")
 | 
							return emptyDesc, fmt.Errorf("failed to get reader from content store: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer ra.Close()
 | 
						defer ra.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -79,7 +79,7 @@ func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [
 | 
				
			|||||||
	processors = append(processors, processor)
 | 
						processors = append(processors, processor)
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil {
 | 
							if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrapf(err, "failed to get stream processor for %s", desc.MediaType)
 | 
								return emptyDesc, fmt.Errorf("failed to get stream processor for %s: %w", desc.MediaType, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		processors = append(processors, processor)
 | 
							processors = append(processors, processor)
 | 
				
			||||||
		if processor.MediaType() == ocispec.MediaTypeImageLayer {
 | 
							if processor.MediaType() == ocispec.MediaTypeImageLayer {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package apply
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +26,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/mount"
 | 
						"github.com/containerd/containerd/mount"
 | 
				
			||||||
	"github.com/containerd/containerd/pkg/userns"
 | 
						"github.com/containerd/containerd/pkg/userns"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func apply(ctx context.Context, mounts []mount.Mount, r io.Reader) error {
 | 
					func apply(ctx context.Context, mounts []mount.Mount, r io.Reader) error {
 | 
				
			||||||
@@ -86,7 +86,7 @@ func getOverlayPath(options []string) (upper string, lower []string, err error)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if upper == "" {
 | 
						if upper == "" {
 | 
				
			||||||
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "upperdir not found")
 | 
							return "", nil, fmt.Errorf("upperdir not found: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
@@ -111,22 +111,22 @@ func getAufsPath(options []string) (upper string, lower []string, err error) {
 | 
				
			|||||||
		for _, b := range strings.Split(o, sep) {
 | 
							for _, b := range strings.Split(o, sep) {
 | 
				
			||||||
			if strings.HasSuffix(b, rwSuffix) {
 | 
								if strings.HasSuffix(b, rwSuffix) {
 | 
				
			||||||
				if upper != "" {
 | 
									if upper != "" {
 | 
				
			||||||
					return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "multiple rw branch found")
 | 
										return "", nil, fmt.Errorf("multiple rw branch found: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				upper = strings.TrimSuffix(b, rwSuffix)
 | 
									upper = strings.TrimSuffix(b, rwSuffix)
 | 
				
			||||||
			} else if strings.HasSuffix(b, roSuffix) {
 | 
								} else if strings.HasSuffix(b, roSuffix) {
 | 
				
			||||||
				if upper == "" {
 | 
									if upper == "" {
 | 
				
			||||||
					return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "rw branch be first")
 | 
										return "", nil, fmt.Errorf("rw branch be first: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				lower = append(lower, strings.TrimSuffix(b, roSuffix))
 | 
									lower = append(lower, strings.TrimSuffix(b, roSuffix))
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "unhandled aufs suffix")
 | 
									return "", nil, fmt.Errorf("unhandled aufs suffix: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if upper == "" {
 | 
						if upper == "" {
 | 
				
			||||||
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "rw branch not found")
 | 
							return "", nil, fmt.Errorf("rw branch not found: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ package lcow
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
@@ -38,7 +39,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/plugin"
 | 
						"github.com/containerd/containerd/plugin"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,7 +111,7 @@ func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mou
 | 
				
			|||||||
	var config diff.ApplyConfig
 | 
						var config diff.ApplyConfig
 | 
				
			||||||
	for _, o := range opts {
 | 
						for _, o := range opts {
 | 
				
			||||||
		if err := o(ctx, desc, &config); err != nil {
 | 
							if err := o(ctx, desc, &config); err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrap(err, "failed to apply config opt")
 | 
								return emptyDesc, fmt.Errorf("failed to apply config opt: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,14 +122,14 @@ func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mou
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ra, err := s.store.ReaderAt(ctx, desc)
 | 
						ra, err := s.store.ReaderAt(ctx, desc)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return emptyDesc, errors.Wrap(err, "failed to get reader from content store")
 | 
							return emptyDesc, fmt.Errorf("failed to get reader from content store: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer ra.Close()
 | 
						defer ra.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra))
 | 
						processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra))
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil {
 | 
							if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrapf(err, "failed to get stream processor for %s", desc.MediaType)
 | 
								return emptyDesc, fmt.Errorf("failed to get stream processor for %s: %w", desc.MediaType, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if processor.MediaType() == ocispec.MediaTypeImageLayer {
 | 
							if processor.MediaType() == ocispec.MediaTypeImageLayer {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
@@ -157,11 +157,11 @@ func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mou
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	err = tar2ext4.Convert(rc, outFile, tar2ext4.ConvertWhiteout, tar2ext4.AppendVhdFooter, tar2ext4.MaximumDiskSize(maxLcowVhdSizeGB))
 | 
						err = tar2ext4.Convert(rc, outFile, tar2ext4.ConvertWhiteout, tar2ext4.AppendVhdFooter, tar2ext4.MaximumDiskSize(maxLcowVhdSizeGB))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return emptyDesc, errors.Wrapf(err, "failed to convert tar2ext4 vhd")
 | 
							return emptyDesc, fmt.Errorf("failed to convert tar2ext4 vhd: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = outFile.Sync()
 | 
						err = outFile.Sync()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return emptyDesc, errors.Wrapf(err, "failed to sync tar2ext4 vhd to disk")
 | 
							return emptyDesc, fmt.Errorf("failed to sync tar2ext4 vhd to disk: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	outFile.Close()
 | 
						outFile.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -172,7 +172,7 @@ func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mou
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	err = security.GrantVmGroupAccess(layerPath)
 | 
						err = security.GrantVmGroupAccess(layerPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return emptyDesc, errors.Wrapf(err, "failed GrantVmGroupAccess on layer vhd: %v", layerPath)
 | 
							return emptyDesc, fmt.Errorf("failed GrantVmGroupAccess on layer vhd: %v: %w", layerPath, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ocispec.Descriptor{
 | 
						return ocispec.Descriptor{
 | 
				
			||||||
@@ -185,7 +185,7 @@ func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mou
 | 
				
			|||||||
// Compare creates a diff between the given mounts and uploads the result
 | 
					// Compare creates a diff between the given mounts and uploads the result
 | 
				
			||||||
// to the content store.
 | 
					// to the content store.
 | 
				
			||||||
func (s windowsLcowDiff) Compare(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (d ocispec.Descriptor, err error) {
 | 
					func (s windowsLcowDiff) Compare(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (d ocispec.Descriptor, err error) {
 | 
				
			||||||
	return emptyDesc, errors.Wrap(errdefs.ErrNotImplemented, "windowsLcowDiff does not implement Compare method")
 | 
						return emptyDesc, fmt.Errorf("windowsLcowDiff does not implement Compare method: %w", errdefs.ErrNotImplemented)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type readCounter struct {
 | 
					type readCounter struct {
 | 
				
			||||||
@@ -201,11 +201,11 @@ func (rc *readCounter) Read(p []byte) (n int, err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func mountsToLayerAndParents(mounts []mount.Mount) (string, []string, error) {
 | 
					func mountsToLayerAndParents(mounts []mount.Mount) (string, []string, error) {
 | 
				
			||||||
	if len(mounts) != 1 {
 | 
						if len(mounts) != 1 {
 | 
				
			||||||
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "number of mounts should always be 1 for Windows lcow-layers")
 | 
							return "", nil, fmt.Errorf("number of mounts should always be 1 for Windows lcow-layers: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mnt := mounts[0]
 | 
						mnt := mounts[0]
 | 
				
			||||||
	if mnt.Type != "lcow-layer" {
 | 
						if mnt.Type != "lcow-layer" {
 | 
				
			||||||
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "mount layer type must be lcow-layer")
 | 
							return "", nil, fmt.Errorf("mount layer type must be lcow-layer: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	parentLayerPaths, err := mnt.GetParentPaths()
 | 
						parentLayerPaths, err := mnt.GetParentPaths()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package diff
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +26,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/images"
 | 
						"github.com/containerd/containerd/images"
 | 
				
			||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ package diff
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -29,7 +30,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/gogo/protobuf/proto"
 | 
						"github.com/gogo/protobuf/proto"
 | 
				
			||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package diff
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -28,7 +29,6 @@ import (
 | 
				
			|||||||
	winio "github.com/Microsoft/go-winio"
 | 
						winio "github.com/Microsoft/go-winio"
 | 
				
			||||||
	"github.com/gogo/protobuf/proto"
 | 
						"github.com/gogo/protobuf/proto"
 | 
				
			||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package walking
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/base64"
 | 
						"encoding/base64"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
@@ -33,7 +34,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/mount"
 | 
						"github.com/containerd/containerd/mount"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type walkingDiff struct {
 | 
					type walkingDiff struct {
 | 
				
			||||||
@@ -81,7 +81,7 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
 | 
				
			|||||||
		case ocispec.MediaTypeImageLayerGzip:
 | 
							case ocispec.MediaTypeImageLayerGzip:
 | 
				
			||||||
			isCompressed = true
 | 
								isCompressed = true
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", config.MediaType)
 | 
								return emptyDesc, fmt.Errorf("unsupported diff media type: %v: %w", config.MediaType, errdefs.ErrNotImplemented)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,7 +100,7 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
 | 
				
			|||||||
					MediaType: config.MediaType, // most contentstore implementations just ignore this
 | 
										MediaType: config.MediaType, // most contentstore implementations just ignore this
 | 
				
			||||||
				}))
 | 
									}))
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "failed to open writer")
 | 
									return fmt.Errorf("failed to open writer: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// errOpen is set when an error occurs while the content writer has not been
 | 
								// errOpen is set when an error occurs while the content writer has not been
 | 
				
			||||||
@@ -128,18 +128,18 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
 | 
				
			|||||||
				if config.Compressor != nil {
 | 
									if config.Compressor != nil {
 | 
				
			||||||
					compressed, errOpen = config.Compressor(cw, config.MediaType)
 | 
										compressed, errOpen = config.Compressor(cw, config.MediaType)
 | 
				
			||||||
					if errOpen != nil {
 | 
										if errOpen != nil {
 | 
				
			||||||
						return errors.Wrap(errOpen, "failed to get compressed stream")
 | 
											return fmt.Errorf("failed to get compressed stream: %w", errOpen)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					compressed, errOpen = compression.CompressStream(cw, compression.Gzip)
 | 
										compressed, errOpen = compression.CompressStream(cw, compression.Gzip)
 | 
				
			||||||
					if errOpen != nil {
 | 
										if errOpen != nil {
 | 
				
			||||||
						return errors.Wrap(errOpen, "failed to get compressed stream")
 | 
											return fmt.Errorf("failed to get compressed stream: %w", errOpen)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				errOpen = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), lowerRoot, upperRoot)
 | 
									errOpen = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), lowerRoot, upperRoot)
 | 
				
			||||||
				compressed.Close()
 | 
									compressed.Close()
 | 
				
			||||||
				if errOpen != nil {
 | 
									if errOpen != nil {
 | 
				
			||||||
					return errors.Wrap(errOpen, "failed to write compressed diff")
 | 
										return fmt.Errorf("failed to write compressed diff: %w", errOpen)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if config.Labels == nil {
 | 
									if config.Labels == nil {
 | 
				
			||||||
@@ -148,7 +148,7 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
 | 
				
			|||||||
				config.Labels[uncompressed] = dgstr.Digest().String()
 | 
									config.Labels[uncompressed] = dgstr.Digest().String()
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				if errOpen = archive.WriteDiff(ctx, cw, lowerRoot, upperRoot); errOpen != nil {
 | 
									if errOpen = archive.WriteDiff(ctx, cw, lowerRoot, upperRoot); errOpen != nil {
 | 
				
			||||||
					return errors.Wrap(errOpen, "failed to write diff")
 | 
										return fmt.Errorf("failed to write diff: %w", errOpen)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,14 +160,14 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
 | 
				
			|||||||
			dgst := cw.Digest()
 | 
								dgst := cw.Digest()
 | 
				
			||||||
			if errOpen = cw.Commit(ctx, 0, dgst, commitopts...); errOpen != nil {
 | 
								if errOpen = cw.Commit(ctx, 0, dgst, commitopts...); errOpen != nil {
 | 
				
			||||||
				if !errdefs.IsAlreadyExists(errOpen) {
 | 
									if !errdefs.IsAlreadyExists(errOpen) {
 | 
				
			||||||
					return errors.Wrap(errOpen, "failed to commit")
 | 
										return fmt.Errorf("failed to commit: %w", errOpen)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				errOpen = nil
 | 
									errOpen = nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			info, err := s.store.Info(ctx, dgst)
 | 
								info, err := s.store.Info(ctx, dgst)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "failed to get info from content store")
 | 
									return fmt.Errorf("failed to get info from content store: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if info.Labels == nil {
 | 
								if info.Labels == nil {
 | 
				
			||||||
				info.Labels = make(map[string]string)
 | 
									info.Labels = make(map[string]string)
 | 
				
			||||||
@@ -176,7 +176,7 @@ func (s *walkingDiff) Compare(ctx context.Context, lower, upper []mount.Mount, o
 | 
				
			|||||||
			if _, ok := info.Labels[uncompressed]; !ok {
 | 
								if _, ok := info.Labels[uncompressed]; !ok {
 | 
				
			||||||
				info.Labels[uncompressed] = config.Labels[uncompressed]
 | 
									info.Labels[uncompressed] = config.Labels[uncompressed]
 | 
				
			||||||
				if _, err := s.store.Update(ctx, info, "labels."+uncompressed); err != nil {
 | 
									if _, err := s.store.Update(ctx, info, "labels."+uncompressed); err != nil {
 | 
				
			||||||
					return errors.Wrap(err, "error setting uncompressed label")
 | 
										return fmt.Errorf("error setting uncompressed label: %w", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,7 +40,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/plugin"
 | 
						"github.com/containerd/containerd/plugin"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -106,20 +105,20 @@ func (s windowsDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts
 | 
				
			|||||||
	var config diff.ApplyConfig
 | 
						var config diff.ApplyConfig
 | 
				
			||||||
	for _, o := range opts {
 | 
						for _, o := range opts {
 | 
				
			||||||
		if err := o(ctx, desc, &config); err != nil {
 | 
							if err := o(ctx, desc, &config); err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrap(err, "failed to apply config opt")
 | 
								return emptyDesc, fmt.Errorf("failed to apply config opt: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ra, err := s.store.ReaderAt(ctx, desc)
 | 
						ra, err := s.store.ReaderAt(ctx, desc)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return emptyDesc, errors.Wrap(err, "failed to get reader from content store")
 | 
							return emptyDesc, fmt.Errorf("failed to get reader from content store: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer ra.Close()
 | 
						defer ra.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra))
 | 
						processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra))
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil {
 | 
							if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrapf(err, "failed to get stream processor for %s", desc.MediaType)
 | 
								return emptyDesc, fmt.Errorf("failed to get stream processor for %s: %w", desc.MediaType, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if processor.MediaType() == ocispec.MediaTypeImageLayer {
 | 
							if processor.MediaType() == ocispec.MediaTypeImageLayer {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
@@ -188,7 +187,7 @@ func (s windowsDiff) Compare(ctx context.Context, lower, upper []mount.Mount, op
 | 
				
			|||||||
	case ocispec.MediaTypeImageLayerGzip:
 | 
						case ocispec.MediaTypeImageLayerGzip:
 | 
				
			||||||
		isCompressed = true
 | 
							isCompressed = true
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", config.MediaType)
 | 
							return emptyDesc, fmt.Errorf("unsupported diff media type: %v: %w", config.MediaType, errdefs.ErrNotImplemented)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	newReference := false
 | 
						newReference := false
 | 
				
			||||||
@@ -202,7 +201,7 @@ func (s windowsDiff) Compare(ctx context.Context, lower, upper []mount.Mount, op
 | 
				
			|||||||
	}))
 | 
						}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return emptyDesc, errors.Wrap(err, "failed to open writer")
 | 
							return emptyDesc, fmt.Errorf("failed to open writer: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
@@ -235,12 +234,12 @@ func (s windowsDiff) Compare(ctx context.Context, lower, upper []mount.Mount, op
 | 
				
			|||||||
		var compressed io.WriteCloser
 | 
							var compressed io.WriteCloser
 | 
				
			||||||
		compressed, err = compression.CompressStream(cw, compression.Gzip)
 | 
							compressed, err = compression.CompressStream(cw, compression.Gzip)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrap(err, "failed to get compressed stream")
 | 
								return emptyDesc, fmt.Errorf("failed to get compressed stream: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		err = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), "", layers[0], archive.AsWindowsContainerLayerPair(), archive.WithParentLayers(layers[1:]))
 | 
							err = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), "", layers[0], archive.AsWindowsContainerLayerPair(), archive.WithParentLayers(layers[1:]))
 | 
				
			||||||
		compressed.Close()
 | 
							compressed.Close()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrap(err, "failed to write compressed diff")
 | 
								return emptyDesc, fmt.Errorf("failed to write compressed diff: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if config.Labels == nil {
 | 
							if config.Labels == nil {
 | 
				
			||||||
@@ -249,7 +248,7 @@ func (s windowsDiff) Compare(ctx context.Context, lower, upper []mount.Mount, op
 | 
				
			|||||||
		config.Labels[uncompressed] = dgstr.Digest().String()
 | 
							config.Labels[uncompressed] = dgstr.Digest().String()
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if err = archive.WriteDiff(ctx, cw, "", layers[0], archive.AsWindowsContainerLayerPair(), archive.WithParentLayers(layers[1:])); err != nil {
 | 
							if err = archive.WriteDiff(ctx, cw, "", layers[0], archive.AsWindowsContainerLayerPair(), archive.WithParentLayers(layers[1:])); err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrap(err, "failed to write diff")
 | 
								return emptyDesc, fmt.Errorf("failed to write diff: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -261,13 +260,13 @@ func (s windowsDiff) Compare(ctx context.Context, lower, upper []mount.Mount, op
 | 
				
			|||||||
	dgst := cw.Digest()
 | 
						dgst := cw.Digest()
 | 
				
			||||||
	if err := cw.Commit(ctx, 0, dgst, commitopts...); err != nil {
 | 
						if err := cw.Commit(ctx, 0, dgst, commitopts...); err != nil {
 | 
				
			||||||
		if !errdefs.IsAlreadyExists(err) {
 | 
							if !errdefs.IsAlreadyExists(err) {
 | 
				
			||||||
			return emptyDesc, errors.Wrap(err, "failed to commit")
 | 
								return emptyDesc, fmt.Errorf("failed to commit: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info, err := s.store.Info(ctx, dgst)
 | 
						info, err := s.store.Info(ctx, dgst)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return emptyDesc, errors.Wrap(err, "failed to get info from content store")
 | 
							return emptyDesc, fmt.Errorf("failed to get info from content store: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if info.Labels == nil {
 | 
						if info.Labels == nil {
 | 
				
			||||||
		info.Labels = make(map[string]string)
 | 
							info.Labels = make(map[string]string)
 | 
				
			||||||
@@ -276,7 +275,7 @@ func (s windowsDiff) Compare(ctx context.Context, lower, upper []mount.Mount, op
 | 
				
			|||||||
	if _, ok := info.Labels[uncompressed]; !ok {
 | 
						if _, ok := info.Labels[uncompressed]; !ok {
 | 
				
			||||||
		info.Labels[uncompressed] = config.Labels[uncompressed]
 | 
							info.Labels[uncompressed] = config.Labels[uncompressed]
 | 
				
			||||||
		if _, err := s.store.Update(ctx, info, "labels."+uncompressed); err != nil {
 | 
							if _, err := s.store.Update(ctx, info, "labels."+uncompressed); err != nil {
 | 
				
			||||||
			return emptyDesc, errors.Wrap(err, "error setting uncompressed label")
 | 
								return emptyDesc, fmt.Errorf("error setting uncompressed label: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -309,14 +308,14 @@ func (rc *readCounter) Read(p []byte) (n int, err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func mountsToLayerAndParents(mounts []mount.Mount) (string, []string, error) {
 | 
					func mountsToLayerAndParents(mounts []mount.Mount) (string, []string, error) {
 | 
				
			||||||
	if len(mounts) != 1 {
 | 
						if len(mounts) != 1 {
 | 
				
			||||||
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "number of mounts should always be 1 for Windows layers")
 | 
							return "", nil, fmt.Errorf("number of mounts should always be 1 for Windows layers: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mnt := mounts[0]
 | 
						mnt := mounts[0]
 | 
				
			||||||
	if mnt.Type != "windows-layer" {
 | 
						if mnt.Type != "windows-layer" {
 | 
				
			||||||
		// This is a special case error. When this is received the diff service
 | 
							// This is a special case error. When this is received the diff service
 | 
				
			||||||
		// will attempt the next differ in the chain which for Windows is the
 | 
							// will attempt the next differ in the chain which for Windows is the
 | 
				
			||||||
		// lcow differ that we want.
 | 
							// lcow differ that we want.
 | 
				
			||||||
		return "", nil, errors.Wrapf(errdefs.ErrNotImplemented, "windowsDiff does not support layer type %s", mnt.Type)
 | 
							return "", nil, fmt.Errorf("windowsDiff does not support layer type %s: %w", mnt.Type, errdefs.ErrNotImplemented)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	parentLayerPaths, err := mnt.GetParentPaths()
 | 
						parentLayerPaths, err := mnt.GetParentPaths()
 | 
				
			||||||
@@ -335,39 +334,39 @@ func mountPairToLayerStack(lower, upper []mount.Mount) ([]string, error) {
 | 
				
			|||||||
	// May return an ErrNotImplemented, which will fall back to LCOW
 | 
						// May return an ErrNotImplemented, which will fall back to LCOW
 | 
				
			||||||
	upperLayer, upperParentLayerPaths, err := mountsToLayerAndParents(upper)
 | 
						upperLayer, upperParentLayerPaths, err := mountsToLayerAndParents(upper)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrapf(err, "Upper mount invalid")
 | 
							return nil, fmt.Errorf("Upper mount invalid: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Trivial case, diff-against-nothing
 | 
						// Trivial case, diff-against-nothing
 | 
				
			||||||
	if len(lower) == 0 {
 | 
						if len(lower) == 0 {
 | 
				
			||||||
		if len(upperParentLayerPaths) != 0 {
 | 
							if len(upperParentLayerPaths) != 0 {
 | 
				
			||||||
			return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer with parents against a null layer")
 | 
								return nil, fmt.Errorf("windowsDiff cannot diff a layer with parents against a null layer: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return []string{upperLayer}, nil
 | 
							return []string{upperLayer}, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(upperParentLayerPaths) < 1 {
 | 
						if len(upperParentLayerPaths) < 1 {
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer with no parents against another layer")
 | 
							return nil, fmt.Errorf("windowsDiff cannot diff a layer with no parents against another layer: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lowerLayer, lowerParentLayerPaths, err := mountsToLayerAndParents(lower)
 | 
						lowerLayer, lowerParentLayerPaths, err := mountsToLayerAndParents(lower)
 | 
				
			||||||
	if errdefs.IsNotImplemented(err) {
 | 
						if errdefs.IsNotImplemented(err) {
 | 
				
			||||||
		// Upper was a windows-layer, lower is not. We can't handle that.
 | 
							// Upper was a windows-layer, lower is not. We can't handle that.
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a windows-layer against a non-windows-layer")
 | 
							return nil, fmt.Errorf("windowsDiff cannot diff a windows-layer against a non-windows-layer: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	} else if err != nil {
 | 
						} else if err != nil {
 | 
				
			||||||
		return nil, errors.Wrapf(err, "Lower mount invalid")
 | 
							return nil, fmt.Errorf("Lower mount invalid: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if upperParentLayerPaths[0] != lowerLayer {
 | 
						if upperParentLayerPaths[0] != lowerLayer {
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer against a layer other than its own parent")
 | 
							return nil, fmt.Errorf("windowsDiff cannot diff a layer against a layer other than its own parent: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(upperParentLayerPaths) != len(lowerParentLayerPaths)+1 {
 | 
						if len(upperParentLayerPaths) != len(lowerParentLayerPaths)+1 {
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer against a layer with different parents")
 | 
							return nil, fmt.Errorf("windowsDiff cannot diff a layer against a layer with different parents: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for i, upperParent := range upperParentLayerPaths[1:] {
 | 
						for i, upperParent := range upperParentLayerPaths[1:] {
 | 
				
			||||||
		if upperParent != lowerParentLayerPaths[i] {
 | 
							if upperParent != lowerParentLayerPaths[i] {
 | 
				
			||||||
			return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer against a layer with different parents")
 | 
								return nil, fmt.Errorf("windowsDiff cannot diff a layer against a layer with different parents: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@
 | 
				
			|||||||
// Package errdefs defines the common errors used throughout containerd
 | 
					// Package errdefs defines the common errors used throughout containerd
 | 
				
			||||||
// packages.
 | 
					// packages.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// Use with errors.Wrap and error.Wrapf to add context to an error.
 | 
					// Use with fmt.Errorf to add context to an error.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// To detect an error class, use the IsXXX functions to tell whether an error
 | 
					// To detect an error class, use the IsXXX functions to tell whether an error
 | 
				
			||||||
// is of a certain type.
 | 
					// is of a certain type.
 | 
				
			||||||
@@ -28,8 +28,7 @@ package errdefs
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Definitions of common error types used throughout containerd. All containerd
 | 
					// Definitions of common error types used throughout containerd. All containerd
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,9 +18,9 @@ package errdefs
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"google.golang.org/grpc/codes"
 | 
						"google.golang.org/grpc/codes"
 | 
				
			||||||
	"google.golang.org/grpc/status"
 | 
						"google.golang.org/grpc/status"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -68,9 +68,9 @@ func ToGRPC(err error) error {
 | 
				
			|||||||
// ToGRPCf maps the error to grpc error codes, assembling the formatting string
 | 
					// ToGRPCf maps the error to grpc error codes, assembling the formatting string
 | 
				
			||||||
// and combining it with the target error string.
 | 
					// and combining it with the target error string.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// This is equivalent to errors.ToGRPC(errors.Wrapf(err, format, args...))
 | 
					// This is equivalent to errdefs.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
 | 
				
			||||||
func ToGRPCf(err error, format string, args ...interface{}) error {
 | 
					func ToGRPCf(err error, format string, args ...interface{}) error {
 | 
				
			||||||
	return ToGRPC(errors.Wrapf(err, format, args...))
 | 
						return ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FromGRPC returns the underlying error from a grpc service based on the grpc error code
 | 
					// FromGRPC returns the underlying error from a grpc service based on the grpc error code
 | 
				
			||||||
@@ -104,9 +104,9 @@ func FromGRPC(err error) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	msg := rebaseMessage(cls, err)
 | 
						msg := rebaseMessage(cls, err)
 | 
				
			||||||
	if msg != "" {
 | 
						if msg != "" {
 | 
				
			||||||
		err = errors.Wrap(cls, msg)
 | 
							err = fmt.Errorf("%s: %w", msg, cls)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		err = errors.WithStack(cls)
 | 
							err = cls
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,12 +18,12 @@ package errdefs
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"google.golang.org/grpc/codes"
 | 
						"google.golang.org/grpc/codes"
 | 
				
			||||||
	"google.golang.org/grpc/status"
 | 
						"google.golang.org/grpc/status"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGRPCRoundTrip(t *testing.T) {
 | 
					func TestGRPCRoundTrip(t *testing.T) {
 | 
				
			||||||
@@ -43,7 +43,7 @@ func TestGRPCRoundTrip(t *testing.T) {
 | 
				
			|||||||
			cause: ErrNotFound,
 | 
								cause: ErrNotFound,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			input: errors.Wrapf(ErrFailedPrecondition, "test test test"),
 | 
								input: fmt.Errorf("test test test: %w", ErrFailedPrecondition),
 | 
				
			||||||
			cause: ErrFailedPrecondition,
 | 
								cause: ErrFailedPrecondition,
 | 
				
			||||||
			str:   "test test test: failed precondition",
 | 
								str:   "test test test: failed precondition",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -63,7 +63,7 @@ func TestGRPCRoundTrip(t *testing.T) {
 | 
				
			|||||||
			str:   "context canceled",
 | 
								str:   "context canceled",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			input: errors.Wrapf(context.Canceled, "this is a test cancel"),
 | 
								input: fmt.Errorf("this is a test cancel: %w", context.Canceled),
 | 
				
			||||||
			cause: context.Canceled,
 | 
								cause: context.Canceled,
 | 
				
			||||||
			str:   "this is a test cancel: context canceled",
 | 
								str:   "this is a test cancel: context canceled",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -73,7 +73,7 @@ func TestGRPCRoundTrip(t *testing.T) {
 | 
				
			|||||||
			str:   "context deadline exceeded",
 | 
								str:   "context deadline exceeded",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			input: errors.Wrapf(context.DeadlineExceeded, "this is a test deadline exceeded"),
 | 
								input: fmt.Errorf("this is a test deadline exceeded: %w", context.DeadlineExceeded),
 | 
				
			||||||
			cause: context.DeadlineExceeded,
 | 
								cause: context.DeadlineExceeded,
 | 
				
			||||||
			str:   "this is a test deadline exceeded: context deadline exceeded",
 | 
								str:   "this is a test deadline exceeded: context deadline exceeded",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -85,9 +85,6 @@ func TestGRPCRoundTrip(t *testing.T) {
 | 
				
			|||||||
			ferr := FromGRPC(gerr)
 | 
								ferr := FromGRPC(gerr)
 | 
				
			||||||
			t.Logf("recovered: %v", ferr)
 | 
								t.Logf("recovered: %v", ferr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if errors.Cause(ferr) != testcase.cause {
 | 
					 | 
				
			||||||
				t.Fatalf("unexpected cause: %v != %v", errors.Cause(ferr), testcase.cause)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if !errors.Is(ferr, testcase.cause) {
 | 
								if !errors.Is(ferr, testcase.cause) {
 | 
				
			||||||
				t.Fatalf("unexpected cause: !errors.Is(%v, %v)", ferr, testcase.cause)
 | 
									t.Fatalf("unexpected cause: !errors.Is(%v, %v)", ferr, testcase.cause)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package exchange
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,7 +31,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	goevents "github.com/docker/go-events"
 | 
						goevents "github.com/docker/go-events"
 | 
				
			||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,10 +88,10 @@ func (e *Exchange) Publish(ctx context.Context, topic string, event events.Event
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	namespace, err = namespaces.NamespaceRequired(ctx)
 | 
						namespace, err = namespaces.NamespaceRequired(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "failed publishing event")
 | 
							return fmt.Errorf("failed publishing event: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := validateTopic(topic); err != nil {
 | 
						if err := validateTopic(topic); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "envelope topic %q", topic)
 | 
							return fmt.Errorf("envelope topic %q: %w", topic, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	encoded, err = typeurl.MarshalAny(event)
 | 
						encoded, err = typeurl.MarshalAny(event)
 | 
				
			||||||
@@ -150,7 +150,7 @@ func (e *Exchange) Subscribe(ctx context.Context, fs ...string) (ch <-chan *even
 | 
				
			|||||||
	if len(fs) > 0 {
 | 
						if len(fs) > 0 {
 | 
				
			||||||
		filter, err := filters.ParseAll(fs...)
 | 
							filter, err := filters.ParseAll(fs...)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			errq <- errors.Wrapf(err, "failed parsing subscription filters")
 | 
								errq <- fmt.Errorf("failed parsing subscription filters: %w", err)
 | 
				
			||||||
			closeAll()
 | 
								closeAll()
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -175,7 +175,7 @@ func (e *Exchange) Subscribe(ctx context.Context, fs ...string) (ch <-chan *even
 | 
				
			|||||||
					// TODO(stevvooe): For the most part, we are well protected
 | 
										// TODO(stevvooe): For the most part, we are well protected
 | 
				
			||||||
					// from this condition. Both Forward and Publish protect
 | 
										// from this condition. Both Forward and Publish protect
 | 
				
			||||||
					// from this.
 | 
										// from this.
 | 
				
			||||||
					err = errors.Errorf("invalid envelope encountered %#v; please file a bug", ev)
 | 
										err = fmt.Errorf("invalid envelope encountered %#v; please file a bug", ev)
 | 
				
			||||||
					break
 | 
										break
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,21 +203,21 @@ func (e *Exchange) Subscribe(ctx context.Context, fs ...string) (ch <-chan *even
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func validateTopic(topic string) error {
 | 
					func validateTopic(topic string) error {
 | 
				
			||||||
	if topic == "" {
 | 
						if topic == "" {
 | 
				
			||||||
		return errors.Wrap(errdefs.ErrInvalidArgument, "must not be empty")
 | 
							return fmt.Errorf("must not be empty: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if topic[0] != '/' {
 | 
						if topic[0] != '/' {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "must start with '/'")
 | 
							return fmt.Errorf("must start with '/': %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(topic) == 1 {
 | 
						if len(topic) == 1 {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "must have at least one component")
 | 
							return fmt.Errorf("must have at least one component: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	components := strings.Split(topic[1:], "/")
 | 
						components := strings.Split(topic[1:], "/")
 | 
				
			||||||
	for _, component := range components {
 | 
						for _, component := range components {
 | 
				
			||||||
		if err := identifiers.Validate(component); err != nil {
 | 
							if err := identifiers.Validate(component); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed validation on component %q", component)
 | 
								return fmt.Errorf("failed validation on component %q: %w", component, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -226,15 +226,15 @@ func validateTopic(topic string) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func validateEnvelope(envelope *events.Envelope) error {
 | 
					func validateEnvelope(envelope *events.Envelope) error {
 | 
				
			||||||
	if err := identifiers.Validate(envelope.Namespace); err != nil {
 | 
						if err := identifiers.Validate(envelope.Namespace); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "event envelope has invalid namespace")
 | 
							return fmt.Errorf("event envelope has invalid namespace: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := validateTopic(envelope.Topic); err != nil {
 | 
						if err := validateTopic(envelope.Topic); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "envelope topic %q", envelope.Topic)
 | 
							return fmt.Errorf("envelope topic %q: %w", envelope.Topic, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if envelope.Timestamp.IsZero() {
 | 
						if envelope.Timestamp.IsZero() {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "timestamp must be set on forwarded event")
 | 
							return fmt.Errorf("timestamp must be set on forwarded event: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package exchange
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -27,7 +28,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/events"
 | 
						"github.com/containerd/containerd/events"
 | 
				
			||||||
	"github.com/containerd/containerd/namespaces"
 | 
						"github.com/containerd/containerd/namespaces"
 | 
				
			||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestExchangeBasic(t *testing.T) {
 | 
					func TestExchangeBasic(t *testing.T) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,6 @@ import (
 | 
				
			|||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -71,7 +70,7 @@ func ParseAll(ss ...string) (Filter, error) {
 | 
				
			|||||||
	for _, s := range ss {
 | 
						for _, s := range ss {
 | 
				
			||||||
		f, err := Parse(s)
 | 
							f, err := Parse(s)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error())
 | 
								return nil, fmt.Errorf("%s: %w", err.Error(), errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fs = append(fs, f)
 | 
							fs = append(fs, f)
 | 
				
			||||||
@@ -90,7 +89,7 @@ func (p *parser) parse() (Filter, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ss, err := p.selectors()
 | 
						ss, err := p.selectors()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "filters")
 | 
							return nil, fmt.Errorf("filters: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ss, nil
 | 
						return ss, nil
 | 
				
			||||||
@@ -284,9 +283,9 @@ func (pe parseError) Error() string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *parser) mkerr(pos int, format string, args ...interface{}) error {
 | 
					func (p *parser) mkerr(pos int, format string, args ...interface{}) error {
 | 
				
			||||||
	return errors.Wrap(parseError{
 | 
						return fmt.Errorf("parse error: %w", parseError{
 | 
				
			||||||
		input: p.input,
 | 
							input: p.input,
 | 
				
			||||||
		pos:   pos,
 | 
							pos:   pos,
 | 
				
			||||||
		msg:   fmt.Sprintf(format, args...),
 | 
							msg:   fmt.Sprintf(format, args...),
 | 
				
			||||||
	}, "parse error")
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,9 +17,8 @@
 | 
				
			|||||||
package filters
 | 
					package filters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"unicode/utf8"
 | 
						"unicode/utf8"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NOTE(stevvooe): Most of this code in this file is copied from the stdlib
 | 
					// NOTE(stevvooe): Most of this code in this file is copied from the stdlib
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package scheduler
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -25,7 +26,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/gc"
 | 
						"github.com/containerd/containerd/gc"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/containerd/containerd/plugin"
 | 
						"github.com/containerd/containerd/plugin"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// config configures the garbage collection policies.
 | 
					// config configures the garbage collection policies.
 | 
				
			||||||
@@ -117,7 +117,7 @@ func init() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			mdCollector, ok := md.(collector)
 | 
								mdCollector, ok := md.(collector)
 | 
				
			||||||
			if !ok {
 | 
								if !ok {
 | 
				
			||||||
				return nil, errors.Errorf("%s %T must implement collector", plugin.MetadataPlugin, md)
 | 
									return nil, fmt.Errorf("%s %T must implement collector", plugin.MetadataPlugin, md)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			m := newScheduler(mdCollector, ic.Config.(*config))
 | 
								m := newScheduler(mdCollector, ic.Config.(*config))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							@@ -49,7 +49,6 @@ require (
 | 
				
			|||||||
	github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
 | 
						github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
 | 
				
			||||||
	github.com/opencontainers/selinux v1.8.2
 | 
						github.com/opencontainers/selinux v1.8.2
 | 
				
			||||||
	github.com/pelletier/go-toml v1.9.3
 | 
						github.com/pelletier/go-toml v1.9.3
 | 
				
			||||||
	github.com/pkg/errors v0.9.1
 | 
					 | 
				
			||||||
	github.com/prometheus/client_golang v1.11.0
 | 
						github.com/prometheus/client_golang v1.11.0
 | 
				
			||||||
	github.com/satori/go.uuid v1.2.0 // indirect
 | 
						github.com/satori/go.uuid v1.2.0 // indirect
 | 
				
			||||||
	github.com/sirupsen/logrus v1.8.1
 | 
						github.com/sirupsen/logrus v1.8.1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,10 +25,10 @@
 | 
				
			|||||||
package identifiers
 | 
					package identifiers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -51,15 +51,15 @@ var (
 | 
				
			|||||||
// In general identifiers that pass this validation should be safe for use as filesystem path components.
 | 
					// In general identifiers that pass this validation should be safe for use as filesystem path components.
 | 
				
			||||||
func Validate(s string) error {
 | 
					func Validate(s string) error {
 | 
				
			||||||
	if len(s) == 0 {
 | 
						if len(s) == 0 {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier must not be empty")
 | 
							return fmt.Errorf("identifier must not be empty: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(s) > maxLength {
 | 
						if len(s) > maxLength {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier %q greater than maximum length (%d characters)", s, maxLength)
 | 
							return fmt.Errorf("identifier %q greater than maximum length (%d characters): %w", s, maxLength, errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !identifierRe.MatchString(s) {
 | 
						if !identifierRe.MatchString(s) {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier %q must match %v", s, identifierRe)
 | 
							return fmt.Errorf("identifier %q must match %v: %w", s, identifierRe, errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								image.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								image.go
									
									
									
									
									
								
							@@ -19,6 +19,7 @@ package containerd
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync/atomic"
 | 
						"sync/atomic"
 | 
				
			||||||
@@ -33,7 +34,6 @@ import (
 | 
				
			|||||||
	"github.com/opencontainers/go-digest"
 | 
						"github.com/opencontainers/go-digest"
 | 
				
			||||||
	"github.com/opencontainers/image-spec/identity"
 | 
						"github.com/opencontainers/image-spec/identity"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"golang.org/x/sync/semaphore"
 | 
						"golang.org/x/sync/semaphore"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -399,7 +399,7 @@ func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer,
 | 
				
			|||||||
	cs := i.ContentStore()
 | 
						cs := i.ContentStore()
 | 
				
			||||||
	diffIDs, err := i.i.RootFS(ctx, cs, platform)
 | 
						diffIDs, err := i.i.RootFS(ctx, cs, platform)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to resolve rootfs")
 | 
							return nil, fmt.Errorf("failed to resolve rootfs: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(diffIDs) != len(manifest.Layers) {
 | 
						if len(diffIDs) != len(manifest.Layers) {
 | 
				
			||||||
		return nil, errors.New("mismatched image rootfs and manifest layers")
 | 
							return nil, errors.New("mismatched image rootfs and manifest layers")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ import (
 | 
				
			|||||||
	"archive/tar"
 | 
						"archive/tar"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
@@ -31,7 +32,6 @@ import (
 | 
				
			|||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispecs "github.com/opencontainers/image-spec/specs-go"
 | 
						ocispecs "github.com/opencontainers/image-spec/specs-go"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type exportOptions struct {
 | 
					type exportOptions struct {
 | 
				
			||||||
@@ -230,7 +230,7 @@ func Export(ctx context.Context, store content.Provider, writer io.Writer, opts
 | 
				
			|||||||
							manifest: manifests[0],
 | 
												manifest: manifests[0],
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					} else if eo.platform != nil {
 | 
										} else if eo.platform != nil {
 | 
				
			||||||
						return errors.Wrap(errdefs.ErrNotFound, "no manifest found for platform")
 | 
											return fmt.Errorf("no manifest found for platform: %w", errdefs.ErrNotFound)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				resolvedIndex[desc.Digest] = d
 | 
									resolvedIndex[desc.Digest] = d
 | 
				
			||||||
@@ -243,14 +243,14 @@ func Export(ctx context.Context, store content.Provider, writer io.Writer, opts
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrInvalidArgument, "only manifests may be exported")
 | 
								return fmt.Errorf("only manifests may be exported: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(dManifests) > 0 {
 | 
						if len(dManifests) > 0 {
 | 
				
			||||||
		tr, err := manifestsRecord(ctx, store, dManifests)
 | 
							tr, err := manifestsRecord(ctx, store, dManifests)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "unable to create manifests file")
 | 
								return fmt.Errorf("unable to create manifests file: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		records = append(records, tr)
 | 
							records = append(records, tr)
 | 
				
			||||||
@@ -316,7 +316,7 @@ func blobRecord(cs content.Provider, desc ocispec.Descriptor, opts *blobRecordOp
 | 
				
			|||||||
		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
 | 
							CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
 | 
				
			||||||
			r, err := cs.ReaderAt(ctx, desc)
 | 
								r, err := cs.ReaderAt(ctx, desc)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return 0, errors.Wrap(err, "failed to get reader")
 | 
									return 0, fmt.Errorf("failed to get reader: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			defer r.Close()
 | 
								defer r.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -325,10 +325,10 @@ func blobRecord(cs content.Provider, desc ocispec.Descriptor, opts *blobRecordOp
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r))
 | 
								n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r))
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return 0, errors.Wrap(err, "failed to copy to tar")
 | 
									return 0, fmt.Errorf("failed to copy to tar: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if dgstr.Digest() != desc.Digest {
 | 
								if dgstr.Digest() != desc.Digest {
 | 
				
			||||||
				return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest())
 | 
									return 0, fmt.Errorf("unexpected digest %s copied", dgstr.Digest())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return n, nil
 | 
								return n, nil
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -424,7 +424,7 @@ func manifestsRecord(ctx context.Context, store content.Provider, manifests map[
 | 
				
			|||||||
			return tarRecord{}, err
 | 
								return tarRecord{}, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := manifest.Config.Digest.Validate(); err != nil {
 | 
							if err := manifest.Config.Digest.Validate(); err != nil {
 | 
				
			||||||
			return tarRecord{}, errors.Wrapf(err, "invalid manifest %q", m.manifest.Digest)
 | 
								return tarRecord{}, fmt.Errorf("invalid manifest %q: %w", m.manifest.Digest, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dgst := manifest.Config.Digest
 | 
							dgst := manifest.Config.Digest
 | 
				
			||||||
@@ -491,10 +491,10 @@ func writeTar(ctx context.Context, tw *tar.Writer, recordsWithEmpty []tarRecord)
 | 
				
			|||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if n != record.Header.Size {
 | 
								if n != record.Header.Size {
 | 
				
			||||||
				return errors.Errorf("unexpected copy size for %s", record.Header.Name)
 | 
									return fmt.Errorf("unexpected copy size for %s", record.Header.Name)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if record.Header.Size > 0 {
 | 
							} else if record.Header.Size > 0 {
 | 
				
			||||||
			return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name)
 | 
								return fmt.Errorf("no content to write to record with non-zero size for %s", record.Header.Name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ import (
 | 
				
			|||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
@@ -35,7 +36,6 @@ import (
 | 
				
			|||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	specs "github.com/opencontainers/image-spec/specs-go"
 | 
						specs "github.com/opencontainers/image-spec/specs-go"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type importOpts struct {
 | 
					type importOpts struct {
 | 
				
			||||||
@@ -104,16 +104,16 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opt
 | 
				
			|||||||
		hdrName := path.Clean(hdr.Name)
 | 
							hdrName := path.Clean(hdr.Name)
 | 
				
			||||||
		if hdrName == ocispec.ImageLayoutFile {
 | 
							if hdrName == ocispec.ImageLayoutFile {
 | 
				
			||||||
			if err = onUntarJSON(tr, &ociLayout); err != nil {
 | 
								if err = onUntarJSON(tr, &ociLayout); err != nil {
 | 
				
			||||||
				return ocispec.Descriptor{}, errors.Wrapf(err, "untar oci layout %q", hdr.Name)
 | 
									return ocispec.Descriptor{}, fmt.Errorf("untar oci layout %q: %w", hdr.Name, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if hdrName == "manifest.json" {
 | 
							} else if hdrName == "manifest.json" {
 | 
				
			||||||
			if err = onUntarJSON(tr, &mfsts); err != nil {
 | 
								if err = onUntarJSON(tr, &mfsts); err != nil {
 | 
				
			||||||
				return ocispec.Descriptor{}, errors.Wrapf(err, "untar manifest %q", hdr.Name)
 | 
									return ocispec.Descriptor{}, fmt.Errorf("untar manifest %q: %w", hdr.Name, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			dgst, err := onUntarBlob(ctx, tr, store, hdr.Size, "tar-"+hdrName)
 | 
								dgst, err := onUntarBlob(ctx, tr, store, hdr.Size, "tar-"+hdrName)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return ocispec.Descriptor{}, errors.Wrapf(err, "failed to ingest %q", hdr.Name)
 | 
									return ocispec.Descriptor{}, fmt.Errorf("failed to ingest %q: %w", hdr.Name, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			blobs[hdrName] = ocispec.Descriptor{
 | 
								blobs[hdrName] = ocispec.Descriptor{
 | 
				
			||||||
@@ -128,12 +128,12 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opt
 | 
				
			|||||||
	// as Docker v1.1 or v1.2.
 | 
						// as Docker v1.1 or v1.2.
 | 
				
			||||||
	if ociLayout.Version != "" {
 | 
						if ociLayout.Version != "" {
 | 
				
			||||||
		if ociLayout.Version != ocispec.ImageLayoutVersion {
 | 
							if ociLayout.Version != ocispec.ImageLayoutVersion {
 | 
				
			||||||
			return ocispec.Descriptor{}, errors.Errorf("unsupported OCI version %s", ociLayout.Version)
 | 
								return ocispec.Descriptor{}, fmt.Errorf("unsupported OCI version %s", ociLayout.Version)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		idx, ok := blobs["index.json"]
 | 
							idx, ok := blobs["index.json"]
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return ocispec.Descriptor{}, errors.Errorf("missing index.json in OCI layout %s", ocispec.ImageLayoutVersion)
 | 
								return ocispec.Descriptor{}, fmt.Errorf("missing index.json in OCI layout %s", ocispec.ImageLayoutVersion)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		idx.MediaType = ocispec.MediaTypeImageIndex
 | 
							idx.MediaType = ocispec.MediaTypeImageIndex
 | 
				
			||||||
@@ -147,7 +147,7 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opt
 | 
				
			|||||||
	for name, linkname := range symlinks {
 | 
						for name, linkname := range symlinks {
 | 
				
			||||||
		desc, ok := blobs[linkname]
 | 
							desc, ok := blobs[linkname]
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return ocispec.Descriptor{}, errors.Errorf("no target for symlink layer from %q to %q", name, linkname)
 | 
								return ocispec.Descriptor{}, fmt.Errorf("no target for symlink layer from %q to %q", name, linkname)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		blobs[name] = desc
 | 
							blobs[name] = desc
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -160,13 +160,13 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opt
 | 
				
			|||||||
	for _, mfst := range mfsts {
 | 
						for _, mfst := range mfsts {
 | 
				
			||||||
		config, ok := blobs[mfst.Config]
 | 
							config, ok := blobs[mfst.Config]
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return ocispec.Descriptor{}, errors.Errorf("image config %q not found", mfst.Config)
 | 
								return ocispec.Descriptor{}, fmt.Errorf("image config %q not found", mfst.Config)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		config.MediaType = images.MediaTypeDockerSchema2Config
 | 
							config.MediaType = images.MediaTypeDockerSchema2Config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		layers, err := resolveLayers(ctx, store, mfst.Layers, blobs, iopts.compress)
 | 
							layers, err := resolveLayers(ctx, store, mfst.Layers, blobs, iopts.compress)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return ocispec.Descriptor{}, errors.Wrap(err, "failed to resolve layers")
 | 
								return ocispec.Descriptor{}, fmt.Errorf("failed to resolve layers: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		manifest := struct {
 | 
							manifest := struct {
 | 
				
			||||||
@@ -183,12 +183,12 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opt
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		desc, err := writeManifest(ctx, store, manifest, manifest.MediaType)
 | 
							desc, err := writeManifest(ctx, store, manifest, manifest.MediaType)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return ocispec.Descriptor{}, errors.Wrap(err, "write docker manifest")
 | 
								return ocispec.Descriptor{}, fmt.Errorf("write docker manifest: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		imgPlatforms, err := images.Platforms(ctx, store, desc)
 | 
							imgPlatforms, err := images.Platforms(ctx, store, desc)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return ocispec.Descriptor{}, errors.Wrap(err, "unable to resolve platform")
 | 
								return ocispec.Descriptor{}, fmt.Errorf("unable to resolve platform: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(imgPlatforms) > 0 {
 | 
							if len(imgPlatforms) > 0 {
 | 
				
			||||||
			// Only one platform can be resolved from non-index manifest,
 | 
								// Only one platform can be resolved from non-index manifest,
 | 
				
			||||||
@@ -257,7 +257,7 @@ func resolveLayers(ctx context.Context, store content.Store, layerFiles []string
 | 
				
			|||||||
	for i, f := range layerFiles {
 | 
						for i, f := range layerFiles {
 | 
				
			||||||
		desc, ok := blobs[f]
 | 
							desc, ok := blobs[f]
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return nil, errors.Errorf("layer %q not found", f)
 | 
								return nil, fmt.Errorf("layer %q not found", f)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		layers[i] = desc
 | 
							layers[i] = desc
 | 
				
			||||||
		descs[desc.Digest] = &layers[i]
 | 
							descs[desc.Digest] = &layers[i]
 | 
				
			||||||
@@ -277,7 +277,7 @@ func resolveLayers(ctx context.Context, store content.Store, layerFiles []string
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, filters...)
 | 
						}, filters...)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failure checking for compressed blobs")
 | 
							return nil, fmt.Errorf("failure checking for compressed blobs: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i, desc := range layers {
 | 
						for i, desc := range layers {
 | 
				
			||||||
@@ -287,12 +287,12 @@ func resolveLayers(ctx context.Context, store content.Store, layerFiles []string
 | 
				
			|||||||
		// Open blob, resolve media type
 | 
							// Open blob, resolve media type
 | 
				
			||||||
		ra, err := store.ReaderAt(ctx, desc)
 | 
							ra, err := store.ReaderAt(ctx, desc)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "failed to open %q (%s)", layerFiles[i], desc.Digest)
 | 
								return nil, fmt.Errorf("failed to open %q (%s): %w", layerFiles[i], desc.Digest, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		s, err := compression.DecompressStream(content.NewReader(ra))
 | 
							s, err := compression.DecompressStream(content.NewReader(ra))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ra.Close()
 | 
								ra.Close()
 | 
				
			||||||
			return nil, errors.Wrapf(err, "failed to detect compression for %q", layerFiles[i])
 | 
								return nil, fmt.Errorf("failed to detect compression for %q: %w", layerFiles[i], err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if s.GetCompression() == compression.Uncompressed {
 | 
							if s.GetCompression() == compression.Uncompressed {
 | 
				
			||||||
			if compress {
 | 
								if compress {
 | 
				
			||||||
@@ -322,7 +322,7 @@ func resolveLayers(ctx context.Context, store content.Store, layerFiles []string
 | 
				
			|||||||
func compressBlob(ctx context.Context, cs content.Store, r io.Reader, ref string, opts ...content.Opt) (desc ocispec.Descriptor, err error) {
 | 
					func compressBlob(ctx context.Context, cs content.Store, r io.Reader, ref string, opts ...content.Opt) (desc ocispec.Descriptor, err error) {
 | 
				
			||||||
	w, err := content.OpenWriter(ctx, cs, content.WithRef(ref))
 | 
						w, err := content.OpenWriter(ctx, cs, content.WithRef(ref))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return ocispec.Descriptor{}, errors.Wrap(err, "failed to open writer")
 | 
							return ocispec.Descriptor{}, fmt.Errorf("failed to open writer: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
@@ -332,7 +332,7 @@ func compressBlob(ctx context.Context, cs content.Store, r io.Reader, ref string
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	if err := w.Truncate(0); err != nil {
 | 
						if err := w.Truncate(0); err != nil {
 | 
				
			||||||
		return ocispec.Descriptor{}, errors.Wrap(err, "failed to truncate writer")
 | 
							return ocispec.Descriptor{}, fmt.Errorf("failed to truncate writer: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cw, err := compression.CompressStream(w, compression.Gzip)
 | 
						cw, err := compression.CompressStream(w, compression.Gzip)
 | 
				
			||||||
@@ -349,7 +349,7 @@ func compressBlob(ctx context.Context, cs content.Store, r io.Reader, ref string
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cst, err := w.Status()
 | 
						cst, err := w.Status()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return ocispec.Descriptor{}, errors.Wrap(err, "failed to get writer status")
 | 
							return ocispec.Descriptor{}, fmt.Errorf("failed to get writer status: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	desc.Digest = w.Digest()
 | 
						desc.Digest = w.Digest()
 | 
				
			||||||
@@ -357,7 +357,7 @@ func compressBlob(ctx context.Context, cs content.Store, r io.Reader, ref string
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if err := w.Commit(ctx, desc.Size, desc.Digest, opts...); err != nil {
 | 
						if err := w.Commit(ctx, desc.Size, desc.Digest, opts...); err != nil {
 | 
				
			||||||
		if !errdefs.IsAlreadyExists(err) {
 | 
							if !errdefs.IsAlreadyExists(err) {
 | 
				
			||||||
			return ocispec.Descriptor{}, errors.Wrap(err, "failed to commit")
 | 
								return ocispec.Descriptor{}, fmt.Errorf("failed to commit: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,12 +17,12 @@
 | 
				
			|||||||
package archive
 | 
					package archive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/reference"
 | 
						"github.com/containerd/containerd/reference"
 | 
				
			||||||
	distref "github.com/containerd/containerd/reference/docker"
 | 
						distref "github.com/containerd/containerd/reference/docker"
 | 
				
			||||||
	"github.com/opencontainers/go-digest"
 | 
						"github.com/opencontainers/go-digest"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FilterRefPrefix restricts references to having the given image
 | 
					// FilterRefPrefix restricts references to having the given image
 | 
				
			||||||
@@ -72,7 +72,7 @@ func normalizeReference(ref string) (string, error) {
 | 
				
			|||||||
	// TODO: Replace this function to not depend on reference package
 | 
						// TODO: Replace this function to not depend on reference package
 | 
				
			||||||
	normalized, err := distref.ParseDockerRef(ref)
 | 
						normalized, err := distref.ParseDockerRef(ref)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", errors.Wrapf(err, "normalize image ref %q", ref)
 | 
							return "", fmt.Errorf("normalize image ref %q: %w", ref, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return normalized.String(), nil
 | 
						return normalized.String(), nil
 | 
				
			||||||
@@ -81,7 +81,7 @@ func normalizeReference(ref string) (string, error) {
 | 
				
			|||||||
func familiarizeReference(ref string) (string, error) {
 | 
					func familiarizeReference(ref string) (string, error) {
 | 
				
			||||||
	named, err := distref.ParseNormalizedNamed(ref)
 | 
						named, err := distref.ParseNormalizedNamed(ref)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", errors.Wrapf(err, "failed to parse %q", ref)
 | 
							return "", fmt.Errorf("failed to parse %q: %w", ref, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	named = distref.TagNameOnly(named)
 | 
						named = distref.TagNameOnly(named)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package images
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +26,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/platforms"
 | 
						"github.com/containerd/containerd/platforms"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"golang.org/x/sync/errgroup"
 | 
						"golang.org/x/sync/errgroup"
 | 
				
			||||||
	"golang.org/x/sync/semaphore"
 | 
						"golang.org/x/sync/semaphore"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -308,7 +308,7 @@ func LimitManifests(f HandlerFunc, m platforms.MatchComparer, n int) HandlerFunc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if n > 0 {
 | 
								if n > 0 {
 | 
				
			||||||
				if len(children) == 0 {
 | 
									if len(children) == 0 {
 | 
				
			||||||
					return children, errors.Wrap(errdefs.ErrNotFound, "no match for platform in manifest")
 | 
										return children, fmt.Errorf("no match for platform in manifest: %w", errdefs.ErrNotFound)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if len(children) > n {
 | 
									if len(children) > n {
 | 
				
			||||||
					children = children[:n]
 | 
										children = children[:n]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/platforms"
 | 
						"github.com/containerd/containerd/platforms"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Image provides the model for how containerd views container images.
 | 
					// Image provides the model for how containerd views container images.
 | 
				
			||||||
@@ -115,7 +114,7 @@ func (image *Image) Size(ctx context.Context, provider content.Provider, platfor
 | 
				
			|||||||
	var size int64
 | 
						var size int64
 | 
				
			||||||
	return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
 | 
						return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
 | 
				
			||||||
		if desc.Size < 0 {
 | 
							if desc.Size < 0 {
 | 
				
			||||||
			return nil, errors.Errorf("invalid size %v in %v (%v)", desc.Size, desc.Digest, desc.MediaType)
 | 
								return nil, fmt.Errorf("invalid size %v in %v (%v)", desc.Size, desc.Digest, desc.MediaType)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		size += desc.Size
 | 
							size += desc.Size
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
@@ -156,7 +155,7 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := validateMediaType(p, desc.MediaType); err != nil {
 | 
								if err := validateMediaType(p, desc.MediaType); err != nil {
 | 
				
			||||||
				return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
 | 
									return nil, fmt.Errorf("manifest: invalid desc %s: %w", desc.Digest, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var manifest ocispec.Manifest
 | 
								var manifest ocispec.Manifest
 | 
				
			||||||
@@ -200,7 +199,7 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := validateMediaType(p, desc.MediaType); err != nil {
 | 
								if err := validateMediaType(p, desc.MediaType); err != nil {
 | 
				
			||||||
				return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
 | 
									return nil, fmt.Errorf("manifest: invalid desc %s: %w", desc.Digest, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var idx ocispec.Index
 | 
								var idx ocispec.Index
 | 
				
			||||||
@@ -236,15 +235,15 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			return descs, nil
 | 
								return descs, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil, errors.Wrapf(errdefs.ErrNotFound, "unexpected media type %v for %v", desc.MediaType, desc.Digest)
 | 
							return nil, fmt.Errorf("unexpected media type %v for %v: %w", desc.MediaType, desc.Digest, errdefs.ErrNotFound)
 | 
				
			||||||
	}), image); err != nil {
 | 
						}), image); err != nil {
 | 
				
			||||||
		return ocispec.Manifest{}, err
 | 
							return ocispec.Manifest{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(m) == 0 {
 | 
						if len(m) == 0 {
 | 
				
			||||||
		err := errors.Wrapf(errdefs.ErrNotFound, "manifest %v", image.Digest)
 | 
							err := fmt.Errorf("manifest %v: %w", image.Digest, errdefs.ErrNotFound)
 | 
				
			||||||
		if wasIndex {
 | 
							if wasIndex {
 | 
				
			||||||
			err = errors.Wrapf(errdefs.ErrNotFound, "no match for platform in manifest %v", image.Digest)
 | 
								err = fmt.Errorf("no match for platform in manifest %v: %w", image.Digest, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return ocispec.Manifest{}, err
 | 
							return ocispec.Manifest{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -309,7 +308,7 @@ func Check(ctx context.Context, provider content.Provider, image ocispec.Descrip
 | 
				
			|||||||
			return false, []ocispec.Descriptor{image}, nil, []ocispec.Descriptor{image}, nil
 | 
								return false, []ocispec.Descriptor{image}, nil, []ocispec.Descriptor{image}, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return false, nil, nil, nil, errors.Wrapf(err, "failed to check image %v", image.Digest)
 | 
							return false, nil, nil, nil, fmt.Errorf("failed to check image %v: %w", image.Digest, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO(stevvooe): It is possible that referenced conponents could have
 | 
						// TODO(stevvooe): It is possible that referenced conponents could have
 | 
				
			||||||
@@ -324,7 +323,7 @@ func Check(ctx context.Context, provider content.Provider, image ocispec.Descrip
 | 
				
			|||||||
				missing = append(missing, desc)
 | 
									missing = append(missing, desc)
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return false, nil, nil, nil, errors.Wrapf(err, "failed to check image %v", desc.Digest)
 | 
									return false, nil, nil, nil, fmt.Errorf("failed to check image %v: %w", desc.Digest, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ra.Close()
 | 
							ra.Close()
 | 
				
			||||||
@@ -346,7 +345,7 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := validateMediaType(p, desc.MediaType); err != nil {
 | 
							if err := validateMediaType(p, desc.MediaType); err != nil {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
 | 
								return nil, fmt.Errorf("children: invalid desc %s: %w", desc.Digest, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// TODO(stevvooe): We just assume oci manifest, for now. There may be
 | 
							// TODO(stevvooe): We just assume oci manifest, for now. There may be
 | 
				
			||||||
@@ -365,7 +364,7 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := validateMediaType(p, desc.MediaType); err != nil {
 | 
							if err := validateMediaType(p, desc.MediaType); err != nil {
 | 
				
			||||||
			return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
 | 
								return nil, fmt.Errorf("children: invalid desc %s: %w", desc.Digest, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var index ocispec.Index
 | 
							var index ocispec.Index
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,12 +18,12 @@ package images
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// mediatype definitions for image components handled in containerd.
 | 
					// mediatype definitions for image components handled in containerd.
 | 
				
			||||||
@@ -87,7 +87,7 @@ func DiffCompression(ctx context.Context, mediaType string) (string, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return "", nil
 | 
							return "", nil
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return "", errors.Wrapf(errdefs.ErrNotImplemented, "unrecognised mediatype %s", mediaType)
 | 
							return "", fmt.Errorf("unrecognised mediatype %s: %w", mediaType, errdefs.ErrNotImplemented)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,8 @@ package containerd
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"archive/tar"
 | 
						"archive/tar"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
@@ -28,7 +30,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/archive/compression"
 | 
						"github.com/containerd/containerd/archive/compression"
 | 
				
			||||||
	"github.com/containerd/containerd/content"
 | 
						"github.com/containerd/containerd/content"
 | 
				
			||||||
	"github.com/containerd/containerd/images"
 | 
						"github.com/containerd/containerd/images"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Install a binary image into the opt service
 | 
					// Install a binary image into the opt service
 | 
				
			||||||
@@ -82,7 +83,7 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts)
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			if result && !config.Replace {
 | 
								if result && !config.Replace {
 | 
				
			||||||
				if _, err := os.Lstat(filepath.Join(path, hdr.Name)); err == nil {
 | 
									if _, err := os.Lstat(filepath.Join(path, hdr.Name)); err == nil {
 | 
				
			||||||
					return false, errors.Errorf("cannot replace %s in %s", hdr.Name, path)
 | 
										return false, fmt.Errorf("cannot replace %s in %s", hdr.Name, path)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return result, nil
 | 
								return result, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	gogotypes "github.com/gogo/protobuf/types"
 | 
						gogotypes "github.com/gogo/protobuf/types"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1903,7 +1902,7 @@ func TestRegressionIssue4769(t *testing.T) {
 | 
				
			|||||||
	select {
 | 
						select {
 | 
				
			||||||
	case et := <-statusC:
 | 
						case et := <-statusC:
 | 
				
			||||||
		if got := et.ExitCode(); got != 0 {
 | 
							if got := et.ExitCode(); got != 0 {
 | 
				
			||||||
			t.Fatal(errors.Errorf("expect zero exit status, but got %v", got))
 | 
								t.Fatal(fmt.Errorf("expect zero exit status, but got %v", got))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case <-time.After(timeout):
 | 
						case <-time.After(timeout):
 | 
				
			||||||
		t.Fatal(fmt.Errorf("failed to get exit event in time"))
 | 
							t.Fatal(fmt.Errorf("failed to get exit event in time"))
 | 
				
			||||||
@@ -1913,21 +1912,21 @@ func TestRegressionIssue4769(t *testing.T) {
 | 
				
			|||||||
	select {
 | 
						select {
 | 
				
			||||||
	case et := <-eventStream:
 | 
						case et := <-eventStream:
 | 
				
			||||||
		if et.Event == nil {
 | 
							if et.Event == nil {
 | 
				
			||||||
			t.Fatal(errors.Errorf("unexpected empty event: %+v", et))
 | 
								t.Fatal(fmt.Errorf("unexpected empty event: %+v", et))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		v, err := typeurl.UnmarshalAny(et.Event)
 | 
							v, err := typeurl.UnmarshalAny(et.Event)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatal(errors.Wrap(err, "failed to unmarshal event"))
 | 
								t.Fatal(fmt.Errorf("failed to unmarshal event: %w", err))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if e, ok := v.(*apievents.TaskExit); !ok {
 | 
							if e, ok := v.(*apievents.TaskExit); !ok {
 | 
				
			||||||
			t.Fatal(errors.Errorf("unexpected event type: %+v", v))
 | 
								t.Fatal(fmt.Errorf("unexpected event type: %+v", v))
 | 
				
			||||||
		} else if e.ExitStatus != 0 {
 | 
							} else if e.ExitStatus != 0 {
 | 
				
			||||||
			t.Fatal(errors.Errorf("expect zero exit status, but got %v", e.ExitStatus))
 | 
								t.Fatal(fmt.Errorf("expect zero exit status, but got %v", e.ExitStatus))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case err := <-errC:
 | 
						case err := <-errC:
 | 
				
			||||||
		t.Fatal(errors.Wrap(err, "unexpected error from event service"))
 | 
							t.Fatal(fmt.Errorf("unexpected error from event service: %w", err))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case <-time.After(timeout):
 | 
						case <-time.After(timeout):
 | 
				
			||||||
		t.Fatal(fmt.Errorf("failed to get exit event in time"))
 | 
							t.Fatal(fmt.Errorf("failed to get exit event in time"))
 | 
				
			||||||
@@ -1940,9 +1939,9 @@ func TestRegressionIssue4769(t *testing.T) {
 | 
				
			|||||||
	// check duplicate event should not show up
 | 
						// check duplicate event should not show up
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case event := <-eventStream:
 | 
						case event := <-eventStream:
 | 
				
			||||||
		t.Fatal(errors.Errorf("unexpected exit event: %+v", event))
 | 
							t.Fatal(fmt.Errorf("unexpected exit event: %+v", event))
 | 
				
			||||||
	case err := <-errC:
 | 
						case err := <-errC:
 | 
				
			||||||
		t.Fatal(errors.Wrap(err, "unexpected error from event service"))
 | 
							t.Fatal(fmt.Errorf("unexpected error from event service: %w", err))
 | 
				
			||||||
	case <-time.After(timeout):
 | 
						case <-time.After(timeout):
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/content/testsuite"
 | 
						"github.com/containerd/containerd/content/testsuite"
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/namespaces"
 | 
						"github.com/containerd/containerd/namespaces"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newContentStore(ctx context.Context, root string) (context.Context, content.Store, func() error, error) {
 | 
					func newContentStore(ctx context.Context, root string) (context.Context, content.Store, func() error, error) {
 | 
				
			||||||
@@ -59,7 +58,7 @@ func newContentStore(ctx context.Context, root string) (context.Context, content
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			for _, st := range statuses {
 | 
								for _, st := range statuses {
 | 
				
			||||||
				if err := cs.Abort(ctx, st.Ref); err != nil && !errdefs.IsNotFound(err) {
 | 
									if err := cs.Abort(ctx, st.Ref); err != nil && !errdefs.IsNotFound(err) {
 | 
				
			||||||
					return errors.Wrapf(err, "failed to abort %s", st.Ref)
 | 
										return fmt.Errorf("failed to abort %s: %w", st.Ref, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			err = cs.Walk(ctx, func(info content.Info) error {
 | 
								err = cs.Walk(ctx, func(info content.Info) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,13 +18,14 @@ package client
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	. "github.com/containerd/containerd"
 | 
						. "github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	exec "golang.org/x/sys/execabs"
 | 
						exec "golang.org/x/sys/execabs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,7 +47,7 @@ func (d *daemon) start(name, address string, args []string, stdout, stderr io.Wr
 | 
				
			|||||||
	cmd.Stderr = stderr
 | 
						cmd.Stderr = stderr
 | 
				
			||||||
	if err := cmd.Start(); err != nil {
 | 
						if err := cmd.Start(); err != nil {
 | 
				
			||||||
		cmd.Wait()
 | 
							cmd.Wait()
 | 
				
			||||||
		return errors.Wrap(err, "failed to start daemon")
 | 
							return fmt.Errorf("failed to start daemon: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d.addr = address
 | 
						d.addr = address
 | 
				
			||||||
	d.cmd = cmd
 | 
						d.cmd = cmd
 | 
				
			||||||
@@ -117,7 +118,7 @@ func (d *daemon) Restart(stopCb func()) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	if err = d.cmd.Process.Signal(signal); err != nil {
 | 
						if err = d.cmd.Process.Signal(signal); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to signal daemon")
 | 
							return fmt.Errorf("failed to signal daemon: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	d.cmd.Wait()
 | 
						d.cmd.Wait()
 | 
				
			||||||
@@ -131,7 +132,7 @@ func (d *daemon) Restart(stopCb func()) error {
 | 
				
			|||||||
	cmd.Stderr = d.cmd.Stderr
 | 
						cmd.Stderr = d.cmd.Stderr
 | 
				
			||||||
	if err := cmd.Start(); err != nil {
 | 
						if err := cmd.Start(); err != nil {
 | 
				
			||||||
		cmd.Wait()
 | 
							cmd.Wait()
 | 
				
			||||||
		return errors.Wrap(err, "failed to start new daemon instance")
 | 
							return fmt.Errorf("failed to start new daemon instance: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d.cmd = cmd
 | 
						d.cmd = cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,6 @@ require (
 | 
				
			|||||||
	github.com/opencontainers/go-digest v1.0.0
 | 
						github.com/opencontainers/go-digest v1.0.0
 | 
				
			||||||
	github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5
 | 
						github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5
 | 
				
			||||||
	github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
 | 
						github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
 | 
				
			||||||
	github.com/pkg/errors v0.9.1
 | 
					 | 
				
			||||||
	github.com/sirupsen/logrus v1.8.1
 | 
						github.com/sirupsen/logrus v1.8.1
 | 
				
			||||||
	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
 | 
						golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
 | 
				
			||||||
	gotest.tools/v3 v3.0.3
 | 
						gotest.tools/v3 v3.0.3
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,12 +17,12 @@
 | 
				
			|||||||
package integration
 | 
					package integration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	goruntime "runtime"
 | 
						goruntime "runtime"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
	runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
						runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
				
			||||||
@@ -372,7 +372,7 @@ func TestContainerListStatsWithIdSandboxIdFilter(t *testing.T) {
 | 
				
			|||||||
				return false, err
 | 
									return false, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if len(stats) != 1 {
 | 
								if len(stats) != 1 {
 | 
				
			||||||
				return false, errors.Errorf("expected only one stat, but got %v", stats)
 | 
									return false, fmt.Errorf("expected only one stat, but got %v", stats)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if stats[0].GetWritableLayer().GetUsedBytes().GetValue() != 0 {
 | 
								if stats[0].GetWritableLayer().GetUsedBytes().GetValue() != 0 {
 | 
				
			||||||
				return true, nil
 | 
									return true, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,17 +17,17 @@
 | 
				
			|||||||
package integration
 | 
					package integration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/containerd/containerd"
 | 
						"github.com/containerd/containerd"
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/containerd/containerd/namespaces"
 | 
						"github.com/containerd/containerd/namespaces"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
	runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
						runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -77,10 +77,10 @@ func TestContainerdImage(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		if len(img.RepoTags) != 1 {
 | 
							if len(img.RepoTags) != 1 {
 | 
				
			||||||
			// RepoTags must have been populated correctly.
 | 
								// RepoTags must have been populated correctly.
 | 
				
			||||||
			return false, errors.Errorf("unexpected repotags: %+v", img.RepoTags)
 | 
								return false, fmt.Errorf("unexpected repotags: %+v", img.RepoTags)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if img.RepoTags[0] != testImage {
 | 
							if img.RepoTags[0] != testImage {
 | 
				
			||||||
			return false, errors.Errorf("unexpected repotag %q", img.RepoTags[0])
 | 
								return false, fmt.Errorf("unexpected repotag %q", img.RepoTags[0])
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return true, nil
 | 
							return true, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,11 @@
 | 
				
			|||||||
package integration
 | 
					package integration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
	runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
						runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
				
			||||||
@@ -47,7 +47,7 @@ func TestImageFSInfo(t *testing.T) {
 | 
				
			|||||||
			return false, nil
 | 
								return false, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(stats) >= 2 {
 | 
							if len(stats) >= 2 {
 | 
				
			||||||
			return false, errors.Errorf("unexpected stats length: %d", len(stats))
 | 
								return false, fmt.Errorf("unexpected stats length: %d", len(stats))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		info = stats[0]
 | 
							info = stats[0]
 | 
				
			||||||
		if info.GetTimestamp() != 0 &&
 | 
							if info.GetTimestamp() != 0 &&
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package integration
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"flag"
 | 
						"flag"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -37,7 +38,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/pkg/cri/constants"
 | 
						"github.com/containerd/containerd/pkg/cri/constants"
 | 
				
			||||||
	"github.com/containerd/containerd/pkg/cri/server"
 | 
						"github.com/containerd/containerd/pkg/cri/server"
 | 
				
			||||||
	"github.com/containerd/containerd/pkg/cri/util"
 | 
						"github.com/containerd/containerd/pkg/cri/util"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
@@ -78,29 +78,29 @@ func ConnectDaemons() error {
 | 
				
			|||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	runtimeService, err = remote.NewRuntimeService(*criEndpoint, timeout)
 | 
						runtimeService, err = remote.NewRuntimeService(*criEndpoint, timeout)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create runtime service")
 | 
							return fmt.Errorf("failed to create runtime service: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	imageService, err = remote.NewImageService(*criEndpoint, timeout)
 | 
						imageService, err = remote.NewImageService(*criEndpoint, timeout)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to create image service")
 | 
							return fmt.Errorf("failed to create image service: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Since CRI grpc client doesn't have `WithBlock` specified, we
 | 
						// Since CRI grpc client doesn't have `WithBlock` specified, we
 | 
				
			||||||
	// need to check whether it is actually connected.
 | 
						// need to check whether it is actually connected.
 | 
				
			||||||
	// TODO(#6069) Use grpc options to block on connect and remove for this list containers request.
 | 
						// TODO(#6069) Use grpc options to block on connect and remove for this list containers request.
 | 
				
			||||||
	_, err = runtimeService.ListContainers(&runtime.ContainerFilter{})
 | 
						_, err = runtimeService.ListContainers(&runtime.ContainerFilter{})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to list containers")
 | 
							return fmt.Errorf("failed to list containers: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_, err = imageService.ListImages(&runtime.ImageFilter{})
 | 
						_, err = imageService.ListImages(&runtime.ImageFilter{})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to list images")
 | 
							return fmt.Errorf("failed to list images: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// containerdEndpoint is the same with criEndpoint now
 | 
						// containerdEndpoint is the same with criEndpoint now
 | 
				
			||||||
	containerdEndpoint = strings.TrimPrefix(*criEndpoint, "unix://")
 | 
						containerdEndpoint = strings.TrimPrefix(*criEndpoint, "unix://")
 | 
				
			||||||
	containerdEndpoint = strings.TrimPrefix(containerdEndpoint, "npipe:")
 | 
						containerdEndpoint = strings.TrimPrefix(containerdEndpoint, "npipe:")
 | 
				
			||||||
	containerdClient, err = containerd.New(containerdEndpoint, containerd.WithDefaultNamespace(k8sNamespace))
 | 
						containerdClient, err = containerd.New(containerdEndpoint, containerd.WithDefaultNamespace(k8sNamespace))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "failed to connect containerd")
 | 
							return fmt.Errorf("failed to connect containerd: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -371,7 +371,7 @@ func KillProcess(name string) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	output, err := exec.Command(command[0], command[1:]...).CombinedOutput()
 | 
						output, err := exec.Command(command[0], command[1:]...).CombinedOutput()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Errorf("failed to kill %q - error: %v, output: %q", name, err, output)
 | 
							return fmt.Errorf("failed to kill %q - error: %v, output: %q", name, err, output)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -380,7 +380,7 @@ func KillProcess(name string) error {
 | 
				
			|||||||
func KillPid(pid int) error { //nolint:unused
 | 
					func KillPid(pid int) error { //nolint:unused
 | 
				
			||||||
	output, err := exec.Command("kill", strconv.Itoa(pid)).CombinedOutput()
 | 
						output, err := exec.Command("kill", strconv.Itoa(pid)).CombinedOutput()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.Errorf("failed to kill %d - error: %v, output: %q", pid, err, output)
 | 
							return fmt.Errorf("failed to kill %d - error: %v, output: %q", pid, err, output)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -391,7 +391,7 @@ func PidOf(name string) (int, error) {
 | 
				
			|||||||
	output := strings.TrimSpace(string(b))
 | 
						output := strings.TrimSpace(string(b))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if len(output) != 0 {
 | 
							if len(output) != 0 {
 | 
				
			||||||
			return 0, errors.Errorf("failed to run pidof %q - error: %v, output: %q", name, err, output)
 | 
								return 0, fmt.Errorf("failed to run pidof %q - error: %v, output: %q", name, err, output)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return 0, nil
 | 
							return 0, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -402,7 +402,7 @@ func PidOf(name string) (int, error) {
 | 
				
			|||||||
func RawRuntimeClient() (runtime.RuntimeServiceClient, error) {
 | 
					func RawRuntimeClient() (runtime.RuntimeServiceClient, error) {
 | 
				
			||||||
	addr, dialer, err := dialer.GetAddressAndDialer(*criEndpoint)
 | 
						addr, dialer, err := dialer.GetAddressAndDialer(*criEndpoint)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to get dialer")
 | 
							return nil, fmt.Errorf("failed to get dialer: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 | 
						ctx, cancel := context.WithTimeout(context.Background(), timeout)
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
@@ -411,7 +411,7 @@ func RawRuntimeClient() (runtime.RuntimeServiceClient, error) {
 | 
				
			|||||||
		grpc.WithContextDialer(dialer),
 | 
							grpc.WithContextDialer(dialer),
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to connect cri endpoint")
 | 
							return nil, fmt.Errorf("failed to connect cri endpoint: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return runtime.NewRuntimeServiceClient(conn), nil
 | 
						return runtime.NewRuntimeServiceClient(conn), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -420,15 +420,15 @@ func RawRuntimeClient() (runtime.RuntimeServiceClient, error) {
 | 
				
			|||||||
func CRIConfig() (*criconfig.Config, error) {
 | 
					func CRIConfig() (*criconfig.Config, error) {
 | 
				
			||||||
	client, err := RawRuntimeClient()
 | 
						client, err := RawRuntimeClient()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to get raw runtime client")
 | 
							return nil, fmt.Errorf("failed to get raw runtime client: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resp, err := client.Status(context.Background(), &runtime.StatusRequest{Verbose: true})
 | 
						resp, err := client.Status(context.Background(), &runtime.StatusRequest{Verbose: true})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to get status")
 | 
							return nil, fmt.Errorf("failed to get status: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	config := &criconfig.Config{}
 | 
						config := &criconfig.Config{}
 | 
				
			||||||
	if err := json.Unmarshal([]byte(resp.Info["config"]), config); err != nil {
 | 
						if err := json.Unmarshal([]byte(resp.Info["config"]), config); err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to unmarshal config")
 | 
							return nil, fmt.Errorf("failed to unmarshal config: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return config, nil
 | 
						return config, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -437,19 +437,19 @@ func CRIConfig() (*criconfig.Config, error) {
 | 
				
			|||||||
func SandboxInfo(id string) (*runtime.PodSandboxStatus, *server.SandboxInfo, error) { //nolint:unused
 | 
					func SandboxInfo(id string) (*runtime.PodSandboxStatus, *server.SandboxInfo, error) { //nolint:unused
 | 
				
			||||||
	client, err := RawRuntimeClient()
 | 
						client, err := RawRuntimeClient()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, nil, errors.Wrap(err, "failed to get raw runtime client")
 | 
							return nil, nil, fmt.Errorf("failed to get raw runtime client: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resp, err := client.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{
 | 
						resp, err := client.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{
 | 
				
			||||||
		PodSandboxId: id,
 | 
							PodSandboxId: id,
 | 
				
			||||||
		Verbose:      true,
 | 
							Verbose:      true,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, nil, errors.Wrap(err, "failed to get sandbox status")
 | 
							return nil, nil, fmt.Errorf("failed to get sandbox status: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	status := resp.GetStatus()
 | 
						status := resp.GetStatus()
 | 
				
			||||||
	var info server.SandboxInfo
 | 
						var info server.SandboxInfo
 | 
				
			||||||
	if err := json.Unmarshal([]byte(resp.GetInfo()["info"]), &info); err != nil {
 | 
						if err := json.Unmarshal([]byte(resp.GetInfo()["info"]), &info); err != nil {
 | 
				
			||||||
		return nil, nil, errors.Wrap(err, "failed to unmarshal sandbox info")
 | 
							return nil, nil, fmt.Errorf("failed to unmarshal sandbox info: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return status, &info, nil
 | 
						return status, &info, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ package integration
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
@@ -33,7 +34,6 @@ import (
 | 
				
			|||||||
	v1shimcli "github.com/containerd/containerd/runtime/v1/shim/client"
 | 
						v1shimcli "github.com/containerd/containerd/runtime/v1/shim/client"
 | 
				
			||||||
	v2shimcli "github.com/containerd/containerd/runtime/v2/shim"
 | 
						v2shimcli "github.com/containerd/containerd/runtime/v2/shim"
 | 
				
			||||||
	"github.com/containerd/ttrpc"
 | 
						"github.com/containerd/ttrpc"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const abstractSocketPrefix = "\x00"
 | 
					const abstractSocketPrefix = "\x00"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,8 +17,9 @@
 | 
				
			|||||||
package labels
 | 
					package labels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/errdefs"
 | 
						"github.com/containerd/containerd/errdefs"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -31,7 +32,7 @@ func Validate(k, v string) error {
 | 
				
			|||||||
		if len(k) > 10 {
 | 
							if len(k) > 10 {
 | 
				
			||||||
			k = k[:10]
 | 
								k = k[:10]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "label key and value greater than maximum size (%d bytes), key: %s", maxSize, k)
 | 
							return fmt.Errorf("label key and value greater than maximum size (%d bytes), key: %s: %w", maxSize, k, errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,8 +18,8 @@ package metadata
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,7 +55,7 @@ func update(ctx context.Context, db transactor, fn func(*bolt.Tx) error) error {
 | 
				
			|||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		return db.Update(fn)
 | 
							return db.Update(fn)
 | 
				
			||||||
	} else if !tx.Writable() {
 | 
						} else if !tx.Writable() {
 | 
				
			||||||
		return errors.Wrap(bolt.ErrTxNotWritable, "unable to use transaction from context")
 | 
							return fmt.Errorf("unable to use transaction from context: %w", bolt.ErrTxNotWritable)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return fn(tx)
 | 
						return fn(tx)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,11 @@
 | 
				
			|||||||
package boltutil
 | 
					package boltutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gogo/protobuf/proto"
 | 
						"github.com/gogo/protobuf/proto"
 | 
				
			||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -99,7 +99,7 @@ func writeMap(bkt *bolt.Bucket, bucketName []byte, labels map[string]string) err
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := lbkt.Put([]byte(k), []byte(v)); err != nil {
 | 
							if err := lbkt.Put([]byte(k), []byte(v)); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to set label %q=%q", k, v)
 | 
								return fmt.Errorf("failed to set label %q=%q: %w", k, v, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -228,7 +228,7 @@ func ReadAny(bkt *bolt.Bucket, name []byte) (*types.Any, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	out := types.Any{}
 | 
						out := types.Any{}
 | 
				
			||||||
	if err := proto.Unmarshal(bytes, &out); err != nil {
 | 
						if err := proto.Unmarshal(bytes, &out); err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(err, "failed to unmarshal any")
 | 
							return nil, fmt.Errorf("failed to unmarshal any: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &out, nil
 | 
						return &out, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,13 +17,13 @@
 | 
				
			|||||||
package metadata
 | 
					package metadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/labels"
 | 
						"github.com/containerd/containerd/labels"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package metadata
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync/atomic"
 | 
						"sync/atomic"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -31,7 +32,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/namespaces"
 | 
						"github.com/containerd/containerd/namespaces"
 | 
				
			||||||
	"github.com/gogo/protobuf/proto"
 | 
						"github.com/gogo/protobuf/proto"
 | 
				
			||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,11 +57,11 @@ func (s *containerStore) Get(ctx context.Context, id string) (containers.Contain
 | 
				
			|||||||
	if err := view(ctx, s.db, func(tx *bolt.Tx) error {
 | 
						if err := view(ctx, s.db, func(tx *bolt.Tx) error {
 | 
				
			||||||
		bkt := getContainerBucket(tx, namespace, id)
 | 
							bkt := getContainerBucket(tx, namespace, id)
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "container %q in namespace %q", id, namespace)
 | 
								return fmt.Errorf("container %q in namespace %q: %w", id, namespace, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := readContainer(&container, bkt); err != nil {
 | 
							if err := readContainer(&container, bkt); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to read container %q", id)
 | 
								return fmt.Errorf("failed to read container %q: %w", id, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
@@ -80,7 +80,7 @@ func (s *containerStore) List(ctx context.Context, fs ...string) ([]containers.C
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	filter, err := filters.ParseAll(fs...)
 | 
						filter, err := filters.ParseAll(fs...)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error())
 | 
							return nil, fmt.Errorf("%s: %w", err.Error(), errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var m []containers.Container
 | 
						var m []containers.Container
 | 
				
			||||||
@@ -99,7 +99,7 @@ func (s *containerStore) List(ctx context.Context, fs ...string) ([]containers.C
 | 
				
			|||||||
			container := containers.Container{ID: string(k)}
 | 
								container := containers.Container{ID: string(k)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := readContainer(&container, cbkt); err != nil {
 | 
								if err := readContainer(&container, cbkt); err != nil {
 | 
				
			||||||
				return errors.Wrapf(err, "failed to read container %q", string(k))
 | 
									return fmt.Errorf("failed to read container %q: %w", string(k), err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if filter.Match(adaptContainer(container)) {
 | 
								if filter.Match(adaptContainer(container)) {
 | 
				
			||||||
@@ -121,7 +121,7 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := validateContainer(&container); err != nil {
 | 
						if err := validateContainer(&container); err != nil {
 | 
				
			||||||
		return containers.Container{}, errors.Wrap(err, "create container failed validation")
 | 
							return containers.Container{}, fmt.Errorf("create container failed validation: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := update(ctx, s.db, func(tx *bolt.Tx) error {
 | 
						if err := update(ctx, s.db, func(tx *bolt.Tx) error {
 | 
				
			||||||
@@ -133,7 +133,7 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
 | 
				
			|||||||
		cbkt, err := bkt.CreateBucket([]byte(container.ID))
 | 
							cbkt, err := bkt.CreateBucket([]byte(container.ID))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			if err == bolt.ErrBucketExists {
 | 
								if err == bolt.ErrBucketExists {
 | 
				
			||||||
				err = errors.Wrapf(errdefs.ErrAlreadyExists, "container %q", container.ID)
 | 
									err = fmt.Errorf("container %q: %w", container.ID, errdefs.ErrAlreadyExists)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -141,7 +141,7 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
 | 
				
			|||||||
		container.CreatedAt = time.Now().UTC()
 | 
							container.CreatedAt = time.Now().UTC()
 | 
				
			||||||
		container.UpdatedAt = container.CreatedAt
 | 
							container.UpdatedAt = container.CreatedAt
 | 
				
			||||||
		if err := writeContainer(cbkt, &container); err != nil {
 | 
							if err := writeContainer(cbkt, &container); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to write container %q", container.ID)
 | 
								return fmt.Errorf("failed to write container %q: %w", container.ID, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
@@ -159,23 +159,23 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container.ID == "" {
 | 
						if container.ID == "" {
 | 
				
			||||||
		return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "must specify a container id")
 | 
							return containers.Container{}, fmt.Errorf("must specify a container id: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var updated containers.Container
 | 
						var updated containers.Container
 | 
				
			||||||
	if err := update(ctx, s.db, func(tx *bolt.Tx) error {
 | 
						if err := update(ctx, s.db, func(tx *bolt.Tx) error {
 | 
				
			||||||
		bkt := getContainersBucket(tx, namespace)
 | 
							bkt := getContainersBucket(tx, namespace)
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "cannot update container %q in namespace %q", container.ID, namespace)
 | 
								return fmt.Errorf("cannot update container %q in namespace %q: %w", container.ID, namespace, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cbkt := bkt.Bucket([]byte(container.ID))
 | 
							cbkt := bkt.Bucket([]byte(container.ID))
 | 
				
			||||||
		if cbkt == nil {
 | 
							if cbkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
 | 
								return fmt.Errorf("container %q: %w", container.ID, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := readContainer(&updated, cbkt); err != nil {
 | 
							if err := readContainer(&updated, cbkt); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to read container %q", container.ID)
 | 
								return fmt.Errorf("failed to read container %q: %w", container.ID, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		createdat := updated.CreatedAt
 | 
							createdat := updated.CreatedAt
 | 
				
			||||||
		updated.ID = container.ID
 | 
							updated.ID = container.ID
 | 
				
			||||||
@@ -188,11 +188,11 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
 | 
				
			|||||||
			// are provided. This allows these fields to become mutable in the
 | 
								// are provided. This allows these fields to become mutable in the
 | 
				
			||||||
			// future.
 | 
								// future.
 | 
				
			||||||
			if updated.Snapshotter != container.Snapshotter {
 | 
								if updated.Snapshotter != container.Snapshotter {
 | 
				
			||||||
				return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable")
 | 
									return fmt.Errorf("container.Snapshotter field is immutable: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if updated.Runtime.Name != container.Runtime.Name {
 | 
								if updated.Runtime.Name != container.Runtime.Name {
 | 
				
			||||||
				return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name field is immutable")
 | 
									return fmt.Errorf("container.Runtime.Name field is immutable: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -230,18 +230,18 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
 | 
				
			|||||||
			case "snapshotkey":
 | 
								case "snapshotkey":
 | 
				
			||||||
				updated.SnapshotKey = container.SnapshotKey
 | 
									updated.SnapshotKey = container.SnapshotKey
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
 | 
									return fmt.Errorf("cannot update %q field on %q: %w", path, container.ID, errdefs.ErrInvalidArgument)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := validateContainer(&updated); err != nil {
 | 
							if err := validateContainer(&updated); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "update failed validation")
 | 
								return fmt.Errorf("update failed validation: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		updated.CreatedAt = createdat
 | 
							updated.CreatedAt = createdat
 | 
				
			||||||
		updated.UpdatedAt = time.Now().UTC()
 | 
							updated.UpdatedAt = time.Now().UTC()
 | 
				
			||||||
		if err := writeContainer(cbkt, &updated); err != nil {
 | 
							if err := writeContainer(cbkt, &updated); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "failed to write container %q", container.ID)
 | 
								return fmt.Errorf("failed to write container %q: %w", container.ID, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
@@ -261,12 +261,12 @@ func (s *containerStore) Delete(ctx context.Context, id string) error {
 | 
				
			|||||||
	return update(ctx, s.db, func(tx *bolt.Tx) error {
 | 
						return update(ctx, s.db, func(tx *bolt.Tx) error {
 | 
				
			||||||
		bkt := getContainersBucket(tx, namespace)
 | 
							bkt := getContainersBucket(tx, namespace)
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %q in namespace %q", id, namespace)
 | 
								return fmt.Errorf("cannot delete container %q in namespace %q: %w", id, namespace, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := bkt.DeleteBucket([]byte(id)); err != nil {
 | 
							if err := bkt.DeleteBucket([]byte(id)); err != nil {
 | 
				
			||||||
			if err == bolt.ErrBucketNotFound {
 | 
								if err == bolt.ErrBucketNotFound {
 | 
				
			||||||
				err = errors.Wrapf(errdefs.ErrNotFound, "container %v", id)
 | 
									err = fmt.Errorf("container %v: %w", id, errdefs.ErrNotFound)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -279,32 +279,32 @@ func (s *containerStore) Delete(ctx context.Context, id string) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func validateContainer(container *containers.Container) error {
 | 
					func validateContainer(container *containers.Container) error {
 | 
				
			||||||
	if err := identifiers.Validate(container.ID); err != nil {
 | 
						if err := identifiers.Validate(container.ID); err != nil {
 | 
				
			||||||
		return errors.Wrap(err, "container.ID")
 | 
							return fmt.Errorf("container.ID: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k := range container.Extensions {
 | 
						for k := range container.Extensions {
 | 
				
			||||||
		if k == "" {
 | 
							if k == "" {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Extension keys must not be zero-length")
 | 
								return fmt.Errorf("container.Extension keys must not be zero-length: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// image has no validation
 | 
						// image has no validation
 | 
				
			||||||
	for k, v := range container.Labels {
 | 
						for k, v := range container.Labels {
 | 
				
			||||||
		if err := labels.Validate(k, v); err != nil {
 | 
							if err := labels.Validate(k, v); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "containers.Labels")
 | 
								return fmt.Errorf("containers.Labels: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container.Runtime.Name == "" {
 | 
						if container.Runtime.Name == "" {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name must be set")
 | 
							return fmt.Errorf("container.Runtime.Name must be set: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container.Spec == nil {
 | 
						if container.Spec == nil {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Spec must be set")
 | 
							return fmt.Errorf("container.Spec must be set: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container.SnapshotKey != "" && container.Snapshotter == "" {
 | 
						if container.SnapshotKey != "" && container.Snapshotter == "" {
 | 
				
			||||||
		return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set if container.SnapshotKey is set")
 | 
							return fmt.Errorf("container.Snapshotter must be set if container.SnapshotKey is set: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package metadata
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
@@ -34,7 +35,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/typeurl"
 | 
						"github.com/containerd/typeurl"
 | 
				
			||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
						specs "github.com/opencontainers/runtime-spec/specs-go"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -639,7 +639,7 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 | 
				
			|||||||
				if testcase.createerr == nil {
 | 
									if testcase.createerr == nil {
 | 
				
			||||||
					t.Fatalf("unexpected error: %v", err)
 | 
										t.Fatalf("unexpected error: %v", err)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					t.Fatalf("cause of %v (cause: %v) != %v", err, errors.Cause(err), testcase.createerr)
 | 
										t.Fatalf("cause of %v (cause: %v) != %v", err, errors.Unwrap(err), testcase.createerr)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if testcase.createerr != nil {
 | 
								} else if testcase.createerr != nil {
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
@@ -661,7 +661,7 @@ func TestContainersCreateUpdateDelete(t *testing.T) {
 | 
				
			|||||||
				if testcase.cause == nil {
 | 
									if testcase.cause == nil {
 | 
				
			||||||
					t.Fatalf("unexpected error: %v", err)
 | 
										t.Fatalf("unexpected error: %v", err)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					t.Fatalf("cause of %v (cause: %v) != %v", err, errors.Cause(err), testcase.cause)
 | 
										t.Fatalf("cause of %v (cause: %v) != %v", err, errors.Unwrap(err), testcase.cause)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if testcase.cause != nil {
 | 
								} else if testcase.cause != nil {
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package metadata
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/binary"
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"sync/atomic"
 | 
						"sync/atomic"
 | 
				
			||||||
@@ -33,7 +34,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/namespaces"
 | 
						"github.com/containerd/containerd/namespaces"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,7 +81,7 @@ func (cs *contentStore) Info(ctx context.Context, dgst digest.Digest) (content.I
 | 
				
			|||||||
			bkt = getShareableBucket(tx, dgst)
 | 
								bkt = getShareableBucket(tx, dgst)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "content digest %v", dgst)
 | 
								return fmt.Errorf("content digest %v: %w", dgst, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		info.Digest = dgst
 | 
							info.Digest = dgst
 | 
				
			||||||
@@ -112,10 +112,10 @@ func (cs *contentStore) Update(ctx context.Context, info content.Info, fieldpath
 | 
				
			|||||||
			bkt = getShareableBucket(tx, info.Digest)
 | 
								bkt = getShareableBucket(tx, info.Digest)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "content digest %v", info.Digest)
 | 
								return fmt.Errorf("content digest %v: %w", info.Digest, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := readInfo(&updated, bkt); err != nil {
 | 
							if err := readInfo(&updated, bkt); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "info %q", info.Digest)
 | 
								return fmt.Errorf("info %q: %w", info.Digest, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if len(fieldpaths) > 0 {
 | 
							if len(fieldpaths) > 0 {
 | 
				
			||||||
@@ -134,7 +134,7 @@ func (cs *contentStore) Update(ctx context.Context, info content.Info, fieldpath
 | 
				
			|||||||
				case "labels":
 | 
									case "labels":
 | 
				
			||||||
					updated.Labels = info.Labels
 | 
										updated.Labels = info.Labels
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on content info %q", path, info.Digest)
 | 
										return fmt.Errorf("cannot update %q field on content info %q: %w", path, info.Digest, errdefs.ErrInvalidArgument)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@@ -218,7 +218,7 @@ func (cs *contentStore) Delete(ctx context.Context, dgst digest.Digest) error {
 | 
				
			|||||||
	return update(ctx, cs.db, func(tx *bolt.Tx) error {
 | 
						return update(ctx, cs.db, func(tx *bolt.Tx) error {
 | 
				
			||||||
		bkt := getBlobBucket(tx, ns, dgst)
 | 
							bkt := getBlobBucket(tx, ns, dgst)
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "content digest %v", dgst)
 | 
								return fmt.Errorf("content digest %v: %w", dgst, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := getBlobsBucket(tx, ns).DeleteBucket([]byte(dgst.String())); err != nil {
 | 
							if err := getBlobsBucket(tx, ns).DeleteBucket([]byte(dgst.String())); err != nil {
 | 
				
			||||||
@@ -307,7 +307,7 @@ func (cs *contentStore) Status(ctx context.Context, ref string) (content.Status,
 | 
				
			|||||||
	if err := view(ctx, cs.db, func(tx *bolt.Tx) error {
 | 
						if err := view(ctx, cs.db, func(tx *bolt.Tx) error {
 | 
				
			||||||
		bref = getRef(tx, ns, ref)
 | 
							bref = getRef(tx, ns, ref)
 | 
				
			||||||
		if bref == "" {
 | 
							if bref == "" {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "reference %v", ref)
 | 
								return fmt.Errorf("reference %v: %w", ref, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
@@ -335,15 +335,15 @@ func (cs *contentStore) Abort(ctx context.Context, ref string) error {
 | 
				
			|||||||
	return update(ctx, cs.db, func(tx *bolt.Tx) error {
 | 
						return update(ctx, cs.db, func(tx *bolt.Tx) error {
 | 
				
			||||||
		ibkt := getIngestsBucket(tx, ns)
 | 
							ibkt := getIngestsBucket(tx, ns)
 | 
				
			||||||
		if ibkt == nil {
 | 
							if ibkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "reference %v", ref)
 | 
								return fmt.Errorf("reference %v: %w", ref, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bkt := ibkt.Bucket([]byte(ref))
 | 
							bkt := ibkt.Bucket([]byte(ref))
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "reference %v", ref)
 | 
								return fmt.Errorf("reference %v: %w", ref, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bref := string(bkt.Get(bucketKeyRef))
 | 
							bref := string(bkt.Get(bucketKeyRef))
 | 
				
			||||||
		if bref == "" {
 | 
							if bref == "" {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "reference %v", ref)
 | 
								return fmt.Errorf("reference %v: %w", ref, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		expected := string(bkt.Get(bucketKeyExpected))
 | 
							expected := string(bkt.Get(bucketKeyExpected))
 | 
				
			||||||
		if err := ibkt.DeleteBucket([]byte(ref)); err != nil {
 | 
							if err := ibkt.DeleteBucket([]byte(ref)); err != nil {
 | 
				
			||||||
@@ -374,7 +374,7 @@ func (cs *contentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (
 | 
				
			|||||||
	// TODO(AkihiroSuda): we could create a random string or one calculated based on the context
 | 
						// TODO(AkihiroSuda): we could create a random string or one calculated based on the context
 | 
				
			||||||
	// https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
 | 
						// https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
 | 
				
			||||||
	if wOpts.Ref == "" {
 | 
						if wOpts.Ref == "" {
 | 
				
			||||||
		return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty")
 | 
							return nil, fmt.Errorf("ref must not be empty: %w", errdefs.ErrInvalidArgument)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ns, err := namespaces.NamespaceRequired(ctx)
 | 
						ns, err := namespaces.NamespaceRequired(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -397,7 +397,7 @@ func (cs *contentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (
 | 
				
			|||||||
				// Add content to lease to prevent other reference removals
 | 
									// Add content to lease to prevent other reference removals
 | 
				
			||||||
				// from effecting this object during a provided lease
 | 
									// from effecting this object during a provided lease
 | 
				
			||||||
				if err := addContentLease(ctx, tx, wOpts.Desc.Digest); err != nil {
 | 
									if err := addContentLease(ctx, tx, wOpts.Desc.Digest); err != nil {
 | 
				
			||||||
					return errors.Wrap(err, "unable to lease content")
 | 
										return fmt.Errorf("unable to lease content: %w", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				// Return error outside of transaction to ensure
 | 
									// Return error outside of transaction to ensure
 | 
				
			||||||
				// commit succeeds with the lease.
 | 
									// commit succeeds with the lease.
 | 
				
			||||||
@@ -473,7 +473,7 @@ func (cs *contentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if exists {
 | 
						if exists {
 | 
				
			||||||
		return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", wOpts.Desc.Digest)
 | 
							return nil, fmt.Errorf("content %v: %w", wOpts.Desc.Digest, errdefs.ErrAlreadyExists)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &namespacedWriter{
 | 
						return &namespacedWriter{
 | 
				
			||||||
@@ -626,10 +626,10 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
 | 
				
			|||||||
	var actual digest.Digest
 | 
						var actual digest.Digest
 | 
				
			||||||
	if nw.w == nil {
 | 
						if nw.w == nil {
 | 
				
			||||||
		if size != 0 && size != nw.desc.Size {
 | 
							if size != 0 && size != nw.desc.Size {
 | 
				
			||||||
			return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "%q failed size validation: %v != %v", nw.ref, nw.desc.Size, size)
 | 
								return "", fmt.Errorf("%q failed size validation: %v != %v: %w", nw.ref, nw.desc.Size, size, errdefs.ErrFailedPrecondition)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if expected != "" && expected != nw.desc.Digest {
 | 
							if expected != "" && expected != nw.desc.Digest {
 | 
				
			||||||
			return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "%q unexpected digest", nw.ref)
 | 
								return "", fmt.Errorf("%q unexpected digest: %w", nw.ref, errdefs.ErrFailedPrecondition)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		size = nw.desc.Size
 | 
							size = nw.desc.Size
 | 
				
			||||||
		actual = nw.desc.Digest
 | 
							actual = nw.desc.Digest
 | 
				
			||||||
@@ -641,7 +641,7 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		if size != 0 && size != status.Offset {
 | 
							if size != 0 && size != status.Offset {
 | 
				
			||||||
			nw.w.Close()
 | 
								nw.w.Close()
 | 
				
			||||||
			return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "%q failed size validation: %v != %v", nw.ref, status.Offset, size)
 | 
								return "", fmt.Errorf("%q failed size validation: %v != %v: %w", nw.ref, status.Offset, size, errdefs.ErrFailedPrecondition)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		size = status.Offset
 | 
							size = status.Offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -654,7 +654,7 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
 | 
				
			|||||||
	bkt, err := createBlobBucket(tx, nw.namespace, actual)
 | 
						bkt, err := createBlobBucket(tx, nw.namespace, actual)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if err == bolt.ErrBucketExists {
 | 
							if err == bolt.ErrBucketExists {
 | 
				
			||||||
			return actual, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", actual)
 | 
								return actual, fmt.Errorf("content %v: %w", actual, errdefs.ErrAlreadyExists)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -711,7 +711,7 @@ func (cs *contentStore) checkAccess(ctx context.Context, dgst digest.Digest) err
 | 
				
			|||||||
			bkt = getShareableBucket(tx, dgst)
 | 
								bkt = getShareableBucket(tx, dgst)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "content digest %v", dgst)
 | 
								return fmt.Errorf("content digest %v: %w", dgst, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -720,7 +720,7 @@ func (cs *contentStore) checkAccess(ctx context.Context, dgst digest.Digest) err
 | 
				
			|||||||
func validateInfo(info *content.Info) error {
 | 
					func validateInfo(info *content.Info) error {
 | 
				
			||||||
	for k, v := range info.Labels {
 | 
						for k, v := range info.Labels {
 | 
				
			||||||
		if err := labels.Validate(k, v); err != nil {
 | 
							if err := labels.Validate(k, v); err != nil {
 | 
				
			||||||
			return errors.Wrapf(err, "info.Labels")
 | 
								return fmt.Errorf("info.Labels: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -751,7 +751,7 @@ func writeInfo(info *content.Info, bkt *bolt.Bucket) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := boltutil.WriteLabels(bkt, info.Labels); err != nil {
 | 
						if err := boltutil.WriteLabels(bkt, info.Labels); err != nil {
 | 
				
			||||||
		return errors.Wrapf(err, "writing labels for info %v", info.Digest)
 | 
							return fmt.Errorf("writing labels for info %v: %w", info.Digest, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Write size
 | 
						// Write size
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package metadata
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"sync/atomic"
 | 
						"sync/atomic"
 | 
				
			||||||
@@ -32,7 +33,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/namespaces"
 | 
						"github.com/containerd/containerd/namespaces"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -190,11 +190,11 @@ func checkContentLeased(ctx context.Context, db *DB, dgst digest.Digest) error {
 | 
				
			|||||||
	return db.View(func(tx *bolt.Tx) error {
 | 
						return db.View(func(tx *bolt.Tx) error {
 | 
				
			||||||
		bkt := getBucket(tx, bucketKeyVersion, []byte(ns), bucketKeyObjectLeases, []byte(lease), bucketKeyObjectContent)
 | 
							bkt := getBucket(tx, bucketKeyVersion, []byte(ns), bucketKeyObjectLeases, []byte(lease), bucketKeyObjectContent)
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "bucket not found %s", lease)
 | 
								return fmt.Errorf("bucket not found %s: %w", lease, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		v := bkt.Get([]byte(dgst.String()))
 | 
							v := bkt.Get([]byte(dgst.String()))
 | 
				
			||||||
		if v == nil {
 | 
							if v == nil {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrNotFound, "object not leased")
 | 
								return fmt.Errorf("object not leased: %w", errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
@@ -214,11 +214,11 @@ func checkIngestLeased(ctx context.Context, db *DB, ref string) error {
 | 
				
			|||||||
	return db.View(func(tx *bolt.Tx) error {
 | 
						return db.View(func(tx *bolt.Tx) error {
 | 
				
			||||||
		bkt := getBucket(tx, bucketKeyVersion, []byte(ns), bucketKeyObjectLeases, []byte(lease), bucketKeyObjectIngests)
 | 
							bkt := getBucket(tx, bucketKeyVersion, []byte(ns), bucketKeyObjectLeases, []byte(lease), bucketKeyObjectIngests)
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrapf(errdefs.ErrNotFound, "bucket not found %s", lease)
 | 
								return fmt.Errorf("bucket not found %s: %w", lease, errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		v := bkt.Get([]byte(ref))
 | 
							v := bkt.Get([]byte(ref))
 | 
				
			||||||
		if v == nil {
 | 
							if v == nil {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrNotFound, "object not leased")
 | 
								return fmt.Errorf("object not leased: %w", errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,8 @@ package metadata
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/binary"
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"sync/atomic"
 | 
						"sync/atomic"
 | 
				
			||||||
@@ -28,7 +30,6 @@ import (
 | 
				
			|||||||
	"github.com/containerd/containerd/gc"
 | 
						"github.com/containerd/containerd/gc"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/containerd/containerd/snapshots"
 | 
						"github.com/containerd/containerd/snapshots"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -181,7 +182,7 @@ func (m *DB) Init(ctx context.Context) error {
 | 
				
			|||||||
			for _, m := range updates {
 | 
								for _, m := range updates {
 | 
				
			||||||
				t0 := time.Now()
 | 
									t0 := time.Now()
 | 
				
			||||||
				if err := m.migrate(tx); err != nil {
 | 
									if err := m.migrate(tx); err != nil {
 | 
				
			||||||
					return errors.Wrapf(err, "failed to migrate to %s.%d", m.schema, m.version)
 | 
										return fmt.Errorf("failed to migrate to %s.%d: %w", m.schema, m.version, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				log.G(ctx).WithField("d", time.Since(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
 | 
									log.G(ctx).WithField("d", time.Since(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -307,7 +308,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := scanAll(ctx, tx, rm); err != nil {
 | 
							if err := scanAll(ctx, tx, rm); err != nil {
 | 
				
			||||||
			return errors.Wrap(err, "failed to scan and remove")
 | 
								return fmt.Errorf("failed to scan and remove: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ package metadata
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/binary"
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
@@ -43,7 +44,6 @@ import (
 | 
				
			|||||||
	"github.com/gogo/protobuf/types"
 | 
						"github.com/gogo/protobuf/types"
 | 
				
			||||||
	digest "github.com/opencontainers/go-digest"
 | 
						digest "github.com/opencontainers/go-digest"
 | 
				
			||||||
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -208,7 +208,7 @@ func TestMigrations(t *testing.T) {
 | 
				
			|||||||
			check: func(tx *bolt.Tx) error {
 | 
								check: func(tx *bolt.Tx) error {
 | 
				
			||||||
				bkt := getSnapshotterBucket(tx, "testing", "testing")
 | 
									bkt := getSnapshotterBucket(tx, "testing", "testing")
 | 
				
			||||||
				if bkt == nil {
 | 
									if bkt == nil {
 | 
				
			||||||
					return errors.Wrap(errdefs.ErrNotFound, "snapshots bucket not found")
 | 
										return fmt.Errorf("snapshots bucket not found: %w", errdefs.ErrNotFound)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				snapshots := []struct {
 | 
									snapshots := []struct {
 | 
				
			||||||
					key      string
 | 
										key      string
 | 
				
			||||||
@@ -235,7 +235,7 @@ func TestMigrations(t *testing.T) {
 | 
				
			|||||||
				for _, s := range snapshots {
 | 
									for _, s := range snapshots {
 | 
				
			||||||
					sbkt := bkt.Bucket([]byte(s.key))
 | 
										sbkt := bkt.Bucket([]byte(s.key))
 | 
				
			||||||
					if sbkt == nil {
 | 
										if sbkt == nil {
 | 
				
			||||||
						return errors.Wrap(errdefs.ErrNotFound, "key does not exist")
 | 
											return fmt.Errorf("key does not exist: %w", errdefs.ErrNotFound)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					cbkt := sbkt.Bucket(bucketKeyChildren)
 | 
										cbkt := sbkt.Bucket(bucketKeyChildren)
 | 
				
			||||||
@@ -245,12 +245,12 @@ func TestMigrations(t *testing.T) {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if cn != len(s.children) {
 | 
										if cn != len(s.children) {
 | 
				
			||||||
						return errors.Errorf("unexpected number of children %d, expected %d", cn, len(s.children))
 | 
											return fmt.Errorf("unexpected number of children %d, expected %d", cn, len(s.children))
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					for _, ch := range s.children {
 | 
										for _, ch := range s.children {
 | 
				
			||||||
						if v := cbkt.Get([]byte(ch)); v == nil {
 | 
											if v := cbkt.Get([]byte(ch)); v == nil {
 | 
				
			||||||
							return errors.Errorf("missing child record for %s", ch)
 | 
												return fmt.Errorf("missing child record for %s", ch)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -277,18 +277,18 @@ func TestMigrations(t *testing.T) {
 | 
				
			|||||||
			check: func(tx *bolt.Tx) error {
 | 
								check: func(tx *bolt.Tx) error {
 | 
				
			||||||
				bkt := getIngestsBucket(tx, "testing")
 | 
									bkt := getIngestsBucket(tx, "testing")
 | 
				
			||||||
				if bkt == nil {
 | 
									if bkt == nil {
 | 
				
			||||||
					return errors.Wrap(errdefs.ErrNotFound, "ingests bucket not found")
 | 
										return fmt.Errorf("ingests bucket not found: %w", errdefs.ErrNotFound)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				for _, s := range testRefs {
 | 
									for _, s := range testRefs {
 | 
				
			||||||
					sbkt := bkt.Bucket([]byte(s.ref))
 | 
										sbkt := bkt.Bucket([]byte(s.ref))
 | 
				
			||||||
					if sbkt == nil {
 | 
										if sbkt == nil {
 | 
				
			||||||
						return errors.Wrap(errdefs.ErrNotFound, "ref does not exist")
 | 
											return fmt.Errorf("ref does not exist: %w", errdefs.ErrNotFound)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					bref := string(sbkt.Get(bucketKeyRef))
 | 
										bref := string(sbkt.Get(bucketKeyRef))
 | 
				
			||||||
					if bref != s.bref {
 | 
										if bref != s.bref {
 | 
				
			||||||
						return errors.Errorf("unexpected reference key %q, expected %q", bref, s.bref)
 | 
											return fmt.Errorf("unexpected reference key %q, expected %q", bref, s.bref)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -345,11 +345,11 @@ func readDBVersion(db *bolt.DB, schema []byte) (int, error) {
 | 
				
			|||||||
	if err := db.View(func(tx *bolt.Tx) error {
 | 
						if err := db.View(func(tx *bolt.Tx) error {
 | 
				
			||||||
		bkt := tx.Bucket(schema)
 | 
							bkt := tx.Bucket(schema)
 | 
				
			||||||
		if bkt == nil {
 | 
							if bkt == nil {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrNotFound, "no version bucket")
 | 
								return fmt.Errorf("no version bucket: %w", errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		vb := bkt.Get(bucketKeyDBVersion)
 | 
							vb := bkt.Get(bucketKeyDBVersion)
 | 
				
			||||||
		if vb == nil {
 | 
							if vb == nil {
 | 
				
			||||||
			return errors.Wrap(errdefs.ErrNotFound, "no version value")
 | 
								return fmt.Errorf("no version value: %w", errdefs.ErrNotFound)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		v, _ := binary.Varint(vb)
 | 
							v, _ := binary.Varint(vb)
 | 
				
			||||||
		version = int(v)
 | 
							version = int(v)
 | 
				
			||||||
@@ -588,13 +588,13 @@ func create(obj object, tx *bolt.Tx, db *DB, cs content.Store, sn snapshots.Snap
 | 
				
			|||||||
			content.WithRef("test-ref"),
 | 
								content.WithRef("test-ref"),
 | 
				
			||||||
			content.WithDescriptor(ocispec.Descriptor{Size: int64(len(v.data)), Digest: expected}))
 | 
								content.WithDescriptor(ocispec.Descriptor{Size: int64(len(v.data)), Digest: expected}))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrap(err, "failed to create writer")
 | 
								return nil, fmt.Errorf("failed to create writer: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := w.Write(v.data); err != nil {
 | 
							if _, err := w.Write(v.data); err != nil {
 | 
				
			||||||
			return nil, errors.Wrap(err, "write blob failed")
 | 
								return nil, fmt.Errorf("write blob failed: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := w.Commit(ctx, int64(len(v.data)), expected, content.WithLabels(obj.labels)); err != nil {
 | 
							if err := w.Commit(ctx, int64(len(v.data)), expected, content.WithLabels(obj.labels)); err != nil {
 | 
				
			||||||
			return nil, errors.Wrap(err, "failed to commit blob")
 | 
								return nil, fmt.Errorf("failed to commit blob: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !obj.removed {
 | 
							if !obj.removed {
 | 
				
			||||||
			node = &gc.Node{
 | 
								node = &gc.Node{
 | 
				
			||||||
@@ -635,7 +635,7 @@ func create(obj object, tx *bolt.Tx, db *DB, cs content.Store, sn snapshots.Snap
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		_, err := NewImageStore(db).Create(ctx, image)
 | 
							_, err := NewImageStore(db).Create(ctx, image)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, errors.Wrap(err, "failed to create image")
 | 
								return nil, fmt.Errorf("failed to create image: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case testContainer:
 | 
						case testContainer:
 | 
				
			||||||
		container := containers.Container{
 | 
							container := containers.Container{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/containerd/gc"
 | 
						"github.com/containerd/containerd/gc"
 | 
				
			||||||
	"github.com/containerd/containerd/log"
 | 
						"github.com/containerd/containerd/log"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	bolt "go.etcd.io/bbolt"
 | 
						bolt "go.etcd.io/bbolt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -290,7 +289,7 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
 | 
				
			|||||||
	case ResourceSnapshot, resourceSnapshotFlat:
 | 
						case ResourceSnapshot, resourceSnapshotFlat:
 | 
				
			||||||
		parts := strings.SplitN(node.Key, "/", 2)
 | 
							parts := strings.SplitN(node.Key, "/", 2)
 | 
				
			||||||
		if len(parts) != 2 {
 | 
							if len(parts) != 2 {
 | 
				
			||||||
			return errors.Errorf("invalid snapshot gc key %s", node.Key)
 | 
								return fmt.Errorf("invalid snapshot gc key %s", node.Key)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ss := parts[0]
 | 
							ss := parts[0]
 | 
				
			||||||
		name := parts[1]
 | 
							name := parts[1]
 | 
				
			||||||
@@ -435,7 +434,7 @@ func remove(ctx context.Context, tx *bolt.Tx, node gc.Node) error {
 | 
				
			|||||||
		if sbkt != nil {
 | 
							if sbkt != nil {
 | 
				
			||||||
			parts := strings.SplitN(node.Key, "/", 2)
 | 
								parts := strings.SplitN(node.Key, "/", 2)
 | 
				
			||||||
			if len(parts) != 2 {
 | 
								if len(parts) != 2 {
 | 
				
			||||||
				return errors.Errorf("invalid snapshot gc key %s", node.Key)
 | 
									return fmt.Errorf("invalid snapshot gc key %s", node.Key)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ssbkt := sbkt.Bucket([]byte(parts[0]))
 | 
								ssbkt := sbkt.Bucket([]byte(parts[0]))
 | 
				
			||||||
			if ssbkt != nil {
 | 
								if ssbkt != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user