Update containers/image

New pinned commit is b327f751c16e4a189fdcde4ea36be67cc964c605

Signed-off-by: Matthew Heon <matthew.heon@gmail.com>

Closes: #505
Approved by: rhatdan
This commit is contained in:
Matthew Heon
2018-03-15 16:48:32 -04:00
committed by Atomic Bot
parent d7acfb478e
commit b8386ce9e0
18 changed files with 112 additions and 127 deletions

View File

@ -495,7 +495,7 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
defer resp.Body.Close()
logrus.Debugf("Ping %s status %d", url, resp.StatusCode)
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusUnauthorized {
return errors.Errorf("error pinging repository, response code %d", resp.StatusCode)
return errors.Errorf("error pinging registry %s, response code %d", c.registry, resp.StatusCode)
}
c.challenges = parseAuthHeader(resp.Header)
c.scheme = scheme
@ -547,7 +547,7 @@ func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerRe
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, client.HandleErrorResponse(res)
return nil, errors.Wrapf(client.HandleErrorResponse(res), "Error downloading signatures for %s in %s", manifestDigest, ref.ref.Name())
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {

View File

@ -131,7 +131,7 @@ func (d *dockerImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobI
defer res.Body.Close()
if res.StatusCode != http.StatusAccepted {
logrus.Debugf("Error initiating layer upload, response %#v", *res)
return types.BlobInfo{}, errors.Wrapf(client.HandleErrorResponse(res), "Error initiating layer upload to %s", uploadPath)
return types.BlobInfo{}, errors.Wrapf(client.HandleErrorResponse(res), "Error initiating layer upload to %s in %s", uploadPath, d.c.registry)
}
uploadLocation, err := res.Location()
if err != nil {
@ -196,7 +196,7 @@ func (d *dockerImageDestination) HasBlob(info types.BlobInfo) (bool, int64, erro
return true, getBlobSize(res), nil
case http.StatusUnauthorized:
logrus.Debugf("... not authorized")
return false, -1, client.HandleErrorResponse(res)
return false, -1, errors.Wrapf(client.HandleErrorResponse(res), "Error checking whether a blob %s exists in %s", info.Digest, d.ref.ref.Name())
case http.StatusNotFound:
logrus.Debugf("... not present")
return false, -1, nil
@ -237,7 +237,7 @@ func (d *dockerImageDestination) PutManifest(m []byte) error {
}
defer res.Body.Close()
if !successStatus(res.StatusCode) {
err = errors.Wrapf(client.HandleErrorResponse(res), "Error uploading manifest to %s", path)
err = errors.Wrapf(client.HandleErrorResponse(res), "Error uploading manifest %s to %s", refTail, d.ref.ref.Name())
if isManifestInvalidError(errors.Cause(err)) {
err = types.ManifestTypeRejectedError{Err: err}
}
@ -447,7 +447,7 @@ sigExists:
logrus.Debugf("Error body %s", string(body))
}
logrus.Debugf("Error uploading signature, status %d, %#v", res.StatusCode, res)
return errors.Wrapf(client.HandleErrorResponse(res), "Error uploading signature to %s", path)
return errors.Wrapf(client.HandleErrorResponse(res), "Error uploading signature to %s in %s", path, d.c.registry)
}
}

View File

@ -95,7 +95,7 @@ func (s *dockerImageSource) fetchManifest(ctx context.Context, tagOrDigest strin
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, "", client.HandleErrorResponse(res)
return nil, "", errors.Wrapf(client.HandleErrorResponse(res), "Error reading manifest %s in %s", tagOrDigest, s.ref.ref.Name())
}
manblob, err := ioutil.ReadAll(res.Body)
if err != nil {

View File

@ -87,7 +87,8 @@ func (m *manifestSchema1) EmbeddedDockerReferenceConflicts(ref reference.Named)
return m.m.Name != name || m.m.Tag != tag
}
func (m *manifestSchema1) imageInspectInfo() (*types.ImageInspectInfo, error) {
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration.
func (m *manifestSchema1) Inspect() (*types.ImageInspectInfo, error) {
return m.m.Inspect(nil)
}
@ -187,7 +188,7 @@ func (m *manifestSchema1) convertToManifestSchema2(uploadedLayerInfos []types.Bl
diffIDs = append(diffIDs, d)
}
}
configJSON, err := m.m.ToSchema2(diffIDs)
configJSON, err := m.m.ToSchema2Config(diffIDs)
if err != nil {
return nil, err
}

View File

@ -130,7 +130,8 @@ func (m *manifestSchema2) EmbeddedDockerReferenceConflicts(ref reference.Named)
return false
}
func (m *manifestSchema2) imageInspectInfo() (*types.ImageInspectInfo, error) {
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration.
func (m *manifestSchema2) Inspect() (*types.ImageInspectInfo, error) {
getter := func(info types.BlobInfo) ([]byte, error) {
if info.Digest != m.ConfigInfo().Digest {
// Shouldn't ever happen

View File

@ -34,7 +34,8 @@ type genericManifest interface {
// It returns false if the manifest does not embed a Docker reference.
// (This embedding unfortunately happens for Docker schema1, please do not add support for this in any new formats.)
EmbeddedDockerReferenceConflicts(ref reference.Named) bool
imageInspectInfo() (*types.ImageInspectInfo, error) // To be called by inspectManifest
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration.
Inspect() (*types.ImageInspectInfo, error)
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
// This is a horribly specific interface, but computing InformationOnly.LayerDiffIDs can be very expensive to compute
// (most importantly it forces us to download the full layers even if they are already present at the destination).
@ -60,8 +61,3 @@ func manifestInstanceFromBlob(ctx *types.SystemContext, src types.ImageSource, m
return nil, fmt.Errorf("Unimplemented manifest MIME type %s", mt)
}
}
// inspectManifest is an implementation of types.Image.Inspect
func inspectManifest(m genericManifest) (*types.ImageInspectInfo, error) {
return m.imageInspectInfo()
}

View File

@ -57,11 +57,6 @@ func (i *memoryImage) Signatures(ctx context.Context) ([][]byte, error) {
return nil, errors.New("Internal error: Image.Signatures() is not supported for images modified in memory")
}
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration.
func (i *memoryImage) Inspect() (*types.ImageInspectInfo, error) {
return inspectManifest(i.genericManifest)
}
// LayerInfosForCopy returns an updated set of layer blob information which may not match the manifest.
// The Digest field is guaranteed to be provided; Size may be -1.
// WARNING: The list may contain duplicates, and they are semantically relevant.

View File

@ -110,7 +110,8 @@ func (m *manifestOCI1) EmbeddedDockerReferenceConflicts(ref reference.Named) boo
return false
}
func (m *manifestOCI1) imageInspectInfo() (*types.ImageInspectInfo, error) {
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration.
func (m *manifestOCI1) Inspect() (*types.ImageInspectInfo, error) {
getter := func(info types.BlobInfo) ([]byte, error) {
if info.Digest != m.ConfigInfo().Digest {
// Shouldn't ever happen

View File

@ -97,10 +97,6 @@ func (i *sourcedImage) Manifest() ([]byte, string, error) {
return i.manifestBlob, i.manifestMIMEType, nil
}
func (i *sourcedImage) Inspect() (*types.ImageInspectInfo, error) {
return inspectManifest(i.genericManifest)
}
func (i *sourcedImage) LayerInfosForCopy() ([]types.BlobInfo, error) {
return i.UnparsedImage.LayerInfosForCopy()
return i.UnparsedImage.src.LayerInfosForCopy()
}

View File

@ -93,10 +93,3 @@ func (i *UnparsedImage) Signatures(ctx context.Context) ([][]byte, error) {
}
return i.cachedSignatures, nil
}
// LayerInfosForCopy returns an updated set of layer blob information which may not match the manifest.
// The Digest field is guaranteed to be provided; Size may be -1.
// WARNING: The list may contain duplicates, and they are semantically relevant.
func (i *UnparsedImage) LayerInfosForCopy() ([]types.BlobInfo, error) {
return i.src.LayerInfosForCopy()
}

View File

@ -116,6 +116,7 @@ func (m *Schema1) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
if len(m.FSLayers) != len(layerInfos) {
return errors.Errorf("Error preparing updated manifest: layer count changed from %d to %d", len(m.FSLayers), len(layerInfos))
}
m.FSLayers = make([]Schema1FSLayers, len(layerInfos))
for i, info := range layerInfos {
// (docker push) sets up m.History.V1Compatibility->{Id,Parent} based on values of info.Digest,
// but (docker pull) ignores them in favor of computing DiffIDs from uncompressed data, except verifying the child->parent links and uniqueness.
@ -202,44 +203,39 @@ func (m *Schema1) Inspect(_ func(types.BlobInfo) ([]byte, error)) (*types.ImageI
if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), s1); err != nil {
return nil, err
}
return &types.ImageInspectInfo{
i := &types.ImageInspectInfo{
Tag: m.Tag,
Created: s1.Created,
Created: &s1.Created,
DockerVersion: s1.DockerVersion,
Labels: make(map[string]string),
Architecture: s1.Architecture,
Os: s1.OS,
Layers: LayerInfosToStrings(m.LayerInfos()),
}, nil
}
if s1.Config != nil {
i.Labels = s1.Config.Labels
}
return i, nil
}
// ToSchema2 builds a schema2-style configuration blob using the supplied diffIDs.
func (m *Schema1) ToSchema2(diffIDs []digest.Digest) ([]byte, error) {
// ToSchema2Config builds a schema2-style configuration blob using the supplied diffIDs.
func (m *Schema1) ToSchema2Config(diffIDs []digest.Digest) ([]byte, error) {
// Convert the schema 1 compat info into a schema 2 config, constructing some of the fields
// that aren't directly comparable using info from the manifest.
if len(m.History) == 0 {
return nil, errors.New("image has no layers")
}
s2 := struct {
Schema2Image
ID string `json:"id,omitempty"`
Parent string `json:"parent,omitempty"`
ParentID string `json:"parent_id,omitempty"`
LayerID string `json:"layer_id,omitempty"`
ThrowAway bool `json:"throwaway,omitempty"`
Size int64 `json:",omitempty"`
}{}
s1 := Schema2V1Image{}
config := []byte(m.History[0].V1Compatibility)
err := json.Unmarshal(config, &s2)
err := json.Unmarshal(config, &s1)
if err != nil {
return nil, errors.Wrapf(err, "error decoding configuration")
}
// Images created with versions prior to 1.8.3 require us to re-encode the encoded object,
// adding some fields that aren't "omitempty".
if s2.DockerVersion != "" && versions.LessThan(s2.DockerVersion, "1.8.3") {
config, err = json.Marshal(&s2)
if s1.DockerVersion != "" && versions.LessThan(s1.DockerVersion, "1.8.3") {
config, err = json.Marshal(&s1)
if err != nil {
return nil, errors.Wrapf(err, "error re-encoding compat image config %#v", s2)
return nil, errors.Wrapf(err, "error re-encoding compat image config %#v", s1)
}
}
// Build the history.
@ -270,7 +266,7 @@ func (m *Schema1) ToSchema2(diffIDs []digest.Digest) ([]byte, error) {
raw := make(map[string]*json.RawMessage)
err = json.Unmarshal(config, &raw)
if err != nil {
return nil, errors.Wrapf(err, "error re-decoding compat image config %#v: %v", s2)
return nil, errors.Wrapf(err, "error re-decoding compat image config %#v: %v", s1)
}
// Drop some fields.
delete(raw, "id")
@ -295,14 +291,14 @@ func (m *Schema1) ToSchema2(diffIDs []digest.Digest) ([]byte, error) {
// Encode the result.
config, err = json.Marshal(raw)
if err != nil {
return nil, errors.Errorf("error re-encoding compat image config %#v: %v", s2, err)
return nil, errors.Errorf("error re-encoding compat image config %#v: %v", s1, err)
}
return config, nil
}
// ImageID computes an ID which can uniquely identify this image by its contents.
func (m *Schema1) ImageID(diffIDs []digest.Digest) (string, error) {
image, err := m.ToSchema2(diffIDs)
image, err := m.ToSchema2Config(diffIDs)
if err != nil {
return "", err
}

View File

@ -142,13 +142,6 @@ type Schema2Image struct {
History []Schema2History `json:"history,omitempty"`
OSVersion string `json:"os.version,omitempty"`
OSFeatures []string `json:"os.features,omitempty"`
// rawJSON caches the immutable JSON associated with this image.
rawJSON []byte
// computedID is the ID computed from the hash of the image config.
// Not to be confused with the legacy V1 ID in V1Image.
computedID digest.Digest
}
// Schema2FromManifest creates a Schema2 manifest instance from a manifest blob.
@ -230,7 +223,7 @@ func (m *Schema2) Inspect(configGetter func(types.BlobInfo) ([]byte, error)) (*t
}
i := &types.ImageInspectInfo{
Tag: "",
Created: s2.Created,
Created: &s2.Created,
DockerVersion: s2.DockerVersion,
Architecture: s2.Architecture,
Os: s2.OS,

View File

@ -2,7 +2,6 @@ package manifest
import (
"encoding/json"
"time"
"github.com/containers/image/types"
"github.com/opencontainers/go-digest"
@ -95,13 +94,9 @@ func (m *OCI1) Inspect(configGetter func(types.BlobInfo) ([]byte, error)) (*type
}
d1 := &Schema2V1Image{}
json.Unmarshal(config, d1)
created := time.Time{}
if v1.Created != nil {
created = *v1.Created
}
i := &types.ImageInspectInfo{
Tag: "",
Created: created,
Created: v1.Created,
DockerVersion: d1.DockerVersion,
Labels: v1.Config.Labels,
Architecture: v1.Architecture,

View File

@ -27,7 +27,7 @@ type dockerConfigFile struct {
}
const (
defaultPath = "/run/user"
defaultPath = "/run"
authCfg = "containers"
authCfgFileName = "auth.json"
dockerCfg = ".docker"
@ -64,7 +64,11 @@ func GetAuthentication(ctx *types.SystemContext, registry string) (string, strin
}
dockerLegacyPath := filepath.Join(homedir.Get(), dockerLegacyCfg)
paths := [3]string{getPathToAuth(ctx), filepath.Join(homedir.Get(), dockerCfg, dockerCfgFileName), dockerLegacyPath}
pathToAuth, err := getPathToAuth(ctx)
if err != nil {
return "", "", err
}
paths := [3]string{pathToAuth, filepath.Join(homedir.Get(), dockerCfg, dockerCfgFileName), dockerLegacyPath}
for _, path := range paths {
legacyFormat := path == dockerLegacyPath
@ -82,13 +86,16 @@ func GetAuthentication(ctx *types.SystemContext, registry string) (string, strin
// GetUserLoggedIn returns the username logged in to registry from either
// auth.json or XDG_RUNTIME_DIR
// Used to tell the user if someone is logged in to the registry when logging in
func GetUserLoggedIn(ctx *types.SystemContext, registry string) string {
path := getPathToAuth(ctx)
func GetUserLoggedIn(ctx *types.SystemContext, registry string) (string, error) {
path, err := getPathToAuth(ctx)
if err != nil {
return "", err
}
username, _, _ := findAuthentication(registry, path, false)
if username != "" {
return username
return username, nil
}
return ""
return "", nil
}
// RemoveAuthentication deletes the credentials stored in auth.json
@ -123,20 +130,30 @@ func RemoveAllAuthentication(ctx *types.SystemContext) error {
// The path can be overriden by the user if the overwrite-path flag is set
// If the flag is not set and XDG_RUNTIME_DIR is ser, the auth.json file is saved in XDG_RUNTIME_DIR/containers
// Otherwise, the auth.json file is stored in /run/user/UID/containers
func getPathToAuth(ctx *types.SystemContext) string {
func getPathToAuth(ctx *types.SystemContext) (string, error) {
if ctx != nil {
if ctx.AuthFilePath != "" {
return ctx.AuthFilePath
return ctx.AuthFilePath, nil
}
if ctx.RootForImplicitAbsolutePaths != "" {
return filepath.Join(ctx.RootForImplicitAbsolutePaths, defaultPath, strconv.Itoa(os.Getuid()), authCfg, authCfgFileName)
return filepath.Join(ctx.RootForImplicitAbsolutePaths, defaultPath, strconv.Itoa(os.Getuid()), authCfg, authCfgFileName), nil
}
}
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
if runtimeDir == "" {
runtimeDir = filepath.Join(defaultPath, strconv.Itoa(os.Getuid()))
if runtimeDir != "" {
_, err := os.Stat(runtimeDir)
if os.IsNotExist(err) {
// This means the user set the XDG_RUNTIME_DIR variable and either forgot to create the directory
// or made a typo while setting the environment variable
// so we log the error and return an empty string as the path
return "", errors.Wrapf(err, "%q directory set by $XDG_RUNTIME_DIR does not exist. Either create the directory or unset $XDG_RUNTIME_DIR.", runtimeDir)
}
runtimeDir = filepath.Join(runtimeDir, authCfg)
} else {
runtimeDir = filepath.Join(defaultPath, authCfg, strconv.Itoa(os.Getuid()))
}
return filepath.Join(runtimeDir, authCfg, authCfgFileName)
return filepath.Join(runtimeDir, authCfgFileName), nil
}
// readJSONFile unmarshals the authentications stored in the auth.json file and returns it
@ -167,10 +184,14 @@ func readJSONFile(path string, legacyFormat bool) (dockerConfigFile, error) {
// modifyJSON writes to auth.json if the dockerConfigFile has been updated
func modifyJSON(ctx *types.SystemContext, editor func(auths *dockerConfigFile) (bool, error)) error {
path := getPathToAuth(ctx)
path, err := getPathToAuth(ctx)
if err != nil {
return err
}
dir := filepath.Dir(path)
if _, err := os.Stat(dir); os.IsNotExist(err) {
if err = os.Mkdir(dir, 0700); err != nil {
if err = os.MkdirAll(dir, 0700); err != nil {
return errors.Wrapf(err, "error creating directory %q", dir)
}
}

View File

@ -1,6 +1,8 @@
package sysregistries
import (
"strings"
"github.com/BurntSushi/toml"
"github.com/containers/image/types"
"io/ioutil"
@ -29,6 +31,14 @@ type tomlConfig struct {
} `toml:"registries"`
}
// normalizeRegistries removes a trailing slash from registries, which is a
// common pitfall when configuring registries (e.g., "docker.io/library/).
func normalizeRegistries(regs *registries) {
for i := range regs.Registries {
regs.Registries[i] = strings.TrimSuffix(regs.Registries[i], "/")
}
}
// Reads the global registry file from the filesystem. Returns
// a byte array
func readRegistryConf(ctx *types.SystemContext) ([]byte, error) {
@ -58,6 +68,9 @@ func loadRegistryConf(ctx *types.SystemContext) (*tomlConfig, error) {
}
err = toml.Unmarshal(configBytes, &config)
normalizeRegistries(&config.Registries.Search)
normalizeRegistries(&config.Registries.Insecure)
normalizeRegistries(&config.Registries.Block)
return config, err
}

View File

@ -44,15 +44,13 @@ var (
type storageImageSource struct {
imageRef storageReference
ID string
image *storage.Image
layerPosition map[digest.Digest]int // Where we are in reading a blob's layers
cachedManifest []byte // A cached copy of the manifest, if already known, or nil
SignatureSizes []int `json:"signature-sizes,omitempty"` // List of sizes of each signature slice
}
type storageImageDestination struct {
image types.ImageCloser
systemContext *types.SystemContext
imageRef storageReference // The reference we'll use to name the image
publicRef storageReference // The reference we return when asked about the name we'll give to the image
directory string // Temporary directory where we store blobs until Commit() time
@ -81,7 +79,7 @@ func newImageSource(imageRef storageReference) (*storageImageSource, error) {
// Build the reader object.
image := &storageImageSource{
imageRef: imageRef,
ID: img.ID,
image: img,
layerPosition: make(map[digest.Digest]int),
SignatureSizes: []int{},
}
@ -124,7 +122,7 @@ func (s *storageImageSource) getBlobAndLayerID(info types.BlobInfo) (rc io.ReadC
layers, err := s.imageRef.transport.store.LayersByUncompressedDigest(info.Digest)
// If it's not a layer, then it must be a data item.
if len(layers) == 0 {
b, err := s.imageRef.transport.store.ImageBigData(s.ID, info.Digest.String())
b, err := s.imageRef.transport.store.ImageBigData(s.image.ID, info.Digest.String())
if err != nil {
return nil, -1, "", err
}
@ -166,7 +164,7 @@ func (s *storageImageSource) GetManifest(instanceDigest *digest.Digest) (manifes
}
if len(s.cachedManifest) == 0 {
// We stored the manifest as an item named after storage.ImageDigestBigDataKey.
cachedBlob, err := s.imageRef.transport.store.ImageBigData(s.ID, storage.ImageDigestBigDataKey)
cachedBlob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, storage.ImageDigestBigDataKey)
if err != nil {
return nil, "", err
}
@ -178,15 +176,10 @@ func (s *storageImageSource) GetManifest(instanceDigest *digest.Digest) (manifes
// LayerInfosForCopy() returns the list of layer blobs that make up the root filesystem of
// the image, after they've been decompressed.
func (s *storageImageSource) LayerInfosForCopy() ([]types.BlobInfo, error) {
simg, err := s.imageRef.transport.store.Image(s.ID)
if err != nil {
return nil, errors.Wrapf(err, "error reading image %q", s.ID)
}
updatedBlobInfos := []types.BlobInfo{}
layerID := simg.TopLayer
_, manifestType, err := s.GetManifest(nil)
if err != nil {
return nil, errors.Wrapf(err, "error reading image manifest for %q", s.ID)
return nil, errors.Wrapf(err, "error reading image manifest for %q", s.image.ID)
}
uncompressedLayerType := ""
switch manifestType {
@ -196,10 +189,11 @@ func (s *storageImageSource) LayerInfosForCopy() ([]types.BlobInfo, error) {
// This is actually a compressed type, but there's no uncompressed type defined
uncompressedLayerType = manifest.DockerV2Schema2LayerMediaType
}
layerID := s.image.TopLayer
for layerID != "" {
layer, err := s.imageRef.transport.store.Layer(layerID)
if err != nil {
return nil, errors.Wrapf(err, "error reading layer %q in image %q", layerID, s.ID)
return nil, errors.Wrapf(err, "error reading layer %q in image %q", layerID, s.image.ID)
}
if layer.UncompressedDigest == "" {
return nil, errors.Errorf("uncompressed digest for layer %q is unknown", layerID)
@ -227,9 +221,9 @@ func (s *storageImageSource) GetSignatures(ctx context.Context, instanceDigest *
sigslice := [][]byte{}
signature := []byte{}
if len(s.SignatureSizes) > 0 {
signatureBlob, err := s.imageRef.transport.store.ImageBigData(s.ID, "signatures")
signatureBlob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, "signatures")
if err != nil {
return nil, errors.Wrapf(err, "error looking up signatures data for image %q", s.ID)
return nil, errors.Wrapf(err, "error looking up signatures data for image %q", s.image.ID)
}
signature = signatureBlob
}
@ -257,7 +251,6 @@ func newImageDestination(ctx *types.SystemContext, imageRef storageReference) (*
publicRef := imageRef
publicRef.name = nil
image := &storageImageDestination{
systemContext: ctx,
imageRef: imageRef,
publicRef: publicRef,
directory: directory,
@ -412,17 +405,11 @@ func (s *storageImageDestination) computeID(m manifest.Manifest) string {
// fill in the DiffIDs. It's expected (but not enforced by us) that the number of
// diffIDs corresponds to the number of non-EmptyLayer entries in the history.
var diffIDs []digest.Digest
switch m.(type) {
switch m := m.(type) {
case *manifest.Schema1:
// Build a list of the diffIDs we've generated for the non-throwaway FS layers,
// in reverse of the order in which they were originally listed.
s1, ok := m.(*manifest.Schema1)
if !ok {
// Shouldn't happen
logrus.Debugf("internal error reading schema 1 manifest")
return ""
}
for i, history := range s1.History {
for i, history := range m.History {
compat := manifest.Schema1V1Compatibility{}
if err := json.Unmarshal([]byte(history.V1Compatibility), &compat); err != nil {
logrus.Debugf("internal error reading schema 1 history: %v", err)
@ -431,7 +418,7 @@ func (s *storageImageDestination) computeID(m manifest.Manifest) string {
if compat.ThrowAway {
continue
}
blobSum := s1.FSLayers[i].BlobSum
blobSum := m.FSLayers[i].BlobSum
diffID, ok := s.blobDiffIDs[blobSum]
if !ok {
logrus.Infof("error looking up diffID for layer %q", blobSum.String())
@ -442,6 +429,8 @@ func (s *storageImageDestination) computeID(m manifest.Manifest) string {
case *manifest.Schema2, *manifest.OCI1:
// We know the ID calculation for these formats doesn't actually use the diffIDs,
// so we don't need to populate the diffID list.
default:
return ""
}
id, err := m.ImageID(diffIDs)
if err != nil {
@ -566,9 +555,9 @@ func (s *storageImageDestination) Commit() error {
// 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.
options := &storage.ImageOptions{}
if inspect, err := man.Inspect(s.getConfigBlob); err == nil {
if inspect, err := man.Inspect(s.getConfigBlob); err == nil && inspect.Created != nil {
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
@ -735,14 +724,14 @@ func (s *storageImageDestination) PutSignatures(signatures [][]byte) error {
func (s *storageImageSource) getSize() (int64, error) {
var sum int64
// Size up the data blobs.
dataNames, err := s.imageRef.transport.store.ListImageBigData(s.ID)
dataNames, err := s.imageRef.transport.store.ListImageBigData(s.image.ID)
if err != nil {
return -1, errors.Wrapf(err, "error reading image %q", s.ID)
return -1, errors.Wrapf(err, "error reading image %q", s.image.ID)
}
for _, dataName := range dataNames {
bigSize, err := s.imageRef.transport.store.ImageBigDataSize(s.ID, dataName)
bigSize, err := s.imageRef.transport.store.ImageBigDataSize(s.image.ID, dataName)
if err != nil {
return -1, errors.Wrapf(err, "error reading data blob size %q for %q", dataName, s.ID)
return -1, errors.Wrapf(err, "error reading data blob size %q for %q", dataName, s.image.ID)
}
sum += bigSize
}
@ -750,13 +739,8 @@ func (s *storageImageSource) getSize() (int64, error) {
for _, sigSize := range s.SignatureSizes {
sum += int64(sigSize)
}
// Prepare to walk the layer list.
img, err := s.imageRef.transport.store.Image(s.ID)
if err != nil {
return -1, errors.Wrapf(err, "error reading image info %q", s.ID)
}
// Walk the layer list.
layerID := img.TopLayer
layerID := s.image.TopLayer
for layerID != "" {
layer, err := s.imageRef.transport.store.Layer(layerID)
if err != nil {

View File

@ -215,10 +215,6 @@ type UnparsedImage interface {
Manifest() ([]byte, string, error)
// Signatures is like ImageSource.GetSignatures, but the result is cached; it is OK to call this however often you need.
Signatures(ctx context.Context) ([][]byte, error)
// LayerInfosForCopy returns either nil (meaning the values in the manifest are fine), or updated values for the layer blobsums that are listed in the image's manifest.
// The Digest field is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
// WARNING: The list may contain duplicates, and they are semantically relevant.
LayerInfosForCopy() ([]BlobInfo, error)
}
// Image is the primary API for inspecting properties of images.
@ -242,6 +238,10 @@ type Image interface {
// The Digest field is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
// WARNING: The list may contain duplicates, and they are semantically relevant.
LayerInfos() []BlobInfo
// LayerInfosForCopy returns either nil (meaning the values in the manifest are fine), or updated values for the layer blobsums that are listed in the image's manifest.
// The Digest field is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
// WARNING: The list may contain duplicates, and they are semantically relevant.
LayerInfosForCopy() ([]BlobInfo, error)
// EmbeddedDockerReferenceConflicts whether a Docker reference embedded in the manifest, if any, conflicts with destination ref.
// It returns false if the manifest does not embed a Docker reference.
// (This embedding unfortunately happens for Docker schema1, please do not add support for this in any new formats.)
@ -292,7 +292,7 @@ type ManifestUpdateInformation struct {
// for other manifest types.
type ImageInspectInfo struct {
Tag string
Created time.Time
Created *time.Time
DockerVersion string
Labels map[string]string
Architecture string