Merge pull request #634 from tonistiigi/schema1-config-fix
imageutil: fix getting schema1 configsdocker-18.09
commit
9890dda814
|
@ -251,6 +251,13 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
|
|||
_ = ref
|
||||
if len(img.RootFS.DiffIDs) == 0 {
|
||||
isScratch = true
|
||||
// schema1 images can't return diffIDs so double check :(
|
||||
for _, h := range img.History {
|
||||
if !h.EmptyLayer {
|
||||
isScratch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type IngesterProvider interface {
|
||||
type ContentCache interface {
|
||||
content.Ingester
|
||||
content.Provider
|
||||
}
|
||||
|
||||
func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester IngesterProvider, p *specs.Platform) (digest.Digest, []byte, error) {
|
||||
func Config(ctx context.Context, str string, resolver remotes.Resolver, cache ContentCache, p *specs.Platform) (digest.Digest, []byte, error) {
|
||||
// TODO: fix buildkit to take interface instead of struct
|
||||
var platform platforms.MatchComparer
|
||||
if p != nil {
|
||||
|
@ -36,7 +36,7 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester
|
|||
Digest: ref.Digest(),
|
||||
}
|
||||
if desc.Digest != "" {
|
||||
ra, err := ingester.ReaderAt(ctx, desc)
|
||||
ra, err := cache.ReaderAt(ctx, desc)
|
||||
if err == nil {
|
||||
desc.Size = ra.Size()
|
||||
mt, err := DetectManifestMediaType(ra)
|
||||
|
@ -58,19 +58,23 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester
|
|||
return "", nil, err
|
||||
}
|
||||
|
||||
if desc.MediaType == images.MediaTypeDockerSchema1Manifest {
|
||||
return readSchema1Config(ctx, ref.String(), desc, fetcher, cache)
|
||||
}
|
||||
|
||||
handlers := []images.Handler{
|
||||
remotes.FetchHandler(ingester, fetcher),
|
||||
childrenConfigHandler(ingester, platform),
|
||||
remotes.FetchHandler(cache, fetcher),
|
||||
childrenConfigHandler(cache, platform),
|
||||
}
|
||||
if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
config, err := images.Config(ctx, ingester, desc, platform)
|
||||
config, err := images.Config(ctx, cache, desc, platform)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
dt, err := content.ReadBlob(ctx, ingester, config)
|
||||
dt, err := content.ReadBlob(ctx, cache, config)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
package imageutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/remotes"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func readSchema1Config(ctx context.Context, ref string, desc specs.Descriptor, fetcher remotes.Fetcher, cache ContentCache) (digest.Digest, []byte, error) {
|
||||
rc, err := fetcher.Fetch(ctx, desc)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer rc.Close()
|
||||
dt, err := ioutil.ReadAll(rc)
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "failed to fetch schema1 manifest")
|
||||
}
|
||||
dt, err = convertSchema1ConfigMeta(dt)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return desc.Digest, dt, nil
|
||||
}
|
||||
|
||||
func convertSchema1ConfigMeta(in []byte) ([]byte, error) {
|
||||
type history struct {
|
||||
V1Compatibility string `json:"v1Compatibility"`
|
||||
}
|
||||
var m struct {
|
||||
History []history `json:"history"`
|
||||
}
|
||||
if err := json.Unmarshal(in, &m); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal schema1 manifest")
|
||||
}
|
||||
if len(m.History) == 0 {
|
||||
return nil, errors.Errorf("invalid schema1 manifest")
|
||||
}
|
||||
|
||||
var img specs.Image
|
||||
if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), &img); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal image from schema 1 history")
|
||||
}
|
||||
|
||||
img.RootFS = specs.RootFS{
|
||||
Type: "layers", // filled in by exporter
|
||||
}
|
||||
img.History = make([]specs.History, len(m.History))
|
||||
|
||||
for i := range m.History {
|
||||
var h v1History
|
||||
if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), &h); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal history")
|
||||
}
|
||||
img.History[len(m.History)-i-1] = specs.History{
|
||||
Author: h.Author,
|
||||
Comment: h.Comment,
|
||||
Created: &h.Created,
|
||||
CreatedBy: strings.Join(h.ContainerConfig.Cmd, " "),
|
||||
EmptyLayer: (h.ThrowAway != nil && *h.ThrowAway) || (h.Size != nil && *h.Size == 0),
|
||||
}
|
||||
}
|
||||
|
||||
dt, err := json.MarshalIndent(img, "", " ")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshal schema1 config")
|
||||
}
|
||||
return dt, nil
|
||||
}
|
||||
|
||||
type v1History struct {
|
||||
Author string `json:"author,omitempty"`
|
||||
Created time.Time `json:"created"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
ThrowAway *bool `json:"throwaway,omitempty"`
|
||||
Size *int `json:"Size,omitempty"` // used before ThrowAway field
|
||||
ContainerConfig struct {
|
||||
Cmd []string `json:"Cmd,omitempty"`
|
||||
} `json:"container_config,omitempty"`
|
||||
}
|
Loading…
Reference in New Issue