mirror of
https://github.com/containers/podman.git
synced 2025-06-20 17:13:43 +08:00
Vendor in latest c/storage and c/image
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
@ -15,8 +15,8 @@ github.com/containerd/cgroups 39b18af02c4120960f517a3a4c2588fabb61d02c
|
|||||||
github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
|
github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
|
||||||
github.com/containernetworking/cni v0.7.0-alpha1
|
github.com/containernetworking/cni v0.7.0-alpha1
|
||||||
github.com/containernetworking/plugins v0.7.4
|
github.com/containernetworking/plugins v0.7.4
|
||||||
github.com/containers/image v1.3
|
github.com/containers/image 93bced01015eb94bec4821df1876314be8197680
|
||||||
github.com/containers/storage v1.9
|
github.com/containers/storage 06b6c2e4cf254f5922a79da058c94ac2a65bb92f
|
||||||
github.com/containers/psgo v1.1
|
github.com/containers/psgo v1.1
|
||||||
github.com/coreos/go-systemd v14
|
github.com/coreos/go-systemd v14
|
||||||
github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c
|
github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c
|
||||||
|
77
vendor/github.com/containers/image/copy/copy.go
generated
vendored
77
vendor/github.com/containers/image/copy/copy.go
generated
vendored
@ -6,13 +6,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/image/docker/reference"
|
||||||
"github.com/containers/image/image"
|
"github.com/containers/image/image"
|
||||||
|
"github.com/containers/image/manifest"
|
||||||
"github.com/containers/image/pkg/blobinfocache"
|
"github.com/containers/image/pkg/blobinfocache"
|
||||||
"github.com/containers/image/pkg/compression"
|
"github.com/containers/image/pkg/compression"
|
||||||
"github.com/containers/image/signature"
|
"github.com/containers/image/signature"
|
||||||
@ -22,6 +25,7 @@ import (
|
|||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
"golang.org/x/sync/semaphore"
|
"golang.org/x/sync/semaphore"
|
||||||
pb "gopkg.in/cheggaaa/pb.v1"
|
pb "gopkg.in/cheggaaa/pb.v1"
|
||||||
)
|
)
|
||||||
@ -84,6 +88,7 @@ type copier struct {
|
|||||||
dest types.ImageDestination
|
dest types.ImageDestination
|
||||||
rawSource types.ImageSource
|
rawSource types.ImageSource
|
||||||
reportWriter io.Writer
|
reportWriter io.Writer
|
||||||
|
progressOutput io.Writer
|
||||||
progressInterval time.Duration
|
progressInterval time.Duration
|
||||||
progress chan types.ProgressProperties
|
progress chan types.ProgressProperties
|
||||||
blobInfoCache types.BlobInfoCache
|
blobInfoCache types.BlobInfoCache
|
||||||
@ -152,11 +157,19 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// If reportWriter is not a TTY (e.g., when piping to a file), do not
|
||||||
|
// print the progress bars to avoid long and hard to parse output.
|
||||||
|
// createProgressBar() will print a single line instead.
|
||||||
|
progressOutput := reportWriter
|
||||||
|
if !isTTY(reportWriter) {
|
||||||
|
progressOutput = ioutil.Discard
|
||||||
|
}
|
||||||
copyInParallel := dest.HasThreadSafePutBlob() && rawSource.HasThreadSafeGetBlob()
|
copyInParallel := dest.HasThreadSafePutBlob() && rawSource.HasThreadSafeGetBlob()
|
||||||
c := &copier{
|
c := &copier{
|
||||||
dest: dest,
|
dest: dest,
|
||||||
rawSource: rawSource,
|
rawSource: rawSource,
|
||||||
reportWriter: reportWriter,
|
reportWriter: reportWriter,
|
||||||
|
progressOutput: progressOutput,
|
||||||
progressInterval: options.ProgressInterval,
|
progressInterval: options.ProgressInterval,
|
||||||
progress: options.Progress,
|
progress: options.Progress,
|
||||||
copyInParallel: copyInParallel,
|
copyInParallel: copyInParallel,
|
||||||
@ -201,7 +214,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
|
|||||||
|
|
||||||
// Image copies a single (on-manifest-list) image unparsedImage, using policyContext to validate
|
// Image copies a single (on-manifest-list) image unparsedImage, using policyContext to validate
|
||||||
// source image admissibility.
|
// source image admissibility.
|
||||||
func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.PolicyContext, options *Options, unparsedImage *image.UnparsedImage) (manifest []byte, retErr error) {
|
func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.PolicyContext, options *Options, unparsedImage *image.UnparsedImage) (manifestBytes []byte, retErr error) {
|
||||||
// The caller is handling manifest lists; this could happen only if a manifest list contains a manifest list.
|
// The caller is handling manifest lists; this could happen only if a manifest list contains a manifest list.
|
||||||
// Make sure we fail cleanly in such cases.
|
// Make sure we fail cleanly in such cases.
|
||||||
multiImage, err := isMultiImage(ctx, unparsedImage)
|
multiImage, err := isMultiImage(ctx, unparsedImage)
|
||||||
@ -224,6 +237,26 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
|||||||
return nil, errors.Wrapf(err, "Error initializing image from source %s", transports.ImageName(c.rawSource.Reference()))
|
return nil, errors.Wrapf(err, "Error initializing image from source %s", transports.ImageName(c.rawSource.Reference()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the destination is a digested reference, make a note of that, determine what digest value we're
|
||||||
|
// expecting, and check that the source manifest matches it.
|
||||||
|
destIsDigestedReference := false
|
||||||
|
if named := c.dest.Reference().DockerReference(); named != nil {
|
||||||
|
if digested, ok := named.(reference.Digested); ok {
|
||||||
|
destIsDigestedReference = true
|
||||||
|
sourceManifest, _, err := src.Manifest(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Error reading manifest from source image")
|
||||||
|
}
|
||||||
|
matches, err := manifest.MatchesDigest(sourceManifest, digested.Digest())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Error computing digest of source image's manifest")
|
||||||
|
}
|
||||||
|
if !matches {
|
||||||
|
return nil, errors.New("Digest of source image's manifest would not match destination reference")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := checkImageDestinationForCurrentRuntimeOS(ctx, options.DestinationCtx, src, c.dest); err != nil {
|
if err := checkImageDestinationForCurrentRuntimeOS(ctx, options.DestinationCtx, src, c.dest); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -251,15 +284,15 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
|||||||
manifestUpdates: &types.ManifestUpdateOptions{InformationOnly: types.ManifestUpdateInformation{Destination: c.dest}},
|
manifestUpdates: &types.ManifestUpdateOptions{InformationOnly: types.ManifestUpdateInformation{Destination: c.dest}},
|
||||||
src: src,
|
src: src,
|
||||||
// diffIDsAreNeeded is computed later
|
// diffIDsAreNeeded is computed later
|
||||||
canModifyManifest: len(sigs) == 0,
|
canModifyManifest: len(sigs) == 0 && !destIsDigestedReference,
|
||||||
|
}
|
||||||
// Ensure _this_ copy sees exactly the intended data when either processing a signed image or signing it.
|
// Ensure _this_ copy sees exactly the intended data when either processing a signed image or signing it.
|
||||||
// This may be too conservative, but for now, better safe than sorry, _especially_ on the SignBy path:
|
// This may be too conservative, but for now, better safe than sorry, _especially_ on the SignBy path:
|
||||||
// The signature makes the content non-repudiable, so it very much matters that the signature is made over exactly what the user intended.
|
// The signature makes the content non-repudiable, so it very much matters that the signature is made over exactly what the user intended.
|
||||||
// We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
|
// We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
|
||||||
// that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
|
// that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
|
||||||
// and we would reuse and sign it.
|
// and we would reuse and sign it.
|
||||||
canSubstituteBlobs: len(sigs) == 0 && options.SignBy == "",
|
ic.canSubstituteBlobs = ic.canModifyManifest && options.SignBy == ""
|
||||||
}
|
|
||||||
|
|
||||||
if err := ic.updateEmbeddedDockerReference(); err != nil {
|
if err := ic.updateEmbeddedDockerReference(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -283,7 +316,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
|||||||
// and at least with the OpenShift registry "acceptschema2" option, there is no way to detect the support
|
// and at least with the OpenShift registry "acceptschema2" option, there is no way to detect the support
|
||||||
// without actually trying to upload something and getting a types.ManifestTypeRejectedError.
|
// without actually trying to upload something and getting a types.ManifestTypeRejectedError.
|
||||||
// So, try the preferred manifest MIME type. If the process succeeds, fine…
|
// So, try the preferred manifest MIME type. If the process succeeds, fine…
|
||||||
manifest, err = ic.copyUpdatedConfigAndManifest(ctx)
|
manifestBytes, err = ic.copyUpdatedConfigAndManifest(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Writing manifest using preferred type %s failed: %v", preferredManifestMIMEType, err)
|
logrus.Debugf("Writing manifest using preferred type %s failed: %v", preferredManifestMIMEType, err)
|
||||||
// … if it fails, _and_ the failure is because the manifest is rejected, we may have other options.
|
// … if it fails, _and_ the failure is because the manifest is rejected, we may have other options.
|
||||||
@ -314,7 +347,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We have successfully uploaded a manifest.
|
// We have successfully uploaded a manifest.
|
||||||
manifest = attemptedManifest
|
manifestBytes = attemptedManifest
|
||||||
errs = nil // Mark this as a success so that we don't abort below.
|
errs = nil // Mark this as a success so that we don't abort below.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -324,7 +357,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
|||||||
}
|
}
|
||||||
|
|
||||||
if options.SignBy != "" {
|
if options.SignBy != "" {
|
||||||
newSig, err := c.createSignature(manifest, options.SignBy)
|
newSig, err := c.createSignature(manifestBytes, options.SignBy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -336,7 +369,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
|||||||
return nil, errors.Wrap(err, "Error writing signatures")
|
return nil, errors.Wrap(err, "Error writing signatures")
|
||||||
}
|
}
|
||||||
|
|
||||||
return manifest, nil
|
return manifestBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Printf writes a formatted string to c.reportWriter.
|
// Printf writes a formatted string to c.reportWriter.
|
||||||
@ -394,17 +427,30 @@ func shortDigest(d digest.Digest) string {
|
|||||||
return d.Encoded()[:12]
|
return d.Encoded()[:12]
|
||||||
}
|
}
|
||||||
|
|
||||||
// createProgressBar creates a pb.ProgressBar.
|
// createProgressBar creates a pb.ProgressBar. Note that if the copier's
|
||||||
func createProgressBar(srcInfo types.BlobInfo, kind string, writer io.Writer) *pb.ProgressBar {
|
// reportWriter is ioutil.Discard, the progress bar's output will be discarded
|
||||||
|
// and a single line will be printed instead.
|
||||||
|
func (c *copier) createProgressBar(srcInfo types.BlobInfo, kind string) *pb.ProgressBar {
|
||||||
bar := pb.New(int(srcInfo.Size)).SetUnits(pb.U_BYTES)
|
bar := pb.New(int(srcInfo.Size)).SetUnits(pb.U_BYTES)
|
||||||
bar.SetMaxWidth(80)
|
bar.SetMaxWidth(80)
|
||||||
bar.ShowTimeLeft = false
|
bar.ShowTimeLeft = false
|
||||||
bar.ShowPercent = false
|
bar.ShowPercent = false
|
||||||
bar.Prefix(fmt.Sprintf("Copying %s %s:", kind, shortDigest(srcInfo.Digest)))
|
bar.Prefix(fmt.Sprintf("Copying %s %s:", kind, shortDigest(srcInfo.Digest)))
|
||||||
bar.Output = writer
|
bar.Output = c.progressOutput
|
||||||
|
if bar.Output == ioutil.Discard {
|
||||||
|
c.Printf("Copying %s %s\n", kind, srcInfo.Digest)
|
||||||
|
}
|
||||||
return bar
|
return bar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isTTY returns true if the io.Writer is a file and a tty.
|
||||||
|
func isTTY(w io.Writer) bool {
|
||||||
|
if f, ok := w.(*os.File); ok {
|
||||||
|
return terminal.IsTerminal(int(f.Fd()))
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.canModifyManifest.
|
// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.canModifyManifest.
|
||||||
func (ic *imageCopier) copyLayers(ctx context.Context) error {
|
func (ic *imageCopier) copyLayers(ctx context.Context) error {
|
||||||
srcInfos := ic.src.LayerInfos()
|
srcInfos := ic.src.LayerInfos()
|
||||||
@ -456,7 +502,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
|
|||||||
bar.Finish()
|
bar.Finish()
|
||||||
} else {
|
} else {
|
||||||
cld.destInfo = srcLayer
|
cld.destInfo = srcLayer
|
||||||
logrus.Debugf("Skipping foreign layer %q copy to %s\n", cld.destInfo.Digest, ic.c.dest.Reference().Transport().Name())
|
logrus.Debugf("Skipping foreign layer %q copy to %s", cld.destInfo.Digest, ic.c.dest.Reference().Transport().Name())
|
||||||
bar.Prefix(fmt.Sprintf("Skipping blob %s (foreign layer):", shortDigest(srcLayer.Digest)))
|
bar.Prefix(fmt.Sprintf("Skipping blob %s (foreign layer):", shortDigest(srcLayer.Digest)))
|
||||||
bar.Add64(bar.Total)
|
bar.Add64(bar.Total)
|
||||||
bar.Finish()
|
bar.Finish()
|
||||||
@ -469,12 +515,13 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
|
|||||||
|
|
||||||
progressBars := make([]*pb.ProgressBar, numLayers)
|
progressBars := make([]*pb.ProgressBar, numLayers)
|
||||||
for i, srcInfo := range srcInfos {
|
for i, srcInfo := range srcInfos {
|
||||||
bar := createProgressBar(srcInfo, "blob", nil)
|
bar := ic.c.createProgressBar(srcInfo, "blob")
|
||||||
progressBars[i] = bar
|
progressBars[i] = bar
|
||||||
}
|
}
|
||||||
|
|
||||||
progressPool := pb.NewPool(progressBars...)
|
progressPool := pb.NewPool(progressBars...)
|
||||||
progressPool.Output = ic.c.reportWriter
|
progressPool.Output = ic.c.progressOutput
|
||||||
|
|
||||||
if err := progressPool.Start(); err != nil {
|
if err := progressPool.Start(); err != nil {
|
||||||
return errors.Wrapf(err, "error creating progress-bar pool")
|
return errors.Wrapf(err, "error creating progress-bar pool")
|
||||||
}
|
}
|
||||||
@ -568,7 +615,7 @@ func (c *copier) copyConfig(ctx context.Context, src types.Image) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "Error reading config blob %s", srcInfo.Digest)
|
return errors.Wrapf(err, "Error reading config blob %s", srcInfo.Digest)
|
||||||
}
|
}
|
||||||
bar := createProgressBar(srcInfo, "config", c.reportWriter)
|
bar := c.createProgressBar(srcInfo, "config")
|
||||||
defer bar.Finish()
|
defer bar.Finish()
|
||||||
bar.Start()
|
bar.Start()
|
||||||
destInfo, err := c.copyBlobFromStream(ctx, bytes.NewReader(configBlob), srcInfo, nil, false, true, bar)
|
destInfo, err := c.copyBlobFromStream(ctx, bytes.NewReader(configBlob), srcInfo, nil, false, true, bar)
|
||||||
|
33
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
33
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
@ -91,7 +91,6 @@ type dockerClient struct {
|
|||||||
password string
|
password string
|
||||||
signatureBase signatureStorageBase
|
signatureBase signatureStorageBase
|
||||||
scope authScope
|
scope authScope
|
||||||
extraScope *authScope // If non-nil, a temporary extra token scope (necessary for mounting from another repo)
|
|
||||||
// The following members are detected registry properties:
|
// The following members are detected registry properties:
|
||||||
// They are set after a successful detectProperties(), and never change afterwards.
|
// They are set after a successful detectProperties(), and never change afterwards.
|
||||||
scheme string // Empty value also used to indicate detectProperties() has not yet succeeded.
|
scheme string // Empty value also used to indicate detectProperties() has not yet succeeded.
|
||||||
@ -282,7 +281,7 @@ func CheckAuth(ctx context.Context, sys *types.SystemContext, username, password
|
|||||||
client.username = username
|
client.username = username
|
||||||
client.password = password
|
client.password = password
|
||||||
|
|
||||||
resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth)
|
resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -362,8 +361,8 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
|
|||||||
q.Set("n", strconv.Itoa(limit))
|
q.Set("n", strconv.Itoa(limit))
|
||||||
u.RawQuery = q.Encode()
|
u.RawQuery = q.Encode()
|
||||||
|
|
||||||
logrus.Debugf("trying to talk to v1 search endpoint\n")
|
logrus.Debugf("trying to talk to v1 search endpoint")
|
||||||
resp, err := client.makeRequest(ctx, "GET", u.String(), nil, nil, noAuth)
|
resp, err := client.makeRequest(ctx, "GET", u.String(), nil, nil, noAuth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("error getting search results from v1 endpoint %q: %v", registry, err)
|
logrus.Debugf("error getting search results from v1 endpoint %q: %v", registry, err)
|
||||||
} else {
|
} else {
|
||||||
@ -379,8 +378,8 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("trying to talk to v2 search endpoint\n")
|
logrus.Debugf("trying to talk to v2 search endpoint")
|
||||||
resp, err := client.makeRequest(ctx, "GET", "/v2/_catalog", nil, nil, v2Auth)
|
resp, err := client.makeRequest(ctx, "GET", "/v2/_catalog", nil, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("error getting search results from v2 endpoint %q: %v", registry, err)
|
logrus.Debugf("error getting search results from v2 endpoint %q: %v", registry, err)
|
||||||
} else {
|
} else {
|
||||||
@ -409,20 +408,20 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
|
|||||||
|
|
||||||
// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
|
// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
|
||||||
// The host name and schema is taken from the client or autodetected, and the path is relative to it, i.e. the path usually starts with /v2/.
|
// The host name and schema is taken from the client or autodetected, and the path is relative to it, i.e. the path usually starts with /v2/.
|
||||||
func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader, auth sendAuth) (*http.Response, error) {
|
func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader, auth sendAuth, extraScope *authScope) (*http.Response, error) {
|
||||||
if err := c.detectProperties(ctx); err != nil {
|
if err := c.detectProperties(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
url := fmt.Sprintf("%s://%s%s", c.scheme, c.registry, path)
|
url := fmt.Sprintf("%s://%s%s", c.scheme, c.registry, path)
|
||||||
return c.makeRequestToResolvedURL(ctx, method, url, headers, stream, -1, auth)
|
return c.makeRequestToResolvedURL(ctx, method, url, headers, stream, -1, auth, extraScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeRequestToResolvedURL creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
|
// makeRequestToResolvedURL creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
|
||||||
// streamLen, if not -1, specifies the length of the data expected on stream.
|
// streamLen, if not -1, specifies the length of the data expected on stream.
|
||||||
// makeRequest should generally be preferred.
|
// makeRequest should generally be preferred.
|
||||||
// TODO(runcom): too many arguments here, use a struct
|
// TODO(runcom): too many arguments here, use a struct
|
||||||
func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url string, headers map[string][]string, stream io.Reader, streamLen int64, auth sendAuth) (*http.Response, error) {
|
func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url string, headers map[string][]string, stream io.Reader, streamLen int64, auth sendAuth, extraScope *authScope) (*http.Response, error) {
|
||||||
req, err := http.NewRequest(method, url, stream)
|
req, err := http.NewRequest(method, url, stream)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -441,7 +440,7 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url
|
|||||||
req.Header.Add("User-Agent", c.sys.DockerRegistryUserAgent)
|
req.Header.Add("User-Agent", c.sys.DockerRegistryUserAgent)
|
||||||
}
|
}
|
||||||
if auth == v2Auth {
|
if auth == v2Auth {
|
||||||
if err := c.setupRequestAuth(req); err != nil {
|
if err := c.setupRequestAuth(req, extraScope); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,7 +459,7 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url
|
|||||||
// 2) gcr.io is sending 401 without a WWW-Authenticate header in the real request
|
// 2) gcr.io is sending 401 without a WWW-Authenticate header in the real request
|
||||||
//
|
//
|
||||||
// debugging: https://github.com/containers/image/pull/211#issuecomment-273426236 and follows up
|
// debugging: https://github.com/containers/image/pull/211#issuecomment-273426236 and follows up
|
||||||
func (c *dockerClient) setupRequestAuth(req *http.Request) error {
|
func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope) error {
|
||||||
if len(c.challenges) == 0 {
|
if len(c.challenges) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -474,10 +473,10 @@ func (c *dockerClient) setupRequestAuth(req *http.Request) error {
|
|||||||
case "bearer":
|
case "bearer":
|
||||||
cacheKey := ""
|
cacheKey := ""
|
||||||
scopes := []authScope{c.scope}
|
scopes := []authScope{c.scope}
|
||||||
if c.extraScope != nil {
|
if extraScope != nil {
|
||||||
// Using ':' as a separator here is unambiguous because getBearerToken below uses the same separator when formatting a remote request (and because repository names can't contain colons).
|
// Using ':' as a separator here is unambiguous because getBearerToken below uses the same separator when formatting a remote request (and because repository names can't contain colons).
|
||||||
cacheKey = fmt.Sprintf("%s:%s", c.extraScope.remoteName, c.extraScope.actions)
|
cacheKey = fmt.Sprintf("%s:%s", extraScope.remoteName, extraScope.actions)
|
||||||
scopes = append(scopes, *c.extraScope)
|
scopes = append(scopes, *extraScope)
|
||||||
}
|
}
|
||||||
var token bearerToken
|
var token bearerToken
|
||||||
t, inCache := c.tokenCache.Load(cacheKey)
|
t, inCache := c.tokenCache.Load(cacheKey)
|
||||||
@ -564,7 +563,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
|
|||||||
|
|
||||||
ping := func(scheme string) error {
|
ping := func(scheme string) error {
|
||||||
url := fmt.Sprintf(resolvedPingV2URL, scheme, c.registry)
|
url := fmt.Sprintf(resolvedPingV2URL, scheme, c.registry)
|
||||||
resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
|
resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
|
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
|
||||||
return err
|
return err
|
||||||
@ -591,7 +590,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
|
|||||||
// best effort to understand if we're talking to a V1 registry
|
// best effort to understand if we're talking to a V1 registry
|
||||||
pingV1 := func(scheme string) bool {
|
pingV1 := func(scheme string) bool {
|
||||||
url := fmt.Sprintf(resolvedPingV1URL, scheme, c.registry)
|
url := fmt.Sprintf(resolvedPingV1URL, scheme, c.registry)
|
||||||
resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
|
resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
|
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
|
||||||
return false
|
return false
|
||||||
@ -625,7 +624,7 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
|
|||||||
// using the original data structures.
|
// using the original data structures.
|
||||||
func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerReference, manifestDigest digest.Digest) (*extensionSignatureList, error) {
|
func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerReference, manifestDigest digest.Digest) (*extensionSignatureList, error) {
|
||||||
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(ref.ref), manifestDigest)
|
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(ref.ref), manifestDigest)
|
||||||
res, err := c.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
|
res, err := c.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/containers/image/docker/docker_image.go
generated
vendored
2
vendor/github.com/containers/image/docker/docker_image.go
generated
vendored
@ -66,7 +66,7 @@ func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.
|
|||||||
tags := make([]string, 0)
|
tags := make([]string, 0)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
res, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
|
res, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
62
vendor/github.com/containers/image/docker/docker_image_dest.go
generated
vendored
62
vendor/github.com/containers/image/docker/docker_image_dest.go
generated
vendored
@ -12,6 +12,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/image/docker/reference"
|
"github.com/containers/image/docker/reference"
|
||||||
"github.com/containers/image/manifest"
|
"github.com/containers/image/manifest"
|
||||||
@ -113,7 +114,7 @@ func (c *sizeCounter) Write(p []byte) (n int, err error) {
|
|||||||
|
|
||||||
// HasThreadSafePutBlob indicates whether PutBlob can be executed concurrently.
|
// HasThreadSafePutBlob indicates whether PutBlob can be executed concurrently.
|
||||||
func (d *dockerImageDestination) HasThreadSafePutBlob() bool {
|
func (d *dockerImageDestination) HasThreadSafePutBlob() bool {
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutBlob writes contents of stream and returns data representing the result (with all data filled in).
|
// PutBlob writes contents of stream and returns data representing the result (with all data filled in).
|
||||||
@ -140,7 +141,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
|
|||||||
// FIXME? Chunked upload, progress reporting, etc.
|
// FIXME? Chunked upload, progress reporting, etc.
|
||||||
uploadPath := fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref))
|
uploadPath := fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref))
|
||||||
logrus.Debugf("Uploading %s", uploadPath)
|
logrus.Debugf("Uploading %s", uploadPath)
|
||||||
res, err := d.c.makeRequest(ctx, "POST", uploadPath, nil, nil, v2Auth)
|
res, err := d.c.makeRequest(ctx, "POST", uploadPath, nil, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.BlobInfo{}, err
|
return types.BlobInfo{}, err
|
||||||
}
|
}
|
||||||
@ -157,7 +158,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
|
|||||||
digester := digest.Canonical.Digester()
|
digester := digest.Canonical.Digester()
|
||||||
sizeCounter := &sizeCounter{}
|
sizeCounter := &sizeCounter{}
|
||||||
tee := io.TeeReader(stream, io.MultiWriter(digester.Hash(), sizeCounter))
|
tee := io.TeeReader(stream, io.MultiWriter(digester.Hash(), sizeCounter))
|
||||||
res, err = d.c.makeRequestToResolvedURL(ctx, "PATCH", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, tee, inputInfo.Size, v2Auth)
|
res, err = d.c.makeRequestToResolvedURL(ctx, "PATCH", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, tee, inputInfo.Size, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Error uploading layer chunked, response %#v", res)
|
logrus.Debugf("Error uploading layer chunked, response %#v", res)
|
||||||
return types.BlobInfo{}, err
|
return types.BlobInfo{}, err
|
||||||
@ -176,7 +177,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
|
|||||||
// TODO: check inputInfo.Digest == computedDigest https://github.com/containers/image/pull/70#discussion_r77646717
|
// TODO: check inputInfo.Digest == computedDigest https://github.com/containers/image/pull/70#discussion_r77646717
|
||||||
locationQuery.Set("digest", computedDigest.String())
|
locationQuery.Set("digest", computedDigest.String())
|
||||||
uploadLocation.RawQuery = locationQuery.Encode()
|
uploadLocation.RawQuery = locationQuery.Encode()
|
||||||
res, err = d.c.makeRequestToResolvedURL(ctx, "PUT", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, nil, -1, v2Auth)
|
res, err = d.c.makeRequestToResolvedURL(ctx, "PUT", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, nil, -1, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.BlobInfo{}, err
|
return types.BlobInfo{}, err
|
||||||
}
|
}
|
||||||
@ -194,10 +195,10 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
|
|||||||
// blobExists returns true iff repo contains a blob with digest, and if so, also its size.
|
// blobExists returns true iff repo contains a blob with digest, and if so, also its size.
|
||||||
// If the destination does not contain the blob, or it is unknown, blobExists ordinarily returns (false, -1, nil);
|
// If the destination does not contain the blob, or it is unknown, blobExists ordinarily returns (false, -1, nil);
|
||||||
// it returns a non-nil error only on an unexpected failure.
|
// it returns a non-nil error only on an unexpected failure.
|
||||||
func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest) (bool, int64, error) {
|
func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest, extraScope *authScope) (bool, int64, error) {
|
||||||
checkPath := fmt.Sprintf(blobsPath, reference.Path(repo), digest.String())
|
checkPath := fmt.Sprintf(blobsPath, reference.Path(repo), digest.String())
|
||||||
logrus.Debugf("Checking %s", checkPath)
|
logrus.Debugf("Checking %s", checkPath)
|
||||||
res, err := d.c.makeRequest(ctx, "HEAD", checkPath, nil, nil, v2Auth)
|
res, err := d.c.makeRequest(ctx, "HEAD", checkPath, nil, nil, v2Auth, extraScope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, -1, err
|
return false, -1, err
|
||||||
}
|
}
|
||||||
@ -218,7 +219,7 @@ func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mountBlob tries to mount blob srcDigest from srcRepo to the current destination.
|
// mountBlob tries to mount blob srcDigest from srcRepo to the current destination.
|
||||||
func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo reference.Named, srcDigest digest.Digest) error {
|
func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo reference.Named, srcDigest digest.Digest, extraScope *authScope) error {
|
||||||
u := url.URL{
|
u := url.URL{
|
||||||
Path: fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref)),
|
Path: fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref)),
|
||||||
RawQuery: url.Values{
|
RawQuery: url.Values{
|
||||||
@ -228,7 +229,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
|
|||||||
}
|
}
|
||||||
mountPath := u.String()
|
mountPath := u.String()
|
||||||
logrus.Debugf("Trying to mount %s", mountPath)
|
logrus.Debugf("Trying to mount %s", mountPath)
|
||||||
res, err := d.c.makeRequest(ctx, "POST", mountPath, nil, nil, v2Auth)
|
res, err := d.c.makeRequest(ctx, "POST", mountPath, nil, nil, v2Auth, extraScope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -246,7 +247,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
|
|||||||
return errors.Wrap(err, "Error determining upload URL after a mount attempt")
|
return errors.Wrap(err, "Error determining upload URL after a mount attempt")
|
||||||
}
|
}
|
||||||
logrus.Debugf("... started an upload instead of mounting, trying to cancel at %s", uploadLocation.String())
|
logrus.Debugf("... started an upload instead of mounting, trying to cancel at %s", uploadLocation.String())
|
||||||
res2, err := d.c.makeRequestToResolvedURL(ctx, "DELETE", uploadLocation.String(), nil, nil, -1, v2Auth)
|
res2, err := d.c.makeRequestToResolvedURL(ctx, "DELETE", uploadLocation.String(), nil, nil, -1, v2Auth, extraScope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Error trying to cancel an inadvertent upload: %s", err)
|
logrus.Debugf("Error trying to cancel an inadvertent upload: %s", err)
|
||||||
} else {
|
} else {
|
||||||
@ -276,7 +277,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// First, check whether the blob happens to already exist at the destination.
|
// First, check whether the blob happens to already exist at the destination.
|
||||||
exists, size, err := d.blobExists(ctx, d.ref.ref, info.Digest)
|
exists, size, err := d.blobExists(ctx, d.ref.ref, info.Digest, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, types.BlobInfo{}, err
|
return false, types.BlobInfo{}, err
|
||||||
}
|
}
|
||||||
@ -286,15 +287,6 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then try reusing blobs from other locations.
|
// Then try reusing blobs from other locations.
|
||||||
|
|
||||||
// Checking candidateRepo, and mounting from it, requires an expanded token scope.
|
|
||||||
// We still want to reuse the ping information and other aspects of the client, so rather than make a fresh copy, there is this a bit ugly extraScope hack.
|
|
||||||
if d.c.extraScope != nil {
|
|
||||||
return false, types.BlobInfo{}, errors.New("Internal error: dockerClient.extraScope was set before TryReusingBlob")
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
d.c.extraScope = nil
|
|
||||||
}()
|
|
||||||
for _, candidate := range cache.CandidateLocations(d.ref.Transport(), bicTransportScope(d.ref), info.Digest, canSubstitute) {
|
for _, candidate := range cache.CandidateLocations(d.ref.Transport(), bicTransportScope(d.ref), info.Digest, canSubstitute) {
|
||||||
candidateRepo, err := parseBICLocationReference(candidate.Location)
|
candidateRepo, err := parseBICLocationReference(candidate.Location)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -314,7 +306,10 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Whatever happens here, don't abort the entire operation. It's likely we just don't have permissions, and if it is a critical network error, we will find out soon enough anyway.
|
// Whatever happens here, don't abort the entire operation. It's likely we just don't have permissions, and if it is a critical network error, we will find out soon enough anyway.
|
||||||
d.c.extraScope = &authScope{
|
|
||||||
|
// Checking candidateRepo, and mounting from it, requires an
|
||||||
|
// expanded token scope.
|
||||||
|
extraScope := &authScope{
|
||||||
remoteName: reference.Path(candidateRepo),
|
remoteName: reference.Path(candidateRepo),
|
||||||
actions: "pull",
|
actions: "pull",
|
||||||
}
|
}
|
||||||
@ -325,7 +320,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
|
|||||||
// Even worse, docker/distribution does not actually reasonably implement canceling uploads
|
// Even worse, docker/distribution does not actually reasonably implement canceling uploads
|
||||||
// (it would require a "delete" action in the token, and Quay does not give that to anyone, so we can't ask);
|
// (it would require a "delete" action in the token, and Quay does not give that to anyone, so we can't ask);
|
||||||
// so, be a nice client and don't create unnecesary upload sessions on the server.
|
// so, be a nice client and don't create unnecesary upload sessions on the server.
|
||||||
exists, size, err := d.blobExists(ctx, candidateRepo, candidate.Digest)
|
exists, size, err := d.blobExists(ctx, candidateRepo, candidate.Digest, extraScope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("... Failed: %v", err)
|
logrus.Debugf("... Failed: %v", err)
|
||||||
continue
|
continue
|
||||||
@ -335,7 +330,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
|
|||||||
continue // logrus.Debug() already happened in blobExists
|
continue // logrus.Debug() already happened in blobExists
|
||||||
}
|
}
|
||||||
if candidateRepo.Name() != d.ref.ref.Name() {
|
if candidateRepo.Name() != d.ref.ref.Name() {
|
||||||
if err := d.mountBlob(ctx, candidateRepo, candidate.Digest); err != nil {
|
if err := d.mountBlob(ctx, candidateRepo, candidate.Digest, extraScope); err != nil {
|
||||||
logrus.Debugf("... Mount failed: %v", err)
|
logrus.Debugf("... Mount failed: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -369,7 +364,7 @@ func (d *dockerImageDestination) PutManifest(ctx context.Context, m []byte) erro
|
|||||||
if mimeType != "" {
|
if mimeType != "" {
|
||||||
headers["Content-Type"] = []string{mimeType}
|
headers["Content-Type"] = []string{mimeType}
|
||||||
}
|
}
|
||||||
res, err := d.c.makeRequest(ctx, "PUT", path, headers, bytes.NewReader(m), v2Auth)
|
res, err := d.c.makeRequest(ctx, "PUT", path, headers, bytes.NewReader(m), v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -396,14 +391,29 @@ func isManifestInvalidError(err error) bool {
|
|||||||
if !ok || len(errors) == 0 {
|
if !ok || len(errors) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
ec, ok := errors[0].(errcode.ErrorCoder)
|
err = errors[0]
|
||||||
|
ec, ok := err.(errcode.ErrorCoder)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ec.ErrorCode() {
|
||||||
// ErrorCodeManifestInvalid is returned by OpenShift with acceptschema2=false.
|
// ErrorCodeManifestInvalid is returned by OpenShift with acceptschema2=false.
|
||||||
|
case v2.ErrorCodeManifestInvalid:
|
||||||
|
return true
|
||||||
// ErrorCodeTagInvalid is returned by docker/distribution (at least as of commit ec87e9b6971d831f0eff752ddb54fb64693e51cd)
|
// ErrorCodeTagInvalid is returned by docker/distribution (at least as of commit ec87e9b6971d831f0eff752ddb54fb64693e51cd)
|
||||||
// when uploading to a tag (because it can’t find a matching tag inside the manifest)
|
// when uploading to a tag (because it can’t find a matching tag inside the manifest)
|
||||||
return ec.ErrorCode() == v2.ErrorCodeManifestInvalid || ec.ErrorCode() == v2.ErrorCodeTagInvalid
|
case v2.ErrorCodeTagInvalid:
|
||||||
|
return true
|
||||||
|
// ErrorCodeUnsupported with 'Invalid JSON syntax' is returned by AWS ECR when
|
||||||
|
// uploading an OCI manifest that is (correctly, according to the spec) missing
|
||||||
|
// a top-level media type. See libpod issue #1719
|
||||||
|
// FIXME: remove this case when ECR behavior is fixed
|
||||||
|
case errcode.ErrorCodeUnsupported:
|
||||||
|
return strings.Contains(err.Error(), "Invalid JSON syntax")
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dockerImageDestination) PutSignatures(ctx context.Context, signatures [][]byte) error {
|
func (d *dockerImageDestination) PutSignatures(ctx context.Context, signatures [][]byte) error {
|
||||||
@ -574,7 +584,7 @@ sigExists:
|
|||||||
}
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(d.ref.ref), d.manifestDigest.String())
|
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(d.ref.ref), d.manifestDigest.String())
|
||||||
res, err := d.c.makeRequest(ctx, "PUT", path, nil, bytes.NewReader(body), v2Auth)
|
res, err := d.c.makeRequest(ctx, "PUT", path, nil, bytes.NewReader(body), v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
16
vendor/github.com/containers/image/docker/docker_image_src.go
generated
vendored
16
vendor/github.com/containers/image/docker/docker_image_src.go
generated
vendored
@ -89,7 +89,7 @@ func (s *dockerImageSource) fetchManifest(ctx context.Context, tagOrDigest strin
|
|||||||
path := fmt.Sprintf(manifestPath, reference.Path(s.ref.ref), tagOrDigest)
|
path := fmt.Sprintf(manifestPath, reference.Path(s.ref.ref), tagOrDigest)
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
headers["Accept"] = manifest.DefaultRequestedManifestMIMETypes
|
headers["Accept"] = manifest.DefaultRequestedManifestMIMETypes
|
||||||
res, err := s.c.makeRequest(ctx, "GET", path, headers, nil, v2Auth)
|
res, err := s.c.makeRequest(ctx, "GET", path, headers, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
@ -137,7 +137,7 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
|
|||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
for _, url := range urls {
|
for _, url := range urls {
|
||||||
resp, err = s.c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
|
resp, err = s.c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
err = errors.Errorf("error fetching external blob from %q: %d (%s)", url, resp.StatusCode, http.StatusText(resp.StatusCode))
|
err = errors.Errorf("error fetching external blob from %q: %d (%s)", url, resp.StatusCode, http.StatusText(resp.StatusCode))
|
||||||
@ -147,10 +147,10 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if resp.Body != nil && err == nil {
|
if err != nil {
|
||||||
return resp.Body, getBlobSize(resp), nil
|
|
||||||
}
|
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return resp.Body, getBlobSize(resp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlobSize(resp *http.Response) int64 {
|
func getBlobSize(resp *http.Response) int64 {
|
||||||
@ -176,7 +176,7 @@ func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
|
|||||||
|
|
||||||
path := fmt.Sprintf(blobsPath, reference.Path(s.ref.ref), info.Digest.String())
|
path := fmt.Sprintf(blobsPath, reference.Path(s.ref.ref), info.Digest.String())
|
||||||
logrus.Debugf("Downloading %s", path)
|
logrus.Debugf("Downloading %s", path)
|
||||||
res, err := s.c.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
|
res, err := s.c.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@ -340,7 +340,7 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
getPath := fmt.Sprintf(manifestPath, reference.Path(ref.ref), refTail)
|
getPath := fmt.Sprintf(manifestPath, reference.Path(ref.ref), refTail)
|
||||||
get, err := c.makeRequest(ctx, "GET", getPath, headers, nil, v2Auth)
|
get, err := c.makeRequest(ctx, "GET", getPath, headers, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -362,7 +362,7 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
|
|||||||
|
|
||||||
// When retrieving the digest from a registry >= 2.3 use the following header:
|
// When retrieving the digest from a registry >= 2.3 use the following header:
|
||||||
// "Accept": "application/vnd.docker.distribution.manifest.v2+json"
|
// "Accept": "application/vnd.docker.distribution.manifest.v2+json"
|
||||||
delete, err := c.makeRequest(ctx, "DELETE", deletePath, headers, nil, v2Auth)
|
delete, err := c.makeRequest(ctx, "DELETE", deletePath, headers, nil, v2Auth, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
28
vendor/github.com/containers/image/docker/tarfile/src.go
generated
vendored
28
vendor/github.com/containers/image/docker/tarfile/src.go
generated
vendored
@ -9,6 +9,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/containers/image/internal/tmpdir"
|
"github.com/containers/image/internal/tmpdir"
|
||||||
"github.com/containers/image/manifest"
|
"github.com/containers/image/manifest"
|
||||||
@ -22,7 +23,9 @@ import (
|
|||||||
type Source struct {
|
type Source struct {
|
||||||
tarPath string
|
tarPath string
|
||||||
removeTarPathOnClose bool // Remove temp file on close if true
|
removeTarPathOnClose bool // Remove temp file on close if true
|
||||||
|
cacheDataLock sync.Once // Atomic way to ensure that ensureCachedDataIsPresent is only invoked once
|
||||||
// The following data is only available after ensureCachedDataIsPresent() succeeds
|
// The following data is only available after ensureCachedDataIsPresent() succeeds
|
||||||
|
cacheDataResult error // The return value of ensureCachedDataIsPresent, since it should be as safe to cache as the side effects
|
||||||
tarManifest *ManifestItem // nil if not available yet.
|
tarManifest *ManifestItem // nil if not available yet.
|
||||||
configBytes []byte
|
configBytes []byte
|
||||||
configDigest digest.Digest
|
configDigest digest.Digest
|
||||||
@ -199,34 +202,36 @@ func (s *Source) readTarComponent(path string) ([]byte, error) {
|
|||||||
|
|
||||||
// ensureCachedDataIsPresent loads data necessary for any of the public accessors.
|
// ensureCachedDataIsPresent loads data necessary for any of the public accessors.
|
||||||
func (s *Source) ensureCachedDataIsPresent() error {
|
func (s *Source) ensureCachedDataIsPresent() error {
|
||||||
if s.tarManifest != nil {
|
s.cacheDataLock.Do(func() {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and parse manifest.json
|
// Read and parse manifest.json
|
||||||
tarManifest, err := s.loadTarManifest()
|
tarManifest, err := s.loadTarManifest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
s.cacheDataResult = err
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to make sure length is 1
|
// Check to make sure length is 1
|
||||||
if len(tarManifest) != 1 {
|
if len(tarManifest) != 1 {
|
||||||
return errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(tarManifest))
|
s.cacheDataResult = errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(tarManifest))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and parse config.
|
// Read and parse config.
|
||||||
configBytes, err := s.readTarComponent(tarManifest[0].Config)
|
configBytes, err := s.readTarComponent(tarManifest[0].Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
s.cacheDataResult = err
|
||||||
|
return
|
||||||
}
|
}
|
||||||
var parsedConfig manifest.Schema2Image // There's a lot of info there, but we only really care about layer DiffIDs.
|
var parsedConfig manifest.Schema2Image // There's a lot of info there, but we only really care about layer DiffIDs.
|
||||||
if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
|
if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
|
||||||
return errors.Wrapf(err, "Error decoding tar config %s", tarManifest[0].Config)
|
s.cacheDataResult = errors.Wrapf(err, "Error decoding tar config %s", tarManifest[0].Config)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
knownLayers, err := s.prepareLayerData(&tarManifest[0], &parsedConfig)
|
knownLayers, err := s.prepareLayerData(&tarManifest[0], &parsedConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
s.cacheDataResult = err
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success; commit.
|
// Success; commit.
|
||||||
@ -235,7 +240,8 @@ func (s *Source) ensureCachedDataIsPresent() error {
|
|||||||
s.configDigest = digest.FromBytes(configBytes)
|
s.configDigest = digest.FromBytes(configBytes)
|
||||||
s.orderedDiffIDList = parsedConfig.RootFS.DiffIDs
|
s.orderedDiffIDList = parsedConfig.RootFS.DiffIDs
|
||||||
s.knownLayers = knownLayers
|
s.knownLayers = knownLayers
|
||||||
return nil
|
})
|
||||||
|
return s.cacheDataResult
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadTarManifest loads and decodes the manifest.json.
|
// loadTarManifest loads and decodes the manifest.json.
|
||||||
@ -399,7 +405,7 @@ func (r uncompressedReadCloser) Close() error {
|
|||||||
|
|
||||||
// HasThreadSafeGetBlob indicates whether GetBlob can be executed concurrently.
|
// HasThreadSafeGetBlob indicates whether GetBlob can be executed concurrently.
|
||||||
func (s *Source) HasThreadSafeGetBlob() bool {
|
func (s *Source) HasThreadSafeGetBlob() bool {
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown).
|
// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown).
|
||||||
|
13
vendor/github.com/containers/image/ostree/ostree_src.go
generated
vendored
13
vendor/github.com/containers/image/ostree/ostree_src.go
generated
vendored
@ -17,7 +17,7 @@ import (
|
|||||||
"github.com/containers/image/types"
|
"github.com/containers/image/types"
|
||||||
"github.com/containers/storage/pkg/ioutils"
|
"github.com/containers/storage/pkg/ioutils"
|
||||||
"github.com/klauspost/pgzip"
|
"github.com/klauspost/pgzip"
|
||||||
"github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
glib "github.com/ostreedev/ostree-go/pkg/glibobject"
|
glib "github.com/ostreedev/ostree-go/pkg/glibobject"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/vbatts/tar-split/tar/asm"
|
"github.com/vbatts/tar-split/tar/asm"
|
||||||
@ -313,24 +313,19 @@ func (s *ostreeImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
defer mfz.Close()
|
|
||||||
metaUnpacker := storage.NewJSONUnpacker(mfz)
|
metaUnpacker := storage.NewJSONUnpacker(mfz)
|
||||||
|
|
||||||
getter, err := newOSTreePathFileGetter(s.repo, branch)
|
getter, err := newOSTreePathFileGetter(s.repo, branch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mfz.Close()
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ots := asm.NewOutputTarStream(getter, metaUnpacker)
|
ots := asm.NewOutputTarStream(getter, metaUnpacker)
|
||||||
|
|
||||||
pipeReader, pipeWriter := io.Pipe()
|
rc := ioutils.NewReadCloserWrapper(ots, func() error {
|
||||||
go func() {
|
|
||||||
io.Copy(pipeWriter, ots)
|
|
||||||
pipeWriter.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
rc := ioutils.NewReadCloserWrapper(pipeReader, func() error {
|
|
||||||
getter.Close()
|
getter.Close()
|
||||||
|
mfz.Close()
|
||||||
return ots.Close()
|
return ots.Close()
|
||||||
})
|
})
|
||||||
return rc, layerSize, nil
|
return rc, layerSize, nil
|
||||||
|
23
vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
23
vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
@ -53,20 +53,23 @@ type Registry struct {
|
|||||||
Prefix string `toml:"prefix"`
|
Prefix string `toml:"prefix"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// backwards compatability to sysregistries v1
|
// V1TOMLregistries is for backwards compatibility to sysregistries v1
|
||||||
type v1TOMLregistries struct {
|
type V1TOMLregistries struct {
|
||||||
Registries []string `toml:"registries"`
|
Registries []string `toml:"registries"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// V1TOMLConfig is for backwards compatibility to sysregistries v1
|
||||||
|
type V1TOMLConfig struct {
|
||||||
|
Search V1TOMLregistries `toml:"search"`
|
||||||
|
Insecure V1TOMLregistries `toml:"insecure"`
|
||||||
|
Block V1TOMLregistries `toml:"block"`
|
||||||
|
}
|
||||||
|
|
||||||
// tomlConfig is the data type used to unmarshal the toml config.
|
// tomlConfig is the data type used to unmarshal the toml config.
|
||||||
type tomlConfig struct {
|
type tomlConfig struct {
|
||||||
Registries []Registry `toml:"registry"`
|
Registries []Registry `toml:"registry"`
|
||||||
// backwards compatability to sysregistries v1
|
// backwards compatability to sysregistries v1
|
||||||
V1Registries struct {
|
V1TOMLConfig `toml:"registries"`
|
||||||
Search v1TOMLregistries `toml:"search"`
|
|
||||||
Insecure v1TOMLregistries `toml:"insecure"`
|
|
||||||
Block v1TOMLregistries `toml:"block"`
|
|
||||||
} `toml:"registries"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvalidRegistries represents an invalid registry configurations. An example
|
// InvalidRegistries represents an invalid registry configurations. An example
|
||||||
@ -129,21 +132,21 @@ func getV1Registries(config *tomlConfig) ([]Registry, error) {
|
|||||||
|
|
||||||
// Note: config.V1Registries.Search needs to be processed first to ensure registryOrder is populated in the right order
|
// Note: config.V1Registries.Search needs to be processed first to ensure registryOrder is populated in the right order
|
||||||
// if one of the search registries is also in one of the other lists.
|
// if one of the search registries is also in one of the other lists.
|
||||||
for _, search := range config.V1Registries.Search.Registries {
|
for _, search := range config.V1TOMLConfig.Search.Registries {
|
||||||
reg, err := getRegistry(search)
|
reg, err := getRegistry(search)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reg.Search = true
|
reg.Search = true
|
||||||
}
|
}
|
||||||
for _, blocked := range config.V1Registries.Block.Registries {
|
for _, blocked := range config.V1TOMLConfig.Block.Registries {
|
||||||
reg, err := getRegistry(blocked)
|
reg, err := getRegistry(blocked)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reg.Blocked = true
|
reg.Blocked = true
|
||||||
}
|
}
|
||||||
for _, insecure := range config.V1Registries.Insecure.Registries {
|
for _, insecure := range config.V1TOMLConfig.Insecure.Registries {
|
||||||
reg, err := getRegistry(insecure)
|
reg, err := getRegistry(insecure)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
65
vendor/github.com/containers/image/storage/storage_image.go
generated
vendored
65
vendor/github.com/containers/image/storage/storage_image.go
generated
vendored
@ -14,6 +14,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/containers/image/docker/reference"
|
||||||
"github.com/containers/image/image"
|
"github.com/containers/image/image"
|
||||||
"github.com/containers/image/internal/tmpdir"
|
"github.com/containers/image/internal/tmpdir"
|
||||||
"github.com/containers/image/manifest"
|
"github.com/containers/image/manifest"
|
||||||
@ -70,6 +71,13 @@ type storageImageCloser struct {
|
|||||||
size int64
|
size int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// manifestBigDataKey returns a key suitable for recording a manifest with the specified digest using storage.Store.ImageBigData and related functions.
|
||||||
|
// If a specific manifest digest is explicitly requested by the user, the key retruned function should be used preferably;
|
||||||
|
// for compatibility, if a manifest is not available under this key, check also storage.ImageDigestBigDataKey
|
||||||
|
func manifestBigDataKey(digest digest.Digest) string {
|
||||||
|
return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String()
|
||||||
|
}
|
||||||
|
|
||||||
// newImageSource sets up an image for reading.
|
// newImageSource sets up an image for reading.
|
||||||
func newImageSource(imageRef storageReference) (*storageImageSource, error) {
|
func newImageSource(imageRef storageReference) (*storageImageSource, error) {
|
||||||
// First, locate the image.
|
// First, locate the image.
|
||||||
@ -177,13 +185,30 @@ func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *di
|
|||||||
return nil, "", ErrNoManifestLists
|
return nil, "", ErrNoManifestLists
|
||||||
}
|
}
|
||||||
if len(s.cachedManifest) == 0 {
|
if len(s.cachedManifest) == 0 {
|
||||||
// We stored the manifest as an item named after storage.ImageDigestBigDataKey.
|
// The manifest is stored as a big data item.
|
||||||
|
// Prefer the manifest corresponding to the user-specified digest, if available.
|
||||||
|
if s.imageRef.named != nil {
|
||||||
|
if digested, ok := s.imageRef.named.(reference.Digested); ok {
|
||||||
|
key := manifestBigDataKey(digested.Digest())
|
||||||
|
blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
|
||||||
|
if err != nil && !os.IsNotExist(err) { // os.IsNotExist is true if the image exists but there is no data corresponding to key
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
s.cachedManifest = blob
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the user did not specify a digest, or this is an old image stored before manifestBigDataKey was introduced, use the default manifest.
|
||||||
|
// Note that the manifest may not match the expected digest, and that is likely to fail eventually, e.g. in c/image/image/UnparsedImage.Manifest().
|
||||||
|
if len(s.cachedManifest) == 0 {
|
||||||
cachedBlob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, storage.ImageDigestBigDataKey)
|
cachedBlob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, storage.ImageDigestBigDataKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
s.cachedManifest = cachedBlob
|
s.cachedManifest = cachedBlob
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return s.cachedManifest, manifest.GuessMIMEType(s.cachedManifest), err
|
return s.cachedManifest, manifest.GuessMIMEType(s.cachedManifest), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,6 +685,7 @@ func (s *storageImageDestination) Commit(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
lastLayer = layer.ID
|
lastLayer = layer.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// If one of those blobs was a configuration blob, then we can try to dig out the date when the image
|
// If one of those blobs was a configuration blob, then we can try to dig out the date when the image
|
||||||
// was originally created, in case we're just copying it. If not, no harm done.
|
// was originally created, in case we're just copying it. If not, no harm done.
|
||||||
options := &storage.ImageOptions{}
|
options := &storage.ImageOptions{}
|
||||||
@ -667,9 +693,6 @@ func (s *storageImageDestination) Commit(ctx context.Context) error {
|
|||||||
logrus.Debugf("setting image creation date to %s", inspect.Created)
|
logrus.Debugf("setting image creation date to %s", inspect.Created)
|
||||||
options.CreationDate = *inspect.Created
|
options.CreationDate = *inspect.Created
|
||||||
}
|
}
|
||||||
if manifestDigest, err := manifest.Digest(s.manifest); err == nil {
|
|
||||||
options.Digest = manifestDigest
|
|
||||||
}
|
|
||||||
// Create the image record, pointing to the most-recently added layer.
|
// Create the image record, pointing to the most-recently added layer.
|
||||||
intendedID := s.imageRef.id
|
intendedID := s.imageRef.id
|
||||||
if intendedID == "" {
|
if intendedID == "" {
|
||||||
@ -735,8 +758,20 @@ func (s *storageImageDestination) Commit(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
logrus.Debugf("set names of image %q to %v", img.ID, names)
|
logrus.Debugf("set names of image %q to %v", img.ID, names)
|
||||||
}
|
}
|
||||||
// Save the manifest. Use storage.ImageDigestBigDataKey as the item's
|
// Save the manifest. Allow looking it up by digest by using the key convention defined by the Store.
|
||||||
// name, so that its digest can be used to locate the image in the Store.
|
// Record the manifest twice: using a digest-specific key to allow references to that specific digest instance,
|
||||||
|
// and using storage.ImageDigestBigDataKey for future users that don’t specify any digest and for compatibility with older readers.
|
||||||
|
manifestDigest, err := manifest.Digest(s.manifest)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error computing manifest digest")
|
||||||
|
}
|
||||||
|
if err := s.imageRef.transport.store.SetImageBigData(img.ID, manifestBigDataKey(manifestDigest), s.manifest); err != nil {
|
||||||
|
if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
|
||||||
|
logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
|
||||||
|
}
|
||||||
|
logrus.Debugf("error saving manifest for image %q: %v", img.ID, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := s.imageRef.transport.store.SetImageBigData(img.ID, storage.ImageDigestBigDataKey, s.manifest); err != nil {
|
if err := s.imageRef.transport.store.SetImageBigData(img.ID, storage.ImageDigestBigDataKey, s.manifest); err != nil {
|
||||||
if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
|
if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
|
||||||
logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
|
logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
|
||||||
@ -788,9 +823,21 @@ func (s *storageImageDestination) SupportedManifestMIMETypes() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PutManifest writes the manifest to the destination.
|
// PutManifest writes the manifest to the destination.
|
||||||
func (s *storageImageDestination) PutManifest(ctx context.Context, manifest []byte) error {
|
func (s *storageImageDestination) PutManifest(ctx context.Context, manifestBlob []byte) error {
|
||||||
s.manifest = make([]byte, len(manifest))
|
if s.imageRef.named != nil {
|
||||||
copy(s.manifest, manifest)
|
if digested, ok := s.imageRef.named.(reference.Digested); ok {
|
||||||
|
matches, err := manifest.MatchesDigest(manifestBlob, digested.Digest())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !matches {
|
||||||
|
return fmt.Errorf("Manifest does not match expected digest %s", digested.Digest())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.manifest = make([]byte, len(manifestBlob))
|
||||||
|
copy(s.manifest, manifestBlob)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
vendor/github.com/containers/image/storage/storage_reference.go
generated
vendored
22
vendor/github.com/containers/image/storage/storage_reference.go
generated
vendored
@ -55,7 +55,7 @@ func imageMatchesRepo(image *storage.Image, ref reference.Named) bool {
|
|||||||
// one present with the same name or ID, and return the image.
|
// one present with the same name or ID, and return the image.
|
||||||
func (s *storageReference) resolveImage() (*storage.Image, error) {
|
func (s *storageReference) resolveImage() (*storage.Image, error) {
|
||||||
var loadedImage *storage.Image
|
var loadedImage *storage.Image
|
||||||
if s.id == "" {
|
if s.id == "" && s.named != nil {
|
||||||
// Look for an image that has the expanded reference name as an explicit Name value.
|
// Look for an image that has the expanded reference name as an explicit Name value.
|
||||||
image, err := s.transport.store.Image(s.named.String())
|
image, err := s.transport.store.Image(s.named.String())
|
||||||
if image != nil && err == nil {
|
if image != nil && err == nil {
|
||||||
@ -69,7 +69,7 @@ func (s *storageReference) resolveImage() (*storage.Image, error) {
|
|||||||
// though possibly with a different tag or digest, as a Name value, so
|
// though possibly with a different tag or digest, as a Name value, so
|
||||||
// that the canonical reference can be implicitly resolved to the image.
|
// that the canonical reference can be implicitly resolved to the image.
|
||||||
images, err := s.transport.store.ImagesByDigest(digested.Digest())
|
images, err := s.transport.store.ImagesByDigest(digested.Digest())
|
||||||
if images != nil && err == nil {
|
if err == nil && len(images) > 0 {
|
||||||
for _, image := range images {
|
for _, image := range images {
|
||||||
if imageMatchesRepo(image, s.named) {
|
if imageMatchesRepo(image, s.named) {
|
||||||
loadedImage = image
|
loadedImage = image
|
||||||
@ -97,6 +97,24 @@ func (s *storageReference) resolveImage() (*storage.Image, error) {
|
|||||||
return nil, ErrNoSuchImage
|
return nil, ErrNoSuchImage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Default to having the image digest that we hand back match the most recently
|
||||||
|
// added manifest...
|
||||||
|
if digest, ok := loadedImage.BigDataDigests[storage.ImageDigestBigDataKey]; ok {
|
||||||
|
loadedImage.Digest = digest
|
||||||
|
}
|
||||||
|
// ... unless the named reference says otherwise, and it matches one of the digests
|
||||||
|
// in the image. For those cases, set the Digest field to that value, for the
|
||||||
|
// sake of older consumers that don't know there's a whole list in there now.
|
||||||
|
if s.named != nil {
|
||||||
|
if digested, ok := s.named.(reference.Digested); ok {
|
||||||
|
for _, digest := range loadedImage.Digests {
|
||||||
|
if digest == digested.Digest() {
|
||||||
|
loadedImage.Digest = digest
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return loadedImage, nil
|
return loadedImage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
vendor/github.com/containers/image/storage/storage_transport.go
generated
vendored
5
vendor/github.com/containers/image/storage/storage_transport.go
generated
vendored
@ -284,11 +284,6 @@ func (s storageTransport) GetStoreImage(store storage.Store, ref types.ImageRefe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sref, ok := ref.(*storageReference); ok {
|
if sref, ok := ref.(*storageReference); ok {
|
||||||
if sref.id != "" {
|
|
||||||
if img, err := store.Image(sref.id); err == nil {
|
|
||||||
return img, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmpRef := *sref
|
tmpRef := *sref
|
||||||
if img, err := tmpRef.resolveImage(); err == nil {
|
if img, err := tmpRef.resolveImage(); err == nil {
|
||||||
return img, nil
|
return img, nil
|
||||||
|
2
vendor/github.com/containers/image/version/version.go
generated
vendored
2
vendor/github.com/containers/image/version/version.go
generated
vendored
@ -8,7 +8,7 @@ const (
|
|||||||
// VersionMinor is for functionality in a backwards-compatible manner
|
// VersionMinor is for functionality in a backwards-compatible manner
|
||||||
VersionMinor = 1
|
VersionMinor = 1
|
||||||
// VersionPatch is for backwards-compatible bug fixes
|
// VersionPatch is for backwards-compatible bug fixes
|
||||||
VersionPatch = 0
|
VersionPatch = 5
|
||||||
|
|
||||||
// VersionDev indicates development branch. Releases will be empty string.
|
// VersionDev indicates development branch. Releases will be empty string.
|
||||||
VersionDev = "-dev"
|
VersionDev = "-dev"
|
||||||
|
177
vendor/github.com/containers/storage/images.go
generated
vendored
177
vendor/github.com/containers/storage/images.go
generated
vendored
@ -5,8 +5,10 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/image/manifest"
|
||||||
"github.com/containers/storage/pkg/ioutils"
|
"github.com/containers/storage/pkg/ioutils"
|
||||||
"github.com/containers/storage/pkg/stringid"
|
"github.com/containers/storage/pkg/stringid"
|
||||||
"github.com/containers/storage/pkg/truncindex"
|
"github.com/containers/storage/pkg/truncindex"
|
||||||
@ -15,9 +17,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ImageDigestBigDataKey is the name of the big data item whose
|
// ImageDigestManifestBigDataNamePrefix is a prefix of big data item
|
||||||
// contents we consider useful for computing a "digest" of the
|
// names which we consider to be manifests, used for computing a
|
||||||
// image, by which we can locate the image later.
|
// "digest" value for the image as a whole, by which we can locate the
|
||||||
|
// image later.
|
||||||
|
ImageDigestManifestBigDataNamePrefix = "manifest"
|
||||||
|
// ImageDigestBigDataKey is provided for compatibility with older
|
||||||
|
// versions of the image library. It will be removed in the future.
|
||||||
ImageDigestBigDataKey = "manifest"
|
ImageDigestBigDataKey = "manifest"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,12 +33,19 @@ type Image struct {
|
|||||||
// value which was generated by the library.
|
// value which was generated by the library.
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
|
||||||
// Digest is a digest value that we can use to locate the image.
|
// Digest is a digest value that we can use to locate the image, if one
|
||||||
|
// was specified at creation-time.
|
||||||
Digest digest.Digest `json:"digest,omitempty"`
|
Digest digest.Digest `json:"digest,omitempty"`
|
||||||
|
|
||||||
|
// Digests is a list of digest values of the image's manifests, and
|
||||||
|
// possibly a manually-specified value, that we can use to locate the
|
||||||
|
// image. If Digest is set, its value is also in this list.
|
||||||
|
Digests []digest.Digest `json:"-"`
|
||||||
|
|
||||||
// Names is an optional set of user-defined convenience values. The
|
// Names is an optional set of user-defined convenience values. The
|
||||||
// image can be referred to by its ID or any of its names. Names are
|
// image can be referred to by its ID or any of its names. Names are
|
||||||
// unique among images.
|
// unique among images, and are often the text representation of tagged
|
||||||
|
// or canonical references.
|
||||||
Names []string `json:"names,omitempty"`
|
Names []string `json:"names,omitempty"`
|
||||||
|
|
||||||
// TopLayer is the ID of the topmost layer of the image itself, if the
|
// TopLayer is the ID of the topmost layer of the image itself, if the
|
||||||
@ -92,8 +105,10 @@ type ROImageStore interface {
|
|||||||
// Images returns a slice enumerating the known images.
|
// Images returns a slice enumerating the known images.
|
||||||
Images() ([]Image, error)
|
Images() ([]Image, error)
|
||||||
|
|
||||||
// Images returns a slice enumerating the images which have a big data
|
// ByDigest returns a slice enumerating the images which have either an
|
||||||
// item with the name ImageDigestBigDataKey and the specified digest.
|
// explicitly-set digest, or a big data item with a name that starts
|
||||||
|
// with ImageDigestManifestBigDataNamePrefix, which matches the
|
||||||
|
// specified digest.
|
||||||
ByDigest(d digest.Digest) ([]*Image, error)
|
ByDigest(d digest.Digest) ([]*Image, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +126,8 @@ type ImageStore interface {
|
|||||||
Create(id string, names []string, layer, metadata string, created time.Time, searchableDigest digest.Digest) (*Image, error)
|
Create(id string, names []string, layer, metadata string, created time.Time, searchableDigest digest.Digest) (*Image, error)
|
||||||
|
|
||||||
// SetNames replaces the list of names associated with an image with the
|
// SetNames replaces the list of names associated with an image with the
|
||||||
// supplied values.
|
// supplied values. The values are expected to be valid normalized
|
||||||
|
// named image references.
|
||||||
SetNames(id string, names []string) error
|
SetNames(id string, names []string) error
|
||||||
|
|
||||||
// Delete removes the record of the image.
|
// Delete removes the record of the image.
|
||||||
@ -135,6 +151,7 @@ func copyImage(i *Image) *Image {
|
|||||||
return &Image{
|
return &Image{
|
||||||
ID: i.ID,
|
ID: i.ID,
|
||||||
Digest: i.Digest,
|
Digest: i.Digest,
|
||||||
|
Digests: copyDigestSlice(i.Digests),
|
||||||
Names: copyStringSlice(i.Names),
|
Names: copyStringSlice(i.Names),
|
||||||
TopLayer: i.TopLayer,
|
TopLayer: i.TopLayer,
|
||||||
MappedTopLayers: copyStringSlice(i.MappedTopLayers),
|
MappedTopLayers: copyStringSlice(i.MappedTopLayers),
|
||||||
@ -147,6 +164,17 @@ func copyImage(i *Image) *Image {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyImageSlice(slice []*Image) []*Image {
|
||||||
|
if len(slice) > 0 {
|
||||||
|
cp := make([]*Image, len(slice))
|
||||||
|
for i := range slice {
|
||||||
|
cp[i] = copyImage(slice[i])
|
||||||
|
}
|
||||||
|
return cp
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *imageStore) Images() ([]Image, error) {
|
func (r *imageStore) Images() ([]Image, error) {
|
||||||
images := make([]Image, len(r.images))
|
images := make([]Image, len(r.images))
|
||||||
for i := range r.images {
|
for i := range r.images {
|
||||||
@ -167,6 +195,46 @@ func (r *imageStore) datapath(id, key string) string {
|
|||||||
return filepath.Join(r.datadir(id), makeBigDataBaseName(key))
|
return filepath.Join(r.datadir(id), makeBigDataBaseName(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bigDataNameIsManifest determines if a big data item with the specified name
|
||||||
|
// is considered to be representative of the image, in that its digest can be
|
||||||
|
// said to also be the image's digest. Currently, if its name is, or begins
|
||||||
|
// with, "manifest", we say that it is.
|
||||||
|
func bigDataNameIsManifest(name string) bool {
|
||||||
|
return strings.HasPrefix(name, ImageDigestManifestBigDataNamePrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// recomputeDigests takes a fixed digest and a name-to-digest map and builds a
|
||||||
|
// list of the unique values that would identify the image.
|
||||||
|
func (image *Image) recomputeDigests() error {
|
||||||
|
validDigests := make([]digest.Digest, 0, len(image.BigDataDigests)+1)
|
||||||
|
digests := make(map[digest.Digest]struct{})
|
||||||
|
if image.Digest != "" {
|
||||||
|
if err := image.Digest.Validate(); err != nil {
|
||||||
|
return errors.Wrapf(err, "error validating image digest %q", string(image.Digest))
|
||||||
|
}
|
||||||
|
digests[image.Digest] = struct{}{}
|
||||||
|
validDigests = append(validDigests, image.Digest)
|
||||||
|
}
|
||||||
|
for name, digest := range image.BigDataDigests {
|
||||||
|
if !bigDataNameIsManifest(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if digest.Validate() != nil {
|
||||||
|
return errors.Wrapf(digest.Validate(), "error validating digest %q for big data item %q", string(digest), name)
|
||||||
|
}
|
||||||
|
// Deduplicate the digest values.
|
||||||
|
if _, known := digests[digest]; !known {
|
||||||
|
digests[digest] = struct{}{}
|
||||||
|
validDigests = append(validDigests, digest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if image.Digest == "" && len(validDigests) > 0 {
|
||||||
|
image.Digest = validDigests[0]
|
||||||
|
}
|
||||||
|
image.Digests = validDigests
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *imageStore) Load() error {
|
func (r *imageStore) Load() error {
|
||||||
shouldSave := false
|
shouldSave := false
|
||||||
rpath := r.imagespath()
|
rpath := r.imagespath()
|
||||||
@ -189,17 +257,18 @@ func (r *imageStore) Load() error {
|
|||||||
r.removeName(conflict, name)
|
r.removeName(conflict, name)
|
||||||
shouldSave = true
|
shouldSave = true
|
||||||
}
|
}
|
||||||
names[name] = images[n]
|
|
||||||
}
|
}
|
||||||
// Implicit digest
|
// Compute the digest list.
|
||||||
if digest, ok := image.BigDataDigests[ImageDigestBigDataKey]; ok {
|
err = image.recomputeDigests()
|
||||||
digests[digest] = append(digests[digest], images[n])
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error computing digests for image with ID %q (%v)", image.ID, image.Names)
|
||||||
}
|
}
|
||||||
// Explicit digest
|
for _, name := range image.Names {
|
||||||
if image.Digest == "" {
|
names[name] = image
|
||||||
image.Digest = image.BigDataDigests[ImageDigestBigDataKey]
|
}
|
||||||
} else if image.Digest != image.BigDataDigests[ImageDigestBigDataKey] {
|
for _, digest := range image.Digests {
|
||||||
digests[image.Digest] = append(digests[image.Digest], images[n])
|
list := digests[digest]
|
||||||
|
digests[digest] = append(list, image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,12 +402,12 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, idInUse := r.byid[id]; idInUse {
|
if _, idInUse := r.byid[id]; idInUse {
|
||||||
return nil, ErrDuplicateID
|
return nil, errors.Wrapf(ErrDuplicateID, "an image with ID %q already exists", id)
|
||||||
}
|
}
|
||||||
names = dedupeNames(names)
|
names = dedupeNames(names)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if _, nameInUse := r.byname[name]; nameInUse {
|
if image, nameInUse := r.byname[name]; nameInUse {
|
||||||
return nil, ErrDuplicateName
|
return nil, errors.Wrapf(ErrDuplicateName, "image name %q is already associated with image %q", name, image.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if created.IsZero() {
|
if created.IsZero() {
|
||||||
@ -348,6 +417,7 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
|
|||||||
image = &Image{
|
image = &Image{
|
||||||
ID: id,
|
ID: id,
|
||||||
Digest: searchableDigest,
|
Digest: searchableDigest,
|
||||||
|
Digests: nil,
|
||||||
Names: names,
|
Names: names,
|
||||||
TopLayer: layer,
|
TopLayer: layer,
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
@ -357,16 +427,20 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
|
|||||||
Created: created,
|
Created: created,
|
||||||
Flags: make(map[string]interface{}),
|
Flags: make(map[string]interface{}),
|
||||||
}
|
}
|
||||||
|
err := image.recomputeDigests()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error validating digests for new image")
|
||||||
|
}
|
||||||
r.images = append(r.images, image)
|
r.images = append(r.images, image)
|
||||||
r.idindex.Add(id)
|
r.idindex.Add(id)
|
||||||
r.byid[id] = image
|
r.byid[id] = image
|
||||||
if searchableDigest != "" {
|
|
||||||
list := r.bydigest[searchableDigest]
|
|
||||||
r.bydigest[searchableDigest] = append(list, image)
|
|
||||||
}
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
r.byname[name] = image
|
r.byname[name] = image
|
||||||
}
|
}
|
||||||
|
for _, digest := range image.Digests {
|
||||||
|
list := r.bydigest[digest]
|
||||||
|
r.bydigest[digest] = append(list, image)
|
||||||
|
}
|
||||||
err = r.Save()
|
err = r.Save()
|
||||||
image = copyImage(image)
|
image = copyImage(image)
|
||||||
}
|
}
|
||||||
@ -444,34 +518,20 @@ func (r *imageStore) Delete(id string) error {
|
|||||||
for _, name := range image.Names {
|
for _, name := range image.Names {
|
||||||
delete(r.byname, name)
|
delete(r.byname, name)
|
||||||
}
|
}
|
||||||
if toDeleteIndex != -1 {
|
for _, digest := range image.Digests {
|
||||||
// delete the image at toDeleteIndex
|
prunedList := imageSliceWithoutValue(r.bydigest[digest], image)
|
||||||
if toDeleteIndex == len(r.images)-1 {
|
|
||||||
r.images = r.images[:len(r.images)-1]
|
|
||||||
} else {
|
|
||||||
r.images = append(r.images[:toDeleteIndex], r.images[toDeleteIndex+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if digest, ok := image.BigDataDigests[ImageDigestBigDataKey]; ok {
|
|
||||||
// remove the image from the digest-based index
|
|
||||||
if list, ok := r.bydigest[digest]; ok {
|
|
||||||
prunedList := imageSliceWithoutValue(list, image)
|
|
||||||
if len(prunedList) == 0 {
|
if len(prunedList) == 0 {
|
||||||
delete(r.bydigest, digest)
|
delete(r.bydigest, digest)
|
||||||
} else {
|
} else {
|
||||||
r.bydigest[digest] = prunedList
|
r.bydigest[digest] = prunedList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if toDeleteIndex != -1 {
|
||||||
if image.Digest != "" {
|
// delete the image at toDeleteIndex
|
||||||
// remove the image's hard-coded digest from the digest-based index
|
if toDeleteIndex == len(r.images)-1 {
|
||||||
if list, ok := r.bydigest[image.Digest]; ok {
|
r.images = r.images[:len(r.images)-1]
|
||||||
prunedList := imageSliceWithoutValue(list, image)
|
|
||||||
if len(prunedList) == 0 {
|
|
||||||
delete(r.bydigest, image.Digest)
|
|
||||||
} else {
|
} else {
|
||||||
r.bydigest[image.Digest] = prunedList
|
r.images = append(r.images[:toDeleteIndex], r.images[toDeleteIndex+1:]...)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := r.Save(); err != nil {
|
if err := r.Save(); err != nil {
|
||||||
@ -504,7 +564,7 @@ func (r *imageStore) Exists(id string) bool {
|
|||||||
|
|
||||||
func (r *imageStore) ByDigest(d digest.Digest) ([]*Image, error) {
|
func (r *imageStore) ByDigest(d digest.Digest) ([]*Image, error) {
|
||||||
if images, ok := r.bydigest[d]; ok {
|
if images, ok := r.bydigest[d]; ok {
|
||||||
return images, nil
|
return copyImageSlice(images), nil
|
||||||
}
|
}
|
||||||
return nil, ErrImageUnknown
|
return nil, ErrImageUnknown
|
||||||
}
|
}
|
||||||
@ -606,10 +666,19 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return ErrImageUnknown
|
return ErrImageUnknown
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(r.datadir(image.ID), 0700); err != nil {
|
err := os.MkdirAll(r.datadir(image.ID), 0700)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err := ioutils.AtomicWriteFile(r.datapath(image.ID, key), data, 0600)
|
var newDigest digest.Digest
|
||||||
|
if bigDataNameIsManifest(key) {
|
||||||
|
if newDigest, err = manifest.Digest(data); err != nil {
|
||||||
|
return errors.Wrapf(err, "error digesting manifest")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newDigest = digest.Canonical.FromBytes(data)
|
||||||
|
}
|
||||||
|
err = ioutils.AtomicWriteFile(r.datapath(image.ID, key), data, 0600)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
save := false
|
save := false
|
||||||
if image.BigDataSizes == nil {
|
if image.BigDataSizes == nil {
|
||||||
@ -621,7 +690,6 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
|
|||||||
image.BigDataDigests = make(map[string]digest.Digest)
|
image.BigDataDigests = make(map[string]digest.Digest)
|
||||||
}
|
}
|
||||||
oldDigest, digestOk := image.BigDataDigests[key]
|
oldDigest, digestOk := image.BigDataDigests[key]
|
||||||
newDigest := digest.Canonical.FromBytes(data)
|
|
||||||
image.BigDataDigests[key] = newDigest
|
image.BigDataDigests[key] = newDigest
|
||||||
if !sizeOk || oldSize != image.BigDataSizes[key] || !digestOk || oldDigest != newDigest {
|
if !sizeOk || oldSize != image.BigDataSizes[key] || !digestOk || oldDigest != newDigest {
|
||||||
save = true
|
save = true
|
||||||
@ -637,11 +705,8 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
|
|||||||
image.BigDataNames = append(image.BigDataNames, key)
|
image.BigDataNames = append(image.BigDataNames, key)
|
||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
if key == ImageDigestBigDataKey {
|
for _, oldDigest := range image.Digests {
|
||||||
if oldDigest != "" && oldDigest != newDigest && oldDigest != image.Digest {
|
// remove the image from the list of images in the digest-based index
|
||||||
// remove the image from the list of images in the digest-based
|
|
||||||
// index which corresponds to the old digest for this item, unless
|
|
||||||
// it's also the hard-coded digest
|
|
||||||
if list, ok := r.bydigest[oldDigest]; ok {
|
if list, ok := r.bydigest[oldDigest]; ok {
|
||||||
prunedList := imageSliceWithoutValue(list, image)
|
prunedList := imageSliceWithoutValue(list, image)
|
||||||
if len(prunedList) == 0 {
|
if len(prunedList) == 0 {
|
||||||
@ -651,6 +716,10 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err = image.recomputeDigests(); err != nil {
|
||||||
|
return errors.Wrapf(err, "error loading recomputing image digest information for %s", image.ID)
|
||||||
|
}
|
||||||
|
for _, newDigest := range image.Digests {
|
||||||
// add the image to the list of images in the digest-based index which
|
// add the image to the list of images in the digest-based index which
|
||||||
// corresponds to the new digest for this item, unless it's already there
|
// corresponds to the new digest for this item, unless it's already there
|
||||||
list := r.bydigest[newDigest]
|
list := r.bydigest[newDigest]
|
||||||
|
2
vendor/github.com/containers/storage/images_ffjson.go
generated
vendored
2
vendor/github.com/containers/storage/images_ffjson.go
generated
vendored
@ -1,5 +1,5 @@
|
|||||||
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
|
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
|
||||||
// source: ./images.go
|
// source: images.go
|
||||||
|
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
|
96
vendor/github.com/containers/storage/pkg/config/config.go
generated
vendored
Normal file
96
vendor/github.com/containers/storage/pkg/config/config.go
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
// ThinpoolOptionsConfig represents the "storage.options.thinpool"
|
||||||
|
// TOML config table.
|
||||||
|
type ThinpoolOptionsConfig struct {
|
||||||
|
// AutoExtendPercent determines the amount by which pool needs to be
|
||||||
|
// grown. This is specified in terms of % of pool size. So a value of
|
||||||
|
// 20 means that when threshold is hit, pool will be grown by 20% of
|
||||||
|
// existing pool size.
|
||||||
|
AutoExtendPercent string `toml:"autoextend_percent"`
|
||||||
|
|
||||||
|
// AutoExtendThreshold determines the pool extension threshold in terms
|
||||||
|
// of percentage of pool size. For example, if threshold is 60, that
|
||||||
|
// means when pool is 60% full, threshold has been hit.
|
||||||
|
AutoExtendThreshold string `toml:"autoextend_threshold"`
|
||||||
|
|
||||||
|
// BaseSize specifies the size to use when creating the base device,
|
||||||
|
// which limits the size of images and containers.
|
||||||
|
BaseSize string `toml:"basesize"`
|
||||||
|
|
||||||
|
// BlockSize specifies a custom blocksize to use for the thin pool.
|
||||||
|
BlockSize string `toml:"blocksize"`
|
||||||
|
|
||||||
|
// DirectLvmDevice specifies a custom block storage device to use for
|
||||||
|
// the thin pool.
|
||||||
|
DirectLvmDevice string `toml:"directlvm_device"`
|
||||||
|
|
||||||
|
// DirectLvmDeviceForcewipes device even if device already has a
|
||||||
|
// filesystem
|
||||||
|
DirectLvmDeviceForce string `toml:"directlvm_device_force"`
|
||||||
|
|
||||||
|
// Fs specifies the filesystem type to use for the base device.
|
||||||
|
Fs string `toml:"fs"`
|
||||||
|
|
||||||
|
// log_level sets the log level of devicemapper.
|
||||||
|
LogLevel string `toml:"log_level"`
|
||||||
|
|
||||||
|
// MinFreeSpace specifies the min free space percent in a thin pool
|
||||||
|
// require for new device creation to
|
||||||
|
MinFreeSpace string `toml:"min_free_space"`
|
||||||
|
|
||||||
|
// MkfsArg specifies extra mkfs arguments to be used when creating the
|
||||||
|
// basedevice.
|
||||||
|
MkfsArg string `toml:"mkfsarg"`
|
||||||
|
|
||||||
|
// MountOpt specifies extra mount options used when mounting the thin
|
||||||
|
// devices.
|
||||||
|
MountOpt string `toml:"mountopt"`
|
||||||
|
|
||||||
|
// UseDeferredDeletion marks device for deferred deletion
|
||||||
|
UseDeferredDeletion string `toml:"use_deferred_deletion"`
|
||||||
|
|
||||||
|
// UseDeferredRemoval marks device for deferred removal
|
||||||
|
UseDeferredRemoval string `toml:"use_deferred_removal"`
|
||||||
|
|
||||||
|
// XfsNoSpaceMaxRetriesFreeSpace specifies the maximum number of
|
||||||
|
// retries XFS should attempt to complete IO when ENOSPC (no space)
|
||||||
|
// error is returned by underlying storage device.
|
||||||
|
XfsNoSpaceMaxRetries string `toml:"xfs_nospace_max_retries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionsConfig represents the "storage.options" TOML config table.
|
||||||
|
type OptionsConfig struct {
|
||||||
|
// AdditionalImagesStores is the location of additional read/only
|
||||||
|
// Image stores. Usually used to access Networked File System
|
||||||
|
// for shared image content
|
||||||
|
AdditionalImageStores []string `toml:"additionalimagestores"`
|
||||||
|
|
||||||
|
// Size
|
||||||
|
Size string `toml:"size"`
|
||||||
|
|
||||||
|
// RemapUIDs is a list of default UID mappings to use for layers.
|
||||||
|
RemapUIDs string `toml:"remap-uids"`
|
||||||
|
// RemapGIDs is a list of default GID mappings to use for layers.
|
||||||
|
RemapGIDs string `toml:"remap-gids"`
|
||||||
|
|
||||||
|
// RemapUser is the name of one or more entries in /etc/subuid which
|
||||||
|
// should be used to set up default UID mappings.
|
||||||
|
RemapUser string `toml:"remap-user"`
|
||||||
|
// RemapGroup is the name of one or more entries in /etc/subgid which
|
||||||
|
// should be used to set up default GID mappings.
|
||||||
|
RemapGroup string `toml:"remap-group"`
|
||||||
|
// Thinpool container options to be handed to thinpool drivers
|
||||||
|
Thinpool struct{ ThinpoolOptionsConfig } `toml:"thinpool"`
|
||||||
|
// OSTree repository
|
||||||
|
OstreeRepo string `toml:"ostree_repo"`
|
||||||
|
|
||||||
|
// Do not create a bind mount on the storage home
|
||||||
|
SkipMountHome string `toml:"skip_mount_home"`
|
||||||
|
|
||||||
|
// Alternative program to use for the mount of the file system
|
||||||
|
MountProgram string `toml:"mount_program"`
|
||||||
|
|
||||||
|
// MountOpt specifies extra mount options used when mounting
|
||||||
|
MountOpt string `toml:"mountopt"`
|
||||||
|
}
|
435
vendor/github.com/containers/storage/store.go
generated
vendored
435
vendor/github.com/containers/storage/store.go
generated
vendored
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
drivers "github.com/containers/storage/drivers"
|
drivers "github.com/containers/storage/drivers"
|
||||||
"github.com/containers/storage/pkg/archive"
|
"github.com/containers/storage/pkg/archive"
|
||||||
|
"github.com/containers/storage/pkg/config"
|
||||||
"github.com/containers/storage/pkg/directory"
|
"github.com/containers/storage/pkg/directory"
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/containers/storage/pkg/ioutils"
|
"github.com/containers/storage/pkg/ioutils"
|
||||||
@ -842,12 +843,16 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if id == "" {
|
if id == "" {
|
||||||
id = stringid.GenerateRandomID()
|
id = stringid.GenerateRandomID()
|
||||||
@ -870,7 +875,9 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
|
|||||||
lstore.Lock()
|
lstore.Lock()
|
||||||
defer lstore.Unlock()
|
defer lstore.Unlock()
|
||||||
if modified, err := lstore.Modified(); modified || err != nil {
|
if modified, err := lstore.Modified(); modified || err != nil {
|
||||||
lstore.Load()
|
if err = lstore.Load(); err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if l, err := lstore.Get(parent); err == nil && l != nil {
|
if l, err := lstore.Get(parent); err == nil && l != nil {
|
||||||
@ -946,7 +953,9 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ilayer, err = store.Get(layer)
|
ilayer, err = store.Get(layer)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -966,7 +975,9 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o
|
|||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err = ristore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
creationDate := time.Now().UTC()
|
creationDate := time.Now().UTC()
|
||||||
@ -1004,7 +1015,9 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, crea
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Walk the top layer list.
|
// Walk the top layer list.
|
||||||
@ -1125,14 +1138,18 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var cimage *Image
|
var cimage *Image
|
||||||
for _, store := range append([]ROImageStore{istore}, istores...) {
|
for _, store := range append([]ROImageStore{istore}, istores...) {
|
||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cimage, err = store.Get(image)
|
cimage, err = store.Get(image)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -1162,7 +1179,9 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !options.HostUIDMapping && len(options.UIDMap) == 0 {
|
if !options.HostUIDMapping && len(options.UIDMap) == 0 {
|
||||||
uidMap = s.uidMap
|
uidMap = s.uidMap
|
||||||
@ -1222,7 +1241,9 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
options.IDMappingOptions = IDMappingOptions{
|
options.IDMappingOptions = IDMappingOptions{
|
||||||
HostUIDMapping: len(options.UIDMap) == 0,
|
HostUIDMapping: len(options.UIDMap) == 0,
|
||||||
@ -1254,17 +1275,23 @@ func (s *store) SetMetadata(id, metadata string) error {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err := ristore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rlstore.Exists(id) {
|
if rlstore.Exists(id) {
|
||||||
@ -1292,7 +1319,9 @@ func (s *store) Metadata(id string) (string, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if store.Exists(id) {
|
if store.Exists(id) {
|
||||||
return store.Metadata(id)
|
return store.Metadata(id)
|
||||||
@ -1311,7 +1340,9 @@ func (s *store) Metadata(id string) (string, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if store.Exists(id) {
|
if store.Exists(id) {
|
||||||
return store.Metadata(id)
|
return store.Metadata(id)
|
||||||
@ -1325,7 +1356,9 @@ func (s *store) Metadata(id string) (string, error) {
|
|||||||
cstore.Lock()
|
cstore.Lock()
|
||||||
defer cstore.Unlock()
|
defer cstore.Unlock()
|
||||||
if modified, err := cstore.Modified(); modified || err != nil {
|
if modified, err := cstore.Modified(); modified || err != nil {
|
||||||
cstore.Load()
|
if err = cstore.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cstore.Exists(id) {
|
if cstore.Exists(id) {
|
||||||
return cstore.Metadata(id)
|
return cstore.Metadata(id)
|
||||||
@ -1346,7 +1379,9 @@ func (s *store) ListImageBigData(id string) ([]string, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bigDataNames, err := store.BigDataNames(id)
|
bigDataNames, err := store.BigDataNames(id)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -1369,7 +1404,9 @@ func (s *store) ImageBigDataSize(id, key string) (int64, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
size, err := store.BigDataSize(id, key)
|
size, err := store.BigDataSize(id, key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -1393,7 +1430,9 @@ func (s *store) ImageBigDataDigest(id, key string) (digest.Digest, error) {
|
|||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err = ristore.Load(); err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
d, err := ristore.BigDataDigest(id, key)
|
d, err := ristore.BigDataDigest(id, key)
|
||||||
if err == nil && d.Validate() == nil {
|
if err == nil && d.Validate() == nil {
|
||||||
@ -1416,7 +1455,9 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
data, err := store.BigData(id, key)
|
data, err := store.BigData(id, key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -1435,7 +1476,9 @@ func (s *store) SetImageBigData(id, key string, data []byte) error {
|
|||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err = ristore.Load(); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ristore.SetBigData(id, key, data)
|
return ristore.SetBigData(id, key, data)
|
||||||
@ -1456,7 +1499,9 @@ func (s *store) ImageSize(id string) (int64, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1475,7 +1520,9 @@ func (s *store) ImageSize(id string) (int64, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if image, err = store.Get(id); err == nil {
|
if image, err = store.Get(id); err == nil {
|
||||||
imageStore = store
|
imageStore = store
|
||||||
@ -1560,7 +1607,9 @@ func (s *store) ContainerSize(id string) (int64, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1582,7 +1631,9 @@ func (s *store) ContainerSize(id string) (int64, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the container record.
|
// Read the container record.
|
||||||
@ -1644,7 +1695,9 @@ func (s *store) ListContainerBigData(id string) ([]string, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rcstore.BigDataNames(id)
|
return rcstore.BigDataNames(id)
|
||||||
@ -1658,7 +1711,9 @@ func (s *store) ContainerBigDataSize(id, key string) (int64, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rcstore.BigDataSize(id, key)
|
return rcstore.BigDataSize(id, key)
|
||||||
}
|
}
|
||||||
@ -1671,7 +1726,9 @@ func (s *store) ContainerBigDataDigest(id, key string) (digest.Digest, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rcstore.BigDataDigest(id, key)
|
return rcstore.BigDataDigest(id, key)
|
||||||
}
|
}
|
||||||
@ -1684,7 +1741,9 @@ func (s *store) ContainerBigData(id, key string) ([]byte, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rcstore.BigData(id, key)
|
return rcstore.BigData(id, key)
|
||||||
}
|
}
|
||||||
@ -1697,7 +1756,9 @@ func (s *store) SetContainerBigData(id, key string, data []byte) error {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rcstore.SetBigData(id, key, data)
|
return rcstore.SetBigData(id, key, data)
|
||||||
}
|
}
|
||||||
@ -1715,7 +1776,9 @@ func (s *store) Exists(id string) bool {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if store.Exists(id) {
|
if store.Exists(id) {
|
||||||
return true
|
return true
|
||||||
@ -1734,7 +1797,9 @@ func (s *store) Exists(id string) bool {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if store.Exists(id) {
|
if store.Exists(id) {
|
||||||
return true
|
return true
|
||||||
@ -1748,7 +1813,9 @@ func (s *store) Exists(id string) bool {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if rcstore.Exists(id) {
|
if rcstore.Exists(id) {
|
||||||
return true
|
return true
|
||||||
@ -1779,7 +1846,9 @@ func (s *store) SetNames(id string, names []string) error {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if rlstore.Exists(id) {
|
if rlstore.Exists(id) {
|
||||||
return rlstore.SetNames(id, deduped)
|
return rlstore.SetNames(id, deduped)
|
||||||
@ -1792,7 +1861,9 @@ func (s *store) SetNames(id string, names []string) error {
|
|||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err = ristore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ristore.Exists(id) {
|
if ristore.Exists(id) {
|
||||||
return ristore.SetNames(id, deduped)
|
return ristore.SetNames(id, deduped)
|
||||||
@ -1805,7 +1876,9 @@ func (s *store) SetNames(id string, names []string) error {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if rcstore.Exists(id) {
|
if rcstore.Exists(id) {
|
||||||
return rcstore.SetNames(id, deduped)
|
return rcstore.SetNames(id, deduped)
|
||||||
@ -1826,7 +1899,9 @@ func (s *store) Names(id string) ([]string, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if l, err := store.Get(id); l != nil && err == nil {
|
if l, err := store.Get(id); l != nil && err == nil {
|
||||||
return l.Names, nil
|
return l.Names, nil
|
||||||
@ -1845,7 +1920,9 @@ func (s *store) Names(id string) ([]string, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if i, err := store.Get(id); i != nil && err == nil {
|
if i, err := store.Get(id); i != nil && err == nil {
|
||||||
return i.Names, nil
|
return i.Names, nil
|
||||||
@ -1859,7 +1936,9 @@ func (s *store) Names(id string) ([]string, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if c, err := rcstore.Get(id); c != nil && err == nil {
|
if c, err := rcstore.Get(id); c != nil && err == nil {
|
||||||
return c.Names, nil
|
return c.Names, nil
|
||||||
@ -1880,7 +1959,9 @@ func (s *store) Lookup(name string) (string, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if l, err := store.Get(name); l != nil && err == nil {
|
if l, err := store.Get(name); l != nil && err == nil {
|
||||||
return l.ID, nil
|
return l.ID, nil
|
||||||
@ -1899,7 +1980,9 @@ func (s *store) Lookup(name string) (string, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if i, err := store.Get(name); i != nil && err == nil {
|
if i, err := store.Get(name); i != nil && err == nil {
|
||||||
return i.ID, nil
|
return i.ID, nil
|
||||||
@ -1913,7 +1996,9 @@ func (s *store) Lookup(name string) (string, error) {
|
|||||||
cstore.Lock()
|
cstore.Lock()
|
||||||
defer cstore.Unlock()
|
defer cstore.Unlock()
|
||||||
if modified, err := cstore.Modified(); modified || err != nil {
|
if modified, err := cstore.Modified(); modified || err != nil {
|
||||||
cstore.Load()
|
if err = cstore.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if c, err := cstore.Get(name); c != nil && err == nil {
|
if c, err := cstore.Get(name); c != nil && err == nil {
|
||||||
return c.ID, nil
|
return c.ID, nil
|
||||||
@ -1939,17 +2024,23 @@ func (s *store) DeleteLayer(id string) error {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err = ristore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rlstore.Exists(id) {
|
if rlstore.Exists(id) {
|
||||||
@ -2005,17 +2096,23 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error)
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err = ristore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
layersToRemove := []string{}
|
layersToRemove := []string{}
|
||||||
if ristore.Exists(id) {
|
if ristore.Exists(id) {
|
||||||
@ -2137,17 +2234,23 @@ func (s *store) DeleteContainer(id string) error {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err = ristore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rcstore.Exists(id) {
|
if rcstore.Exists(id) {
|
||||||
@ -2192,17 +2295,23 @@ func (s *store) Delete(id string) error {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err := ristore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rcstore.Exists(id) {
|
if rcstore.Exists(id) {
|
||||||
@ -2254,17 +2363,23 @@ func (s *store) Wipe() error {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ristore.Lock()
|
ristore.Lock()
|
||||||
defer ristore.Unlock()
|
defer ristore.Unlock()
|
||||||
if modified, err := ristore.Modified(); modified || err != nil {
|
if modified, err := ristore.Modified(); modified || err != nil {
|
||||||
ristore.Load()
|
if err = ristore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rcstore.Wipe(); err != nil {
|
if err = rcstore.Wipe(); err != nil {
|
||||||
@ -2306,7 +2421,9 @@ func (s *store) Mount(id, mountLabel string) (string, error) {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if rlstore.Exists(id) {
|
if rlstore.Exists(id) {
|
||||||
options := drivers.MountOpts{
|
options := drivers.MountOpts{
|
||||||
@ -2331,7 +2448,9 @@ func (s *store) Mounted(id string) (int, error) {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rlstore.Mounted(id)
|
return rlstore.Mounted(id)
|
||||||
@ -2348,7 +2467,9 @@ func (s *store) Unmount(id string, force bool) (bool, error) {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if rlstore.Exists(id) {
|
if rlstore.Exists(id) {
|
||||||
return rlstore.Unmount(id, force)
|
return rlstore.Unmount(id, force)
|
||||||
@ -2369,7 +2490,9 @@ func (s *store) Changes(from, to string) ([]archive.Change, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if store.Exists(to) {
|
if store.Exists(to) {
|
||||||
return store.Changes(from, to)
|
return store.Changes(from, to)
|
||||||
@ -2391,7 +2514,9 @@ func (s *store) DiffSize(from, to string) (int64, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if store.Exists(to) {
|
if store.Exists(to) {
|
||||||
return store.DiffSize(from, to)
|
return store.DiffSize(from, to)
|
||||||
@ -2412,7 +2537,9 @@ func (s *store) Diff(from, to string, options *DiffOptions) (io.ReadCloser, erro
|
|||||||
for _, store := range append([]ROLayerStore{lstore}, lstores...) {
|
for _, store := range append([]ROLayerStore{lstore}, lstores...) {
|
||||||
store.Lock()
|
store.Lock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if store.Exists(to) {
|
if store.Exists(to) {
|
||||||
rc, err := store.Diff(from, to, options)
|
rc, err := store.Diff(from, to, options)
|
||||||
@ -2440,7 +2567,9 @@ func (s *store) ApplyDiff(to string, diff io.Reader) (int64, error) {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if rlstore.Exists(to) {
|
if rlstore.Exists(to) {
|
||||||
return rlstore.ApplyDiff(to, diff)
|
return rlstore.ApplyDiff(to, diff)
|
||||||
@ -2463,7 +2592,9 @@ func (s *store) layersByMappedDigest(m func(ROLayerStore, digest.Digest) ([]Laye
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
storeLayers, err := m(store, d)
|
storeLayers, err := m(store, d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2507,7 +2638,9 @@ func (s *store) LayerSize(id string) (int64, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if store.Exists(id) {
|
if store.Exists(id) {
|
||||||
return store.Size(id)
|
return store.Size(id)
|
||||||
@ -2524,7 +2657,9 @@ func (s *store) LayerParentOwners(id string) ([]int, []int, error) {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if rlstore.Exists(id) {
|
if rlstore.Exists(id) {
|
||||||
return rlstore.ParentOwners(id)
|
return rlstore.ParentOwners(id)
|
||||||
@ -2544,12 +2679,16 @@ func (s *store) ContainerParentOwners(id string) ([]int, []int, error) {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
container, err := rcstore.Get(id)
|
container, err := rcstore.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2577,7 +2716,9 @@ func (s *store) Layers() ([]Layer, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
storeLayers, err := store.Layers()
|
storeLayers, err := store.Layers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2603,7 +2744,9 @@ func (s *store) Images() ([]Image, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
storeImages, err := store.Images()
|
storeImages, err := store.Images()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2623,7 +2766,9 @@ func (s *store) Containers() ([]Container, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rcstore.Containers()
|
return rcstore.Containers()
|
||||||
@ -2642,7 +2787,9 @@ func (s *store) Layer(id string) (*Layer, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
layer, err := store.Get(id)
|
layer, err := store.Get(id)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -2665,7 +2812,9 @@ func (s *store) Image(id string) (*Image, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
image, err := store.Get(id)
|
image, err := store.Get(id)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -2695,7 +2844,9 @@ func (s *store) ImagesByTopLayer(id string) ([]*Image, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
imageList, err := store.Images()
|
imageList, err := store.Images()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2726,7 +2877,9 @@ func (s *store) ImagesByDigest(d digest.Digest) ([]*Image, error) {
|
|||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
if modified, err := store.Modified(); modified || err != nil {
|
if modified, err := store.Modified(); modified || err != nil {
|
||||||
store.Load()
|
if err = store.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
imageList, err := store.ByDigest(d)
|
imageList, err := store.ByDigest(d)
|
||||||
if err != nil && err != ErrImageUnknown {
|
if err != nil && err != ErrImageUnknown {
|
||||||
@ -2745,7 +2898,9 @@ func (s *store) Container(id string) (*Container, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rcstore.Get(id)
|
return rcstore.Get(id)
|
||||||
@ -2759,7 +2914,9 @@ func (s *store) ContainerLayerID(id string) (string, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
container, err := rcstore.Get(id)
|
container, err := rcstore.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2780,7 +2937,9 @@ func (s *store) ContainerByLayer(id string) (*Container, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
containerList, err := rcstore.Containers()
|
containerList, err := rcstore.Containers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2803,7 +2962,9 @@ func (s *store) ContainerDirectory(id string) (string, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err = rcstore.Lookup(id)
|
id, err = rcstore.Lookup(id)
|
||||||
@ -2828,7 +2989,9 @@ func (s *store) ContainerRunDirectory(id string) (string, error) {
|
|||||||
rcstore.Lock()
|
rcstore.Lock()
|
||||||
defer rcstore.Unlock()
|
defer rcstore.Unlock()
|
||||||
if modified, err := rcstore.Modified(); modified || err != nil {
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
||||||
rcstore.Load()
|
if err = rcstore.Load(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err = rcstore.Lookup(id)
|
id, err = rcstore.Lookup(id)
|
||||||
@ -2899,7 +3062,9 @@ func (s *store) Shutdown(force bool) ([]string, error) {
|
|||||||
rlstore.Lock()
|
rlstore.Lock()
|
||||||
defer rlstore.Unlock()
|
defer rlstore.Unlock()
|
||||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||||
rlstore.Load()
|
if err = rlstore.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layers, err := rlstore.Layers()
|
layers, err := rlstore.Layers()
|
||||||
@ -2992,6 +3157,15 @@ func copyStringDigestMap(m map[string]digest.Digest) map[string]digest.Digest {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyDigestSlice(slice []digest.Digest) []digest.Digest {
|
||||||
|
if len(slice) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret := make([]digest.Digest, len(slice))
|
||||||
|
copy(ret, slice)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// copyStringInterfaceMap still forces us to assume that the interface{} is
|
// copyStringInterfaceMap still forces us to assume that the interface{} is
|
||||||
// a non-pointer scalar value
|
// a non-pointer scalar value
|
||||||
func copyStringInterfaceMap(m map[string]interface{}) map[string]interface{} {
|
func copyStringInterfaceMap(m map[string]interface{}) map[string]interface{} {
|
||||||
@ -3005,108 +3179,13 @@ func copyStringInterfaceMap(m map[string]interface{}) map[string]interface{} {
|
|||||||
// DefaultConfigFile path to the system wide storage.conf file
|
// DefaultConfigFile path to the system wide storage.conf file
|
||||||
const DefaultConfigFile = "/etc/containers/storage.conf"
|
const DefaultConfigFile = "/etc/containers/storage.conf"
|
||||||
|
|
||||||
// ThinpoolOptionsConfig represents the "storage.options.thinpool"
|
|
||||||
// TOML config table.
|
|
||||||
type ThinpoolOptionsConfig struct {
|
|
||||||
// AutoExtendPercent determines the amount by which pool needs to be
|
|
||||||
// grown. This is specified in terms of % of pool size. So a value of
|
|
||||||
// 20 means that when threshold is hit, pool will be grown by 20% of
|
|
||||||
// existing pool size.
|
|
||||||
AutoExtendPercent string `toml:"autoextend_percent"`
|
|
||||||
|
|
||||||
// AutoExtendThreshold determines the pool extension threshold in terms
|
|
||||||
// of percentage of pool size. For example, if threshold is 60, that
|
|
||||||
// means when pool is 60% full, threshold has been hit.
|
|
||||||
AutoExtendThreshold string `toml:"autoextend_threshold"`
|
|
||||||
|
|
||||||
// BaseSize specifies the size to use when creating the base device,
|
|
||||||
// which limits the size of images and containers.
|
|
||||||
BaseSize string `toml:"basesize"`
|
|
||||||
|
|
||||||
// BlockSize specifies a custom blocksize to use for the thin pool.
|
|
||||||
BlockSize string `toml:"blocksize"`
|
|
||||||
|
|
||||||
// DirectLvmDevice specifies a custom block storage device to use for
|
|
||||||
// the thin pool.
|
|
||||||
DirectLvmDevice string `toml:"directlvm_device"`
|
|
||||||
|
|
||||||
// DirectLvmDeviceForcewipes device even if device already has a
|
|
||||||
// filesystem
|
|
||||||
DirectLvmDeviceForce string `toml:"directlvm_device_force"`
|
|
||||||
|
|
||||||
// Fs specifies the filesystem type to use for the base device.
|
|
||||||
Fs string `toml:"fs"`
|
|
||||||
|
|
||||||
// log_level sets the log level of devicemapper.
|
|
||||||
LogLevel string `toml:"log_level"`
|
|
||||||
|
|
||||||
// MinFreeSpace specifies the min free space percent in a thin pool
|
|
||||||
// require for new device creation to
|
|
||||||
MinFreeSpace string `toml:"min_free_space"`
|
|
||||||
|
|
||||||
// MkfsArg specifies extra mkfs arguments to be used when creating the
|
|
||||||
// basedevice.
|
|
||||||
MkfsArg string `toml:"mkfsarg"`
|
|
||||||
|
|
||||||
// MountOpt specifies extra mount options used when mounting the thin
|
|
||||||
// devices.
|
|
||||||
MountOpt string `toml:"mountopt"`
|
|
||||||
|
|
||||||
// UseDeferredDeletion marks device for deferred deletion
|
|
||||||
UseDeferredDeletion string `toml:"use_deferred_deletion"`
|
|
||||||
|
|
||||||
// UseDeferredRemoval marks device for deferred removal
|
|
||||||
UseDeferredRemoval string `toml:"use_deferred_removal"`
|
|
||||||
|
|
||||||
// XfsNoSpaceMaxRetriesFreeSpace specifies the maximum number of
|
|
||||||
// retries XFS should attempt to complete IO when ENOSPC (no space)
|
|
||||||
// error is returned by underlying storage device.
|
|
||||||
XfsNoSpaceMaxRetries string `toml:"xfs_nospace_max_retries"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionsConfig represents the "storage.options" TOML config table.
|
|
||||||
type OptionsConfig struct {
|
|
||||||
// AdditionalImagesStores is the location of additional read/only
|
|
||||||
// Image stores. Usually used to access Networked File System
|
|
||||||
// for shared image content
|
|
||||||
AdditionalImageStores []string `toml:"additionalimagestores"`
|
|
||||||
|
|
||||||
// Size
|
|
||||||
Size string `toml:"size"`
|
|
||||||
|
|
||||||
// RemapUIDs is a list of default UID mappings to use for layers.
|
|
||||||
RemapUIDs string `toml:"remap-uids"`
|
|
||||||
// RemapGIDs is a list of default GID mappings to use for layers.
|
|
||||||
RemapGIDs string `toml:"remap-gids"`
|
|
||||||
|
|
||||||
// RemapUser is the name of one or more entries in /etc/subuid which
|
|
||||||
// should be used to set up default UID mappings.
|
|
||||||
RemapUser string `toml:"remap-user"`
|
|
||||||
// RemapGroup is the name of one or more entries in /etc/subgid which
|
|
||||||
// should be used to set up default GID mappings.
|
|
||||||
RemapGroup string `toml:"remap-group"`
|
|
||||||
// Thinpool container options to be handed to thinpool drivers
|
|
||||||
Thinpool struct{ ThinpoolOptionsConfig } `toml:"thinpool"`
|
|
||||||
// OSTree repository
|
|
||||||
OstreeRepo string `toml:"ostree_repo"`
|
|
||||||
|
|
||||||
// Do not create a bind mount on the storage home
|
|
||||||
SkipMountHome string `toml:"skip_mount_home"`
|
|
||||||
|
|
||||||
// Alternative program to use for the mount of the file system
|
|
||||||
MountProgram string `toml:"mount_program"`
|
|
||||||
|
|
||||||
// MountOpt specifies extra mount options used when mounting
|
|
||||||
MountOpt string `toml:"mountopt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TOML-friendly explicit tables used for conversions.
|
// TOML-friendly explicit tables used for conversions.
|
||||||
type tomlConfig struct {
|
type tomlConfig struct {
|
||||||
Storage struct {
|
Storage struct {
|
||||||
Driver string `toml:"driver"`
|
Driver string `toml:"driver"`
|
||||||
RunRoot string `toml:"runroot"`
|
RunRoot string `toml:"runroot"`
|
||||||
GraphRoot string `toml:"graphroot"`
|
GraphRoot string `toml:"graphroot"`
|
||||||
Options struct{ OptionsConfig } `toml:"options"`
|
Options struct{ config.OptionsConfig } `toml:"options"`
|
||||||
} `toml:"storage"`
|
} `toml:"storage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
vendor/github.com/containers/storage/vendor.conf
generated
vendored
9
vendor/github.com/containers/storage/vendor.conf
generated
vendored
@ -1,12 +1,18 @@
|
|||||||
github.com/BurntSushi/toml master
|
github.com/BurntSushi/toml master
|
||||||
github.com/Microsoft/go-winio 307e919c663683a9000576fdc855acaf9534c165
|
github.com/Microsoft/go-winio 307e919c663683a9000576fdc855acaf9534c165
|
||||||
github.com/Microsoft/hcsshim a8d9cc56cbce765a7eebdf4792e6ceceeff3edb8
|
github.com/Microsoft/hcsshim a8d9cc56cbce765a7eebdf4792e6ceceeff3edb8
|
||||||
|
github.com/containers/image master
|
||||||
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
|
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
|
||||||
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
|
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
|
||||||
github.com/docker/go-units 0dadbb0345b35ec7ef35e228dabb8de89a65bf52
|
github.com/docker/go-units 0dadbb0345b35ec7ef35e228dabb8de89a65bf52
|
||||||
|
github.com/docker/libtrust master
|
||||||
|
github.com/klauspost/compress v1.4.1
|
||||||
|
github.com/klauspost/cpuid v1.2.0
|
||||||
|
github.com/klauspost/pgzip v1.2.1
|
||||||
github.com/mattn/go-shellwords 753a2322a99f87c0eff284980e77f53041555bc6
|
github.com/mattn/go-shellwords 753a2322a99f87c0eff284980e77f53041555bc6
|
||||||
github.com/mistifyio/go-zfs c0224de804d438efd11ea6e52ada8014537d6062
|
github.com/mistifyio/go-zfs c0224de804d438efd11ea6e52ada8014537d6062
|
||||||
github.com/opencontainers/go-digest master
|
github.com/opencontainers/go-digest master
|
||||||
|
github.com/opencontainers/image-spec master
|
||||||
github.com/opencontainers/runc 6c22e77604689db8725fa866f0f2ec0b3e8c3a07
|
github.com/opencontainers/runc 6c22e77604689db8725fa866f0f2ec0b3e8c3a07
|
||||||
github.com/opencontainers/selinux v1.1
|
github.com/opencontainers/selinux v1.1
|
||||||
github.com/ostreedev/ostree-go master
|
github.com/ostreedev/ostree-go master
|
||||||
@ -23,6 +29,3 @@ golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
|
|||||||
golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
|
golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
|
||||||
gotest.tools master
|
gotest.tools master
|
||||||
github.com/google/go-cmp master
|
github.com/google/go-cmp master
|
||||||
github.com/klauspost/pgzip v1.2.1
|
|
||||||
github.com/klauspost/compress v1.4.1
|
|
||||||
github.com/klauspost/cpuid v1.2.0
|
|
||||||
|
Reference in New Issue
Block a user