github.com/demonoid81/containerd@v1.3.4/remotes/docker/registry.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package docker 18 19 import ( 20 "net/http" 21 ) 22 23 // HostCapabilities represent the capabilities of the registry 24 // host. This also represents the set of operations for which 25 // the registry host may be trusted to perform. 26 // 27 // For example pushing is a capability which should only be 28 // performed on an upstream source, not a mirror. 29 // Resolving (the process of converting a name into a digest) 30 // must be considered a trusted operation and only done by 31 // a host which is trusted (or more preferably by secure process 32 // which can prove the provenance of the mapping). A public 33 // mirror should never be trusted to do a resolve action. 34 // 35 // | Registry Type | Pull | Resolve | Push | 36 // |------------------|------|---------|------| 37 // | Public Registry | yes | yes | yes | 38 // | Private Registry | yes | yes | yes | 39 // | Public Mirror | yes | no | no | 40 // | Private Mirror | yes | yes | no | 41 type HostCapabilities uint8 42 43 const ( 44 // HostCapabilityPull represents the capability to fetch manifests 45 // and blobs by digest 46 HostCapabilityPull HostCapabilities = 1 << iota 47 48 // HostCapabilityResolve represents the capability to fetch manifests 49 // by name 50 HostCapabilityResolve 51 52 // HostCapabilityPush represents the capability to push blobs and 53 // manifests 54 HostCapabilityPush 55 56 // Reserved for future capabilities (i.e. search, catalog, remove) 57 ) 58 59 func (c HostCapabilities) Has(t HostCapabilities) bool { 60 return c&t == t 61 } 62 63 // RegistryHost represents a complete configuration for a registry 64 // host, representing the capabilities, authorizations, connection 65 // configuration, and location. 66 type RegistryHost struct { 67 Client *http.Client 68 Authorizer Authorizer 69 Host string 70 Scheme string 71 Path string 72 Capabilities HostCapabilities 73 } 74 75 // RegistryHosts fetches the registry hosts for a given namespace, 76 // provided by the host component of an distribution image reference. 77 type RegistryHosts func(string) ([]RegistryHost, error) 78 79 // Registries joins multiple registry configuration functions, using the same 80 // order as provided within the arguments. When an empty registry configuration 81 // is returned with a nil error, the next function will be called. 82 // NOTE: This function will not join configurations, as soon as a non-empty 83 // configuration is returned from a configuration function, it will be returned 84 // to the caller. 85 func Registries(registries ...RegistryHosts) RegistryHosts { 86 return func(host string) ([]RegistryHost, error) { 87 for _, registry := range registries { 88 config, err := registry(host) 89 if err != nil { 90 return config, err 91 } 92 if len(config) > 0 { 93 return config, nil 94 } 95 } 96 return nil, nil 97 } 98 } 99 100 type registryOpts struct { 101 authorizer Authorizer 102 plainHTTP func(string) (bool, error) 103 host func(string) (string, error) 104 client *http.Client 105 } 106 107 // RegistryOpt defines a registry default option 108 type RegistryOpt func(*registryOpts) 109 110 // WithPlainHTTP configures registries to use plaintext http scheme 111 // for the provided host match function. 112 func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt { 113 return func(opts *registryOpts) { 114 opts.plainHTTP = f 115 } 116 } 117 118 // WithAuthorizer configures the default authorizer for a registry 119 func WithAuthorizer(a Authorizer) RegistryOpt { 120 return func(opts *registryOpts) { 121 opts.authorizer = a 122 } 123 } 124 125 // WithHostTranslator defines the default translator to use for registry hosts 126 func WithHostTranslator(h func(string) (string, error)) RegistryOpt { 127 return func(opts *registryOpts) { 128 opts.host = h 129 } 130 } 131 132 // WithClient configures the default http client for a registry 133 func WithClient(c *http.Client) RegistryOpt { 134 return func(opts *registryOpts) { 135 opts.client = c 136 } 137 } 138 139 // ConfigureDefaultRegistries is used to create a default configuration for 140 // registries. For more advanced configurations or per-domain setups, 141 // the RegistryHosts interface should be used directly. 142 // NOTE: This function will always return a non-empty value or error 143 func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts { 144 var opts registryOpts 145 for _, opt := range ropts { 146 opt(&opts) 147 } 148 149 return func(host string) ([]RegistryHost, error) { 150 config := RegistryHost{ 151 Client: opts.client, 152 Authorizer: opts.authorizer, 153 Host: host, 154 Scheme: "https", 155 Path: "/v2", 156 Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, 157 } 158 159 if config.Client == nil { 160 config.Client = http.DefaultClient 161 } 162 163 if opts.plainHTTP != nil { 164 match, err := opts.plainHTTP(host) 165 if err != nil { 166 return nil, err 167 } 168 if match { 169 config.Scheme = "http" 170 } 171 } 172 173 if opts.host != nil { 174 var err error 175 config.Host, err = opts.host(config.Host) 176 if err != nil { 177 return nil, err 178 } 179 } else if host == "docker.io" { 180 config.Host = "registry-1.docker.io" 181 } 182 183 return []RegistryHost{config}, nil 184 } 185 } 186 187 // MatchAllHosts is a host match function which is always true. 188 func MatchAllHosts(string) (bool, error) { 189 return true, nil 190 } 191 192 // MatchLocalhost is a host match function which returns true for 193 // localhost. 194 func MatchLocalhost(host string) (bool, error) { 195 for _, s := range []string{"localhost", "127.0.0.1", "[::1]"} { 196 if len(host) >= len(s) && host[0:len(s)] == s && (len(host) == len(s) || host[len(s)] == ':') { 197 return true, nil 198 } 199 } 200 return host == "::1", nil 201 202 }