github.com/uber/kraken@v0.1.4/lib/dockerregistry/manifests.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package dockerregistry 15 16 import ( 17 "fmt" 18 "strings" 19 "time" 20 21 "github.com/uber/kraken/core" 22 "github.com/uber/kraken/lib/dockerregistry/transfer" 23 "github.com/uber/kraken/utils/log" 24 storagedriver "github.com/docker/distribution/registry/storage/driver" 25 ) 26 27 const ( 28 pullTimer = "dockertag.time.pull" 29 createSuccessCounter = "dockertag.success.create" 30 createFailureCounter = "dockertag.failure.create" 31 getSuccessCounter = "dockertag.success.get" 32 getFailureCounter = "dockertag.failure.get" 33 ) 34 35 type manifests struct { 36 transferer transfer.ImageTransferer 37 } 38 39 func newManifests(transferer transfer.ImageTransferer) *manifests { 40 return &manifests{transferer} 41 } 42 43 // getDigest downloads and returns manifest digest. 44 // This is the only place storage driver would download a manifest blob via 45 // torrent scheduler or origin because it has namespace information. 46 // The caller of storage driver would first call this function to resolve 47 // the manifest link (and downloads manifest blob), 48 // then call Stat or Reader which would assume the blob is on disk already. 49 func (t *manifests) getDigest(path string, subtype PathSubType) ([]byte, error) { 50 repo, err := GetRepo(path) 51 if err != nil { 52 return nil, fmt.Errorf("get repo: %s", err) 53 } 54 55 var digest core.Digest 56 switch subtype { 57 case _tags: 58 tag, _, err := GetManifestTag(path) 59 if err != nil { 60 return nil, fmt.Errorf("get manifest tag: %s", err) 61 } 62 digest, err = t.transferer.GetTag(fmt.Sprintf("%s:%s", repo, tag)) 63 if err != nil { 64 if err == transfer.ErrTagNotFound { 65 return nil, storagedriver.PathNotFoundError{ 66 DriverName: "kraken", 67 Path: digest.String(), 68 } 69 } 70 return nil, fmt.Errorf("transferer get tag: %s", err) 71 } 72 case _revisions: 73 var err error 74 digest, err = GetManifestDigest(path) 75 if err != nil { 76 return nil, fmt.Errorf("get manifest digest: %s", err) 77 } 78 default: 79 return nil, &InvalidRequestError{path} 80 } 81 82 blob, err := t.transferer.Download(repo, digest) 83 if err != nil { 84 if err == transfer.ErrBlobNotFound { 85 return nil, storagedriver.PathNotFoundError{ 86 DriverName: "kraken", 87 Path: digest.String(), 88 } 89 } 90 return nil, fmt.Errorf("transferer download: %s", err) 91 } 92 defer blob.Close() 93 94 return []byte(digest.String()), nil 95 } 96 97 func (t *manifests) putContent(path string, subtype PathSubType) error { 98 switch subtype { 99 case _tags: 100 repo, err := GetRepo(path) 101 if err != nil { 102 return fmt.Errorf("get repo: %s", err) 103 } 104 tag, isCurrent, err := GetManifestTag(path) 105 if err != nil { 106 return fmt.Errorf("get manifest tag: %s", err) 107 } 108 if isCurrent { 109 return nil 110 } 111 digest, err := GetManifestDigest(path) 112 if err != nil { 113 return fmt.Errorf("get manifest digest: %s", err) 114 } 115 if err := t.transferer.PutTag(fmt.Sprintf("%s:%s", repo, tag), digest); err != nil { 116 return fmt.Errorf("post tag: %s", err) 117 } 118 return nil 119 } 120 // Intentional no-op. 121 return nil 122 } 123 124 func (t *manifests) stat(path string) (storagedriver.FileInfo, error) { 125 repo, err := GetRepo(path) 126 if err != nil { 127 return nil, fmt.Errorf("get repo: %s", err) 128 } 129 tag, _, err := GetManifestTag(path) 130 if err != nil { 131 return nil, fmt.Errorf("get manifest tag: %s", err) 132 } 133 if _, err := t.transferer.GetTag(fmt.Sprintf("%s:%s", repo, tag)); err != nil { 134 if err == transfer.ErrTagNotFound { 135 return nil, storagedriver.PathNotFoundError{ 136 DriverName: "kraken", 137 Path: path, 138 } 139 } 140 return nil, fmt.Errorf("get tag: %s", err) 141 } 142 return storagedriver.FileInfoInternal{ 143 FileInfoFields: storagedriver.FileInfoFields{ 144 Path: path, 145 Size: 64, 146 ModTime: time.Now(), 147 IsDir: false, 148 }, 149 }, nil 150 } 151 152 func (t *manifests) list(path string) ([]string, error) { 153 prefix := path[len(_repositoryRoot):] 154 tags, err := t.transferer.ListTags(prefix) 155 if err != nil { 156 return nil, err 157 } 158 for i, tag := range tags { 159 // Strip repo prefix. 160 parts := strings.Split(tags[i], ":") 161 if len(parts) != 2 { 162 log.With("tag", tag).Warn("Repo list skipping tag, expected repo:tag format") 163 continue 164 } 165 tags[i] = parts[1] 166 } 167 return tags, nil 168 }