Update logic to determine if layer is empty
Handle reliance on the size field when the throwaway field is not used. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
parent
9f90d8a9b4
commit
3a226ef17d
@ -35,6 +35,7 @@ type Converter struct {
|
|||||||
fetcher remotes.Fetcher
|
fetcher remotes.Fetcher
|
||||||
|
|
||||||
pulledManifest *manifest
|
pulledManifest *manifest
|
||||||
|
layers []ocispec.Descriptor
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
blobMap map[digest.Digest]digest.Digest
|
blobMap map[digest.Digest]digest.Digest
|
||||||
@ -66,21 +67,17 @@ func (c *Converter) Handle(ctx context.Context, desc ocispec.Descriptor) ([]ocis
|
|||||||
if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), &h); err != nil {
|
if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), &h); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !h.ThrowAway {
|
if !h.EmptyLayer() {
|
||||||
descs = append(descs, ocispec.Descriptor{
|
descs = append([]ocispec.Descriptor{
|
||||||
|
{
|
||||||
MediaType: images.MediaTypeDockerSchema2LayerGzip,
|
MediaType: images.MediaTypeDockerSchema2LayerGzip,
|
||||||
Digest: c.pulledManifest.FSLayers[i].BlobSum,
|
Digest: c.pulledManifest.FSLayers[i].BlobSum,
|
||||||
})
|
},
|
||||||
|
}, descs...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Reverse
|
c.layers = descs
|
||||||
for i := 0; i <= len(descs)/2; i++ {
|
return c.layers, nil
|
||||||
j := len(descs) - i - 1
|
|
||||||
if i != j {
|
|
||||||
descs[i], descs[j] = descs[j], descs[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return descs, nil
|
|
||||||
case images.MediaTypeDockerSchema2LayerGzip:
|
case images.MediaTypeDockerSchema2LayerGzip:
|
||||||
if c.pulledManifest == nil {
|
if c.pulledManifest == nil {
|
||||||
return nil, errors.New("manifest required for schema 1 blob pull")
|
return nil, errors.New("manifest required for schema 1 blob pull")
|
||||||
@ -95,11 +92,45 @@ func (c *Converter) Convert(ctx context.Context) (ocispec.Descriptor, error) {
|
|||||||
if c.pulledManifest == nil {
|
if c.pulledManifest == nil {
|
||||||
return ocispec.Descriptor{}, errors.New("missing schema 1 manifest for conversion")
|
return ocispec.Descriptor{}, errors.New("missing schema 1 manifest for conversion")
|
||||||
}
|
}
|
||||||
|
if len(c.pulledManifest.History) == 0 {
|
||||||
|
return ocispec.Descriptor{}, errors.New("no history")
|
||||||
|
}
|
||||||
|
if len(c.layers) == 0 {
|
||||||
|
return ocispec.Descriptor{}, errors.New("schema 1 manifest has no usable layers")
|
||||||
|
}
|
||||||
|
|
||||||
img, err := convertSchema1Manifest(c.pulledManifest, c.blobMap)
|
var img ocispec.Image
|
||||||
|
if err := json.Unmarshal([]byte(c.pulledManifest.History[0].V1Compatibility), &img); err != nil {
|
||||||
|
return ocispec.Descriptor{}, errors.Wrap(err, "failed to unmarshal image from schema 1 history")
|
||||||
|
}
|
||||||
|
|
||||||
|
history, err := schema1ManifestHistory(c.pulledManifest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ocispec.Descriptor{}, errors.Wrap(err, "schema 1 conversion failed")
|
return ocispec.Descriptor{}, errors.Wrap(err, "schema 1 conversion failed")
|
||||||
}
|
}
|
||||||
|
img.History = history
|
||||||
|
|
||||||
|
diffIDs := make([]digest.Digest, len(c.layers))
|
||||||
|
for i, layer := range c.layers {
|
||||||
|
info, err := c.contentStore.Info(ctx, layer.Digest)
|
||||||
|
if err != nil {
|
||||||
|
return ocispec.Descriptor{}, errors.Wrap(err, "failed to get blob info")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in size since not given by schema 1 manifest
|
||||||
|
c.layers[i].Size = info.Size
|
||||||
|
|
||||||
|
diffID, ok := c.blobMap[layer.Digest]
|
||||||
|
if !ok {
|
||||||
|
return ocispec.Descriptor{}, errors.New("missing diff id")
|
||||||
|
}
|
||||||
|
diffIDs[i] = diffID
|
||||||
|
}
|
||||||
|
img.RootFS = ocispec.RootFS{
|
||||||
|
Type: "layers",
|
||||||
|
DiffIDs: diffIDs,
|
||||||
|
}
|
||||||
|
|
||||||
b, err := json.Marshal(img)
|
b, err := json.Marshal(img)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal image")
|
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal image")
|
||||||
@ -116,30 +147,12 @@ func (c *Converter) Convert(ctx context.Context) (ocispec.Descriptor, error) {
|
|||||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
|
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
|
||||||
}
|
}
|
||||||
|
|
||||||
layers := make([]ocispec.Descriptor, 0)
|
|
||||||
for _, layer := range c.pulledManifest.FSLayers {
|
|
||||||
// TODO: Use rootfs mapping!
|
|
||||||
info, err := c.contentStore.Info(ctx, layer.BlobSum)
|
|
||||||
if err != nil {
|
|
||||||
if content.IsNotFound(err) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to get blob info")
|
|
||||||
}
|
|
||||||
|
|
||||||
layers = append([]ocispec.Descriptor{{
|
|
||||||
MediaType: ocispec.MediaTypeImageLayerGzip,
|
|
||||||
Digest: layer.BlobSum,
|
|
||||||
Size: info.Size,
|
|
||||||
}}, layers...)
|
|
||||||
}
|
|
||||||
|
|
||||||
manifest := ocispec.Manifest{
|
manifest := ocispec.Manifest{
|
||||||
Versioned: specs.Versioned{
|
Versioned: specs.Versioned{
|
||||||
SchemaVersion: 2,
|
SchemaVersion: 2,
|
||||||
},
|
},
|
||||||
Config: config,
|
Config: config,
|
||||||
Layers: layers,
|
Layers: c.layers,
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err = json.Marshal(manifest)
|
b, err = json.Marshal(manifest)
|
||||||
@ -272,62 +285,44 @@ type v1History struct {
|
|||||||
Author string `json:"author,omitempty"`
|
Author string `json:"author,omitempty"`
|
||||||
Created time.Time `json:"created"`
|
Created time.Time `json:"created"`
|
||||||
Comment string `json:"comment,omitempty"`
|
Comment string `json:"comment,omitempty"`
|
||||||
ThrowAway bool `json:"throwaway,omitempty"`
|
ThrowAway *bool `json:"throwaway,omitempty"`
|
||||||
|
Size *int `json:"Size,omitempty"` // used before ThrowAway field
|
||||||
ContainerConfig struct {
|
ContainerConfig struct {
|
||||||
Cmd []string `json:"Cmd,omitempty"`
|
Cmd []string `json:"Cmd,omitempty"`
|
||||||
} `json:"container_config,omitempty"`
|
} `json:"container_config,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertSchema1Manifest(m *manifest, blobs map[digest.Digest]digest.Digest) (*ocispec.Image, error) {
|
func (h *v1History) EmptyLayer() bool {
|
||||||
if len(m.History) == 0 {
|
if h.ThrowAway != nil {
|
||||||
return nil, errors.New("no history")
|
return !(*h.ThrowAway)
|
||||||
|
}
|
||||||
|
if h.Size != nil {
|
||||||
|
return *h.Size == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var img ocispec.Image
|
// If no size is given or `ThrowAway` specified, the image is empty
|
||||||
if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), &img); err != nil {
|
return true
|
||||||
return nil, errors.Wrap(err, "failed to unmarshal image from schema 1 history")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
diffIDs := make([]digest.Digest, 0, len(m.History))
|
func schema1ManifestHistory(m *manifest) ([]ocispec.History, error) {
|
||||||
img.History = make([]ocispec.History, len(m.History))
|
history := make([]ocispec.History, len(m.History))
|
||||||
for i := range m.History {
|
for i := range m.History {
|
||||||
var h v1History
|
var h v1History
|
||||||
if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), &h); err != nil {
|
if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), &h); err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to unmarshal history")
|
return nil, errors.Wrap(err, "failed to unmarshal history")
|
||||||
}
|
}
|
||||||
|
|
||||||
img.History[len(img.History)-i-1] = ocispec.History{
|
empty := h.EmptyLayer()
|
||||||
|
history[len(history)-i-1] = ocispec.History{
|
||||||
Author: h.Author,
|
Author: h.Author,
|
||||||
Comment: h.Comment,
|
Comment: h.Comment,
|
||||||
Created: &h.Created,
|
Created: &h.Created,
|
||||||
CreatedBy: strings.Join(h.ContainerConfig.Cmd, " "),
|
CreatedBy: strings.Join(h.ContainerConfig.Cmd, " "),
|
||||||
EmptyLayer: h.ThrowAway,
|
EmptyLayer: empty,
|
||||||
}
|
|
||||||
|
|
||||||
if !h.ThrowAway {
|
|
||||||
diffID, ok := blobs[m.FSLayers[i].BlobSum]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.Errorf("no diff id for blob %s", m.FSLayers[i].BlobSum.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
diffIDs = append(diffIDs, diffID)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i <= len(diffIDs)/2; i++ {
|
|
||||||
j := len(diffIDs) - i - 1
|
|
||||||
if i != j {
|
|
||||||
diffIDs[i], diffIDs[j] = diffIDs[j], diffIDs[i]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img.RootFS = ocispec.RootFS{
|
return history, nil
|
||||||
Type: "layers",
|
|
||||||
DiffIDs: diffIDs,
|
|
||||||
}
|
|
||||||
|
|
||||||
return &img, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type signature struct {
|
type signature struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user