Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Unmarshal Docker image labels separately #2785

Merged
merged 1 commit into from
Jan 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func (e *LabelTimestampFormatError) Error() string {
return fmt.Sprintf(
"failed to parse %d timestamp label(s) as RFC3339 (%s); ask the repository administrator to correct this as it conflicts with the spec",
len(e.Labels),
strings.Join(e.Labels, ","))
strings.Join(e.Labels, ", "))
}

// Labels has all the image labels we are interested in for an image
Expand Down
35 changes: 29 additions & 6 deletions pkg/registry/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,53 +128,76 @@ interpret:
switch deserialised := manifest.(type) {
case *schema1.SignedManifest:
var man schema1.Manifest = deserialised.Manifest
// for decoding the v1-compatibility entry in schema1 manifests
// For decoding the v1-compatibility entry in schema1 manifests
// Ref: https://docs.docker.com/registry/spec/manifest-v2-1/
// Ref (spec): https://github.com/moby/moby/blob/master/image/spec/v1.md#image-json-field-descriptions
var v1 struct {
ID string `json:"id"`
Created time.Time `json:"created"`
OS string `json:"os"`
Arch string `json:"architecture"`
}
if err = json.Unmarshal([]byte(man.History[0].V1Compatibility), &v1); err != nil {
return ImageEntry{}, err
}

var config struct {
hiddeco marked this conversation as resolved.
Show resolved Hide resolved
Config struct {
Labels image.Labels `json:"labels"`
} `json:"config"`
}

if err = json.Unmarshal([]byte(man.History[0].V1Compatibility), &v1); err != nil {
// We need to unmarshal the labels separately as the validation error
// that may be returned stops the unmarshalling which would result
// in no data at all for the image.
if err = json.Unmarshal([]byte(man.History[0].V1Compatibility), &config); err != nil {
if _, ok := err.(*image.LabelTimestampFormatError); !ok {
return ImageEntry{}, err
}
labelErr = err
}

// This is not the ImageID that Docker uses, but assumed to
// identify the image as it's the topmost layer.
info.ImageID = v1.ID
info.CreatedAt = v1.Created
info.Labels = v1.Config.Labels
info.Labels = config.Config.Labels
case *schema2.DeserializedManifest:
var man schema2.Manifest = deserialised.Manifest
configBytes, err := repository.Blobs(ctx).Get(ctx, man.Config.Digest)
if err != nil {
return ImageEntry{}, err
}

// Ref: https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md
var config struct {
Arch string `json:"architecture"`
Created time.Time `json:"created"`
OS string `json:"os"`
}
if err = json.Unmarshal(configBytes, &config); err != nil {
return ImageEntry{}, nil
}

// Ref: https://github.com/moby/moby/blob/39e6def2194045cb206160b66bf309f486bd7e64/image/image.go#L47
var container struct {
ContainerConfig struct {
Labels image.Labels `json:"labels"`
} `json:"container_config"`
}
if err = json.Unmarshal(configBytes, &config); err != nil {
// We need to unmarshal the labels separately as the validation error
// that may be returned stops the unmarshalling which would result
// in no data at all for the image.
if err = json.Unmarshal(configBytes, &container); err != nil {
if _, ok := err.(*image.LabelTimestampFormatError); !ok {
return ImageEntry{}, err
}
labelErr = err
}

// This _is_ what Docker uses as its Image ID.
info.ImageID = man.Config.Digest.String()
info.CreatedAt = config.Created
info.Labels = config.ContainerConfig.Labels
info.Labels = container.ContainerConfig.Labels
case *manifestlist.DeserializedManifestList:
var list manifestlist.ManifestList = deserialised.ManifestList
// TODO(michael): is it valid to just pick the first one that matches?
Expand Down