lib/dockerregistry/manifests.go (117 lines of code) (raw):
// Copyright (c) 2016-2019 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package dockerregistry
import (
"fmt"
"strings"
"time"
storagedriver "github.com/docker/distribution/registry/storage/driver"
"github.com/uber/kraken/core"
"github.com/uber/kraken/lib/dockerregistry/transfer"
"github.com/uber/kraken/utils/log"
)
const (
pullTimer = "dockertag.time.pull"
createSuccessCounter = "dockertag.success.create"
createFailureCounter = "dockertag.failure.create"
getSuccessCounter = "dockertag.success.get"
getFailureCounter = "dockertag.failure.get"
)
type manifests struct {
transferer transfer.ImageTransferer
}
func newManifests(transferer transfer.ImageTransferer) *manifests {
return &manifests{transferer}
}
// getDigest downloads and returns manifest digest.
// This is the only place storage driver would download a manifest blob via
// torrent scheduler or origin because it has namespace information.
// The caller of storage driver would first call this function to resolve
// the manifest link (and downloads manifest blob),
// then call Stat or Reader which would assume the blob is on disk already.
func (t *manifests) getDigest(path string, subtype PathSubType) ([]byte, error) {
repo, err := GetRepo(path)
if err != nil {
return nil, fmt.Errorf("get repo: %s", err)
}
var digest core.Digest
switch subtype {
case _tags:
tag, _, err := GetManifestTag(path)
if err != nil {
return nil, fmt.Errorf("get manifest tag: %s", err)
}
digest, err = t.transferer.GetTag(fmt.Sprintf("%s:%s", repo, tag))
if err != nil {
return nil, fmt.Errorf("transferer get tag: %w", err)
}
case _revisions:
var err error
digest, err = GetManifestDigest(path)
if err != nil {
return nil, fmt.Errorf("get manifest digest: %s", err)
}
default:
return nil, &InvalidRequestError{path}
}
blob, err := t.transferer.Download(repo, digest)
if err != nil {
return nil, fmt.Errorf("transferer download: %w", err)
}
defer blob.Close()
return []byte(digest.String()), nil
}
func (t *manifests) putContent(path string, subtype PathSubType) error {
switch subtype {
case _tags:
repo, err := GetRepo(path)
if err != nil {
return fmt.Errorf("get repo: %s", err)
}
tag, isCurrent, err := GetManifestTag(path)
if err != nil {
return fmt.Errorf("get manifest tag: %s", err)
}
if isCurrent {
return nil
}
digest, err := GetManifestDigest(path)
if err != nil {
return fmt.Errorf("get manifest digest: %s", err)
}
if err := t.transferer.PutTag(fmt.Sprintf("%s:%s", repo, tag), digest); err != nil {
return fmt.Errorf("post tag: %w", err)
}
return nil
}
// Intentional no-op.
return nil
}
func (t *manifests) stat(path string) (storagedriver.FileInfo, error) {
repo, err := GetRepo(path)
if err != nil {
return nil, fmt.Errorf("get repo: %s", err)
}
tag, _, err := GetManifestTag(path)
if err != nil {
return nil, fmt.Errorf("get manifest tag: %s", err)
}
if _, err := t.transferer.GetTag(fmt.Sprintf("%s:%s", repo, tag)); err != nil {
return nil, fmt.Errorf("get tag: %w", err)
}
return storagedriver.FileInfoInternal{
FileInfoFields: storagedriver.FileInfoFields{
Path: path,
Size: 64,
ModTime: time.Now(),
IsDir: false,
},
}, nil
}
func (t *manifests) list(path string) ([]string, error) {
prefix := path[len(_repositoryRoot):]
tags, err := t.transferer.ListTags(prefix)
if err != nil {
return nil, err
}
for i, tag := range tags {
// Strip repo prefix.
parts := strings.Split(tags[i], ":")
if len(parts) != 2 {
log.With("tag", tag).Warn("Repo list skipping tag, expected repo:tag format")
continue
}
tags[i] = parts[1]
}
return tags, nil
}