github.com/uber/kraken@v0.1.4/lib/backend/namepath/pather.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 namepath 15 16 import ( 17 "errors" 18 "fmt" 19 "path" 20 "regexp" 21 "strings" 22 ) 23 24 // Pather id strings. 25 const ( 26 DockerTag = "docker_tag" 27 ShardedDockerBlob = "sharded_docker_blob" 28 Identity = "identity" 29 ) 30 31 // New creates a Pather scoped to root. 32 func New(root, id string) (Pather, error) { 33 switch id { 34 case DockerTag: 35 return DockerTagPather{root}, nil 36 case ShardedDockerBlob: 37 return ShardedDockerBlobPather{root}, nil 38 case Identity: 39 return IdentityPather{root}, nil 40 case "": 41 return nil, fmt.Errorf("invalid pather identifier: empty") 42 default: 43 return nil, fmt.Errorf("unknown pather identifier: %s", id) 44 } 45 } 46 47 // Pather defines an interface for converting names into paths. 48 type Pather interface { 49 // BasePath returns the base path of where blobs are stored. 50 BasePath() string 51 52 // BlobPath converts name into a blob path. 53 BlobPath(name string) (string, error) 54 55 // NameFromBlobPath converts blob path bp back into the original blob name. 56 NameFromBlobPath(bp string) (string, error) 57 } 58 59 // DockerTagPather generates paths for Docker tags. 60 type DockerTagPather struct { 61 root string 62 } 63 64 // BasePath returns the docker registry repositories prefix. 65 func (p DockerTagPather) BasePath() string { 66 return path.Join(p.root, "docker/registry/v2/repositories") 67 } 68 69 // BlobPath interprets name as a "repo:tag" and generates a registry path for it. 70 func (p DockerTagPather) BlobPath(name string) (string, error) { 71 tokens := strings.Split(name, ":") 72 if len(tokens) != 2 { 73 return "", errors.New("name must be in format 'repo:tag'") 74 } 75 repo := tokens[0] 76 if len(repo) == 0 { 77 return "", errors.New("repo must be non-empty") 78 } 79 tag := tokens[1] 80 if len(tag) == 0 { 81 return "", errors.New("tag must be non-empty") 82 } 83 return path.Join(p.BasePath(), repo, "_manifests/tags", tag, "current/link"), nil 84 } 85 86 // NameFromBlobPath converts a tag path back into repo:tag format. 87 func (p DockerTagPather) NameFromBlobPath(bp string) (string, error) { 88 re := regexp.MustCompile(p.BasePath() + "/(.+)/_manifests/tags/(.+)/current/link") 89 matches := re.FindStringSubmatch(bp) 90 if len(matches) != 3 { 91 return "", errors.New("invalid docker tag path format") 92 } 93 repo := matches[1] 94 tag := matches[2] 95 return fmt.Sprintf("%s:%s", repo, tag), nil 96 } 97 98 // ShardedDockerBlobPather generates sharded paths for Docker blobs. 99 type ShardedDockerBlobPather struct { 100 root string 101 } 102 103 // BasePath returns the docker registry blobs prefix. 104 func (p ShardedDockerBlobPather) BasePath() string { 105 return path.Join(p.root, "docker/registry/v2/blobs") 106 } 107 108 // BlobPath interprets name as a SHA256 digest and returns a registry path 109 // which is sharded by the first two bytes. 110 func (p ShardedDockerBlobPather) BlobPath(name string) (string, error) { 111 if len(name) <= 2 { 112 return "", errors.New("name is too short, must be > 2 characters") 113 } 114 return path.Join(p.BasePath(), "sha256", name[:2], name, "data"), nil 115 } 116 117 // NameFromBlobPath converts a sharded blob path back into raw hex format. 118 func (p ShardedDockerBlobPather) NameFromBlobPath(bp string) (string, error) { 119 re := regexp.MustCompile(p.BasePath() + "/sha256/../(.+)/data") 120 matches := re.FindStringSubmatch(bp) 121 if len(matches) != 2 { 122 return "", errors.New("invalid sharded docker blob path format") 123 } 124 return matches[1], nil 125 } 126 127 // IdentityPather is the identity Pather. 128 type IdentityPather struct { 129 root string 130 } 131 132 // BasePath returns the root. 133 func (p IdentityPather) BasePath() string { 134 return p.root 135 } 136 137 // BlobPath always returns root/name. 138 func (p IdentityPather) BlobPath(name string) (string, error) { 139 return path.Join(p.root, name), nil 140 } 141 142 // NameFromBlobPath strips the root from bp. 143 func (p IdentityPather) NameFromBlobPath(bp string) (string, error) { 144 if !strings.HasPrefix(bp, p.root) { 145 return "", errors.New("invalid identity path format") 146 } 147 return bp[len(p.root)+1:], nil 148 }