138 lines
3.5 KiB
Go
138 lines
3.5 KiB
Go
![]() |
package metadata
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
|
||
|
"github.com/docker/distribution/digest"
|
||
|
"github.com/docker/docker/layer"
|
||
|
)
|
||
|
|
||
|
// V2MetadataService maps layer IDs to a set of known metadata for
|
||
|
// the layer.
|
||
|
type V2MetadataService struct {
|
||
|
store Store
|
||
|
}
|
||
|
|
||
|
// V2Metadata contains the digest and source repository information for a layer.
|
||
|
type V2Metadata struct {
|
||
|
Digest digest.Digest
|
||
|
SourceRepository string
|
||
|
}
|
||
|
|
||
|
// maxMetadata is the number of metadata entries to keep per layer DiffID.
|
||
|
const maxMetadata = 50
|
||
|
|
||
|
// NewV2MetadataService creates a new diff ID to v2 metadata mapping service.
|
||
|
func NewV2MetadataService(store Store) *V2MetadataService {
|
||
|
return &V2MetadataService{
|
||
|
store: store,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (serv *V2MetadataService) diffIDNamespace() string {
|
||
|
return "v2metadata-by-diffid"
|
||
|
}
|
||
|
|
||
|
func (serv *V2MetadataService) digestNamespace() string {
|
||
|
return "diffid-by-digest"
|
||
|
}
|
||
|
|
||
|
func (serv *V2MetadataService) diffIDKey(diffID layer.DiffID) string {
|
||
|
return string(digest.Digest(diffID).Algorithm()) + "/" + digest.Digest(diffID).Hex()
|
||
|
}
|
||
|
|
||
|
func (serv *V2MetadataService) digestKey(dgst digest.Digest) string {
|
||
|
return string(dgst.Algorithm()) + "/" + dgst.Hex()
|
||
|
}
|
||
|
|
||
|
// GetMetadata finds the metadata associated with a layer DiffID.
|
||
|
func (serv *V2MetadataService) GetMetadata(diffID layer.DiffID) ([]V2Metadata, error) {
|
||
|
jsonBytes, err := serv.store.Get(serv.diffIDNamespace(), serv.diffIDKey(diffID))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var metadata []V2Metadata
|
||
|
if err := json.Unmarshal(jsonBytes, &metadata); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return metadata, nil
|
||
|
}
|
||
|
|
||
|
// GetDiffID finds a layer DiffID from a digest.
|
||
|
func (serv *V2MetadataService) GetDiffID(dgst digest.Digest) (layer.DiffID, error) {
|
||
|
diffIDBytes, err := serv.store.Get(serv.digestNamespace(), serv.digestKey(dgst))
|
||
|
if err != nil {
|
||
|
return layer.DiffID(""), err
|
||
|
}
|
||
|
|
||
|
return layer.DiffID(diffIDBytes), nil
|
||
|
}
|
||
|
|
||
|
// Add associates metadata with a layer DiffID. If too many metadata entries are
|
||
|
// present, the oldest one is dropped.
|
||
|
func (serv *V2MetadataService) Add(diffID layer.DiffID, metadata V2Metadata) error {
|
||
|
oldMetadata, err := serv.GetMetadata(diffID)
|
||
|
if err != nil {
|
||
|
oldMetadata = nil
|
||
|
}
|
||
|
newMetadata := make([]V2Metadata, 0, len(oldMetadata)+1)
|
||
|
|
||
|
// Copy all other metadata to new slice
|
||
|
for _, oldMeta := range oldMetadata {
|
||
|
if oldMeta != metadata {
|
||
|
newMetadata = append(newMetadata, oldMeta)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
newMetadata = append(newMetadata, metadata)
|
||
|
|
||
|
if len(newMetadata) > maxMetadata {
|
||
|
newMetadata = newMetadata[len(newMetadata)-maxMetadata:]
|
||
|
}
|
||
|
|
||
|
jsonBytes, err := json.Marshal(newMetadata)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = serv.store.Set(serv.diffIDNamespace(), serv.diffIDKey(diffID), jsonBytes)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return serv.store.Set(serv.digestNamespace(), serv.digestKey(metadata.Digest), []byte(diffID))
|
||
|
}
|
||
|
|
||
|
// Remove unassociates a metadata entry from a layer DiffID.
|
||
|
func (serv *V2MetadataService) Remove(metadata V2Metadata) error {
|
||
|
diffID, err := serv.GetDiffID(metadata.Digest)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
oldMetadata, err := serv.GetMetadata(diffID)
|
||
|
if err != nil {
|
||
|
oldMetadata = nil
|
||
|
}
|
||
|
newMetadata := make([]V2Metadata, 0, len(oldMetadata))
|
||
|
|
||
|
// Copy all other metadata to new slice
|
||
|
for _, oldMeta := range oldMetadata {
|
||
|
if oldMeta != metadata {
|
||
|
newMetadata = append(newMetadata, oldMeta)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if len(newMetadata) == 0 {
|
||
|
return serv.store.Delete(serv.diffIDNamespace(), serv.diffIDKey(diffID))
|
||
|
}
|
||
|
|
||
|
jsonBytes, err := json.Marshal(newMetadata)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return serv.store.Set(serv.diffIDNamespace(), serv.diffIDKey(diffID), jsonBytes)
|
||
|
}
|