manifest: save raw manifest content on download

This prevents us needing to attempt to reconstruct the exact indentation
registry side, which is not canonical - so may differ.

Signed-off-by: Justin Chadwell <me@jedevc.com>
This commit is contained in:
Justin Chadwell 2023-01-27 10:48:54 +00:00
parent 285e137aa4
commit 67b9617898
4 changed files with 29 additions and 9 deletions

View File

@ -219,7 +219,7 @@ func buildPutManifestRequest(imageManifest types.ImageManifest, targetRef refere
} }
// Attempt to reconstruct indentation of the manifest to ensure sha parity // Attempt to reconstruct indentation of the manifest to ensure sha parity
// with the registry. // with the registry - if we haven't preserved the raw content.
// //
// This is necessary because our previous internal storage format did not // This is necessary because our previous internal storage format did not
// preserve whitespace. If we don't have the newer format present, we can // preserve whitespace. If we don't have the newer format present, we can
@ -227,9 +227,12 @@ func buildPutManifestRequest(imageManifest types.ImageManifest, targetRef refere
// reconstruction failed! // reconstruction failed!
switch { switch {
case imageManifest.SchemaV2Manifest != nil: case imageManifest.SchemaV2Manifest != nil:
dt, err := json.MarshalIndent(imageManifest.SchemaV2Manifest, "", " ") dt := imageManifest.Raw
if err != nil { if len(dt) == 0 {
return mountRequest{}, err dt, err = json.MarshalIndent(imageManifest.SchemaV2Manifest, "", " ")
if err != nil {
return mountRequest{}, err
}
} }
dig := imageManifest.Descriptor.Digest dig := imageManifest.Descriptor.Digest
@ -243,9 +246,12 @@ func buildPutManifestRequest(imageManifest types.ImageManifest, targetRef refere
} }
imageManifest.SchemaV2Manifest = &manifest imageManifest.SchemaV2Manifest = &manifest
case imageManifest.OCIManifest != nil: case imageManifest.OCIManifest != nil:
dt, err := json.MarshalIndent(imageManifest.OCIManifest, "", " ") dt := imageManifest.Raw
if err != nil { if len(dt) == 0 {
return mountRequest{}, err dt, err = json.MarshalIndent(imageManifest.OCIManifest, "", " ")
if err != nil {
return mountRequest{}, err
}
} }
dig := imageManifest.Descriptor.Digest dig := imageManifest.Descriptor.Digest

View File

@ -14,6 +14,7 @@
"variant": "v7" "variant": "v7"
} }
}, },
"Raw": "ewogICAic2NoZW1hVmVyc2lvbiI6IDIsCiAgICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRvY2tlci5kaXN0cmlidXRpb24ubWFuaWZlc3QudjIranNvbiIsCiAgICJjb25maWciOiB7CiAgICAgICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRvY2tlci5jb250YWluZXIuaW1hZ2UudjEranNvbiIsCiAgICAgICJzaXplIjogMTUyMCwKICAgICAgImRpZ2VzdCI6ICJzaGEyNTY6NzMyOGY2ZjhiNDE4OTA1OTc1NzVjYmFhZGM4ODRlNzM4NmFlMGFjYzUzYjc0NzQwMWViY2U1Y2YwZDYyNDU2MCIKICAgfSwKICAgImxheWVycyI6IFsKICAgICAgewogICAgICAgICAibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuaW1hZ2Uucm9vdGZzLmRpZmYudGFyLmd6aXAiLAogICAgICAgICAic2l6ZSI6IDE5OTA0MDIsCiAgICAgICAgICJkaWdlc3QiOiAic2hhMjU2Ojg4Mjg2ZjQxNTMwZTkzZGZmZDRiOTY0ZTFkYjIyY2U0OTM5ZmZmYTRhNGM2NjVkYWI4NTkxZmJhYjAzZDQ5MjYiCiAgICAgIH0KICAgXQp9",
"SchemaV2Manifest": { "SchemaV2Manifest": {
"schemaVersion": 2, "schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json", "mediaType": "application/vnd.docker.distribution.manifest.v2+json",

View File

@ -76,6 +76,8 @@ func getManifest(ctx context.Context, dockerCli command.Cli, listRef, namedRef r
return dockerCli.RegistryClient(insecure).GetManifest(ctx, namedRef) return dockerCli.RegistryClient(insecure).GetManifest(ctx, namedRef)
case err != nil: case err != nil:
return types.ImageManifest{}, err return types.ImageManifest{}, err
case len(data.Raw) == 0:
return dockerCli.RegistryClient(insecure).GetManifest(ctx, namedRef)
default: default:
return data, nil return data, nil
} }

View File

@ -17,8 +17,7 @@ import (
type ImageManifest struct { type ImageManifest struct {
Ref *SerializableNamed Ref *SerializableNamed
Descriptor ocispec.Descriptor Descriptor ocispec.Descriptor
Raw []byte `json:",omitempty"`
// TODO: Deprecate this and store manifest blobs
// SchemaV2Manifest is used for inspection // SchemaV2Manifest is used for inspection
SchemaV2Manifest *schema2.DeserializedManifest `json:",omitempty"` SchemaV2Manifest *schema2.DeserializedManifest `json:",omitempty"`
@ -99,9 +98,15 @@ func (i ImageManifest) References() []distribution.Descriptor {
// NewImageManifest returns a new ImageManifest object. The values for Platform // NewImageManifest returns a new ImageManifest object. The values for Platform
// are initialized from those in the image // are initialized from those in the image
func NewImageManifest(ref reference.Named, desc ocispec.Descriptor, manifest *schema2.DeserializedManifest) ImageManifest { func NewImageManifest(ref reference.Named, desc ocispec.Descriptor, manifest *schema2.DeserializedManifest) ImageManifest {
raw, err := manifest.MarshalJSON()
if err != nil {
raw = nil
}
return ImageManifest{ return ImageManifest{
Ref: &SerializableNamed{Named: ref}, Ref: &SerializableNamed{Named: ref},
Descriptor: desc, Descriptor: desc,
Raw: raw,
SchemaV2Manifest: manifest, SchemaV2Manifest: manifest,
} }
} }
@ -109,9 +114,15 @@ func NewImageManifest(ref reference.Named, desc ocispec.Descriptor, manifest *sc
// NewOCIImageManifest returns a new ImageManifest object. The values for // NewOCIImageManifest returns a new ImageManifest object. The values for
// Platform are initialized from those in the image // Platform are initialized from those in the image
func NewOCIImageManifest(ref reference.Named, desc ocispec.Descriptor, manifest *ocischema.DeserializedManifest) ImageManifest { func NewOCIImageManifest(ref reference.Named, desc ocispec.Descriptor, manifest *ocischema.DeserializedManifest) ImageManifest {
raw, err := manifest.MarshalJSON()
if err != nil {
raw = nil
}
return ImageManifest{ return ImageManifest{
Ref: &SerializableNamed{Named: ref}, Ref: &SerializableNamed{Named: ref},
Descriptor: desc, Descriptor: desc,
Raw: raw,
OCIManifest: manifest, OCIManifest: manifest,
} }
} }