github.com/zhangbaitong/docker@v1.5.0/registry/session_v2.go (about) 1 package registry 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "strconv" 9 10 log "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/registry/v2" 12 "github.com/docker/docker/utils" 13 ) 14 15 func getV2Builder(e *Endpoint) *v2.URLBuilder { 16 if e.URLBuilder == nil { 17 e.URLBuilder = v2.NewURLBuilder(e.URL) 18 } 19 return e.URLBuilder 20 } 21 22 func (r *Session) V2RegistryEndpoint(index *IndexInfo) (ep *Endpoint, err error) { 23 // TODO check if should use Mirror 24 if index.Official { 25 ep, err = newEndpoint(REGISTRYSERVER, true) 26 if err != nil { 27 return 28 } 29 err = validateEndpoint(ep) 30 if err != nil { 31 return 32 } 33 } else if r.indexEndpoint.String() == index.GetAuthConfigKey() { 34 ep = r.indexEndpoint 35 } else { 36 ep, err = NewEndpoint(index) 37 if err != nil { 38 return 39 } 40 } 41 42 ep.URLBuilder = v2.NewURLBuilder(ep.URL) 43 return 44 } 45 46 // GetV2Authorization gets the authorization needed to the given image 47 // If readonly access is requested, then only the authorization may 48 // only be used for Get operations. 49 func (r *Session) GetV2Authorization(ep *Endpoint, imageName string, readOnly bool) (auth *RequestAuthorization, err error) { 50 scopes := []string{"pull"} 51 if !readOnly { 52 scopes = append(scopes, "push") 53 } 54 55 log.Debugf("Getting authorization for %s %s", imageName, scopes) 56 return NewRequestAuthorization(r.GetAuthConfig(true), ep, "repository", imageName, scopes), nil 57 } 58 59 // 60 // 1) Check if TarSum of each layer exists /v2/ 61 // 1.a) if 200, continue 62 // 1.b) if 300, then push the 63 // 1.c) if anything else, err 64 // 2) PUT the created/signed manifest 65 // 66 func (r *Session) GetV2ImageManifest(ep *Endpoint, imageName, tagName string, auth *RequestAuthorization) ([]byte, error) { 67 routeURL, err := getV2Builder(ep).BuildManifestURL(imageName, tagName) 68 if err != nil { 69 return nil, err 70 } 71 72 method := "GET" 73 log.Debugf("[registry] Calling %q %s", method, routeURL) 74 75 req, err := r.reqFactory.NewRequest(method, routeURL, nil) 76 if err != nil { 77 return nil, err 78 } 79 if err := auth.Authorize(req); err != nil { 80 return nil, err 81 } 82 res, _, err := r.doRequest(req) 83 if err != nil { 84 return nil, err 85 } 86 defer res.Body.Close() 87 if res.StatusCode != 200 { 88 if res.StatusCode == 401 { 89 return nil, errLoginRequired 90 } else if res.StatusCode == 404 { 91 return nil, ErrDoesNotExist 92 } 93 return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s:%s", res.StatusCode, imageName, tagName), res) 94 } 95 96 buf, err := ioutil.ReadAll(res.Body) 97 if err != nil { 98 return nil, fmt.Errorf("Error while reading the http response: %s", err) 99 } 100 return buf, nil 101 } 102 103 // - Succeeded to head image blob (already exists) 104 // - Failed with no error (continue to Push the Blob) 105 // - Failed with error 106 func (r *Session) HeadV2ImageBlob(ep *Endpoint, imageName, sumType, sum string, auth *RequestAuthorization) (bool, error) { 107 routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, sumType+":"+sum) 108 if err != nil { 109 return false, err 110 } 111 112 method := "HEAD" 113 log.Debugf("[registry] Calling %q %s", method, routeURL) 114 115 req, err := r.reqFactory.NewRequest(method, routeURL, nil) 116 if err != nil { 117 return false, err 118 } 119 if err := auth.Authorize(req); err != nil { 120 return false, err 121 } 122 res, _, err := r.doRequest(req) 123 if err != nil { 124 return false, err 125 } 126 res.Body.Close() // close early, since we're not needing a body on this call .. yet? 127 switch { 128 case res.StatusCode >= 200 && res.StatusCode < 400: 129 // return something indicating no push needed 130 return true, nil 131 case res.StatusCode == 401: 132 return false, errLoginRequired 133 case res.StatusCode == 404: 134 // return something indicating blob push needed 135 return false, nil 136 } 137 138 return false, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying head request for %s - %s:%s", res.StatusCode, imageName, sumType, sum), res) 139 } 140 141 func (r *Session) GetV2ImageBlob(ep *Endpoint, imageName, sumType, sum string, blobWrtr io.Writer, auth *RequestAuthorization) error { 142 routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, sumType+":"+sum) 143 if err != nil { 144 return err 145 } 146 147 method := "GET" 148 log.Debugf("[registry] Calling %q %s", method, routeURL) 149 req, err := r.reqFactory.NewRequest(method, routeURL, nil) 150 if err != nil { 151 return err 152 } 153 if err := auth.Authorize(req); err != nil { 154 return err 155 } 156 res, _, err := r.doRequest(req) 157 if err != nil { 158 return err 159 } 160 defer res.Body.Close() 161 if res.StatusCode != 200 { 162 if res.StatusCode == 401 { 163 return errLoginRequired 164 } 165 return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res) 166 } 167 168 _, err = io.Copy(blobWrtr, res.Body) 169 return err 170 } 171 172 func (r *Session) GetV2ImageBlobReader(ep *Endpoint, imageName, sumType, sum string, auth *RequestAuthorization) (io.ReadCloser, int64, error) { 173 routeURL, err := getV2Builder(ep).BuildBlobURL(imageName, sumType+":"+sum) 174 if err != nil { 175 return nil, 0, err 176 } 177 178 method := "GET" 179 log.Debugf("[registry] Calling %q %s", method, routeURL) 180 req, err := r.reqFactory.NewRequest(method, routeURL, nil) 181 if err != nil { 182 return nil, 0, err 183 } 184 if err := auth.Authorize(req); err != nil { 185 return nil, 0, err 186 } 187 res, _, err := r.doRequest(req) 188 if err != nil { 189 return nil, 0, err 190 } 191 if res.StatusCode != 200 { 192 if res.StatusCode == 401 { 193 return nil, 0, errLoginRequired 194 } 195 return nil, 0, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob - %s:%s", res.StatusCode, imageName, sumType, sum), res) 196 } 197 lenStr := res.Header.Get("Content-Length") 198 l, err := strconv.ParseInt(lenStr, 10, 64) 199 if err != nil { 200 return nil, 0, err 201 } 202 203 return res.Body, l, err 204 } 205 206 // Push the image to the server for storage. 207 // 'layer' is an uncompressed reader of the blob to be pushed. 208 // The server will generate it's own checksum calculation. 209 func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string, blobRdr io.Reader, auth *RequestAuthorization) error { 210 routeURL, err := getV2Builder(ep).BuildBlobUploadURL(imageName) 211 if err != nil { 212 return err 213 } 214 215 log.Debugf("[registry] Calling %q %s", "POST", routeURL) 216 req, err := r.reqFactory.NewRequest("POST", routeURL, nil) 217 if err != nil { 218 return err 219 } 220 221 if err := auth.Authorize(req); err != nil { 222 return err 223 } 224 res, _, err := r.doRequest(req) 225 if err != nil { 226 return err 227 } 228 location := res.Header.Get("Location") 229 230 method := "PUT" 231 log.Debugf("[registry] Calling %q %s", method, location) 232 req, err = r.reqFactory.NewRequest(method, location, ioutil.NopCloser(blobRdr)) 233 if err != nil { 234 return err 235 } 236 queryParams := req.URL.Query() 237 queryParams.Add("digest", sumType+":"+sumStr) 238 req.URL.RawQuery = queryParams.Encode() 239 if err := auth.Authorize(req); err != nil { 240 return err 241 } 242 res, _, err = r.doRequest(req) 243 if err != nil { 244 return err 245 } 246 defer res.Body.Close() 247 248 if res.StatusCode != 201 { 249 if res.StatusCode == 401 { 250 return errLoginRequired 251 } 252 errBody, err := ioutil.ReadAll(res.Body) 253 if err != nil { 254 return err 255 } 256 log.Debugf("Unexpected response from server: %q %#v", errBody, res.Header) 257 return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob - %s:%s", res.StatusCode, imageName, sumType, sumStr), res) 258 } 259 260 return nil 261 } 262 263 // Finally Push the (signed) manifest of the blobs we've just pushed 264 func (r *Session) PutV2ImageManifest(ep *Endpoint, imageName, tagName string, manifestRdr io.Reader, auth *RequestAuthorization) error { 265 routeURL, err := getV2Builder(ep).BuildManifestURL(imageName, tagName) 266 if err != nil { 267 return err 268 } 269 270 method := "PUT" 271 log.Debugf("[registry] Calling %q %s", method, routeURL) 272 req, err := r.reqFactory.NewRequest(method, routeURL, manifestRdr) 273 if err != nil { 274 return err 275 } 276 if err := auth.Authorize(req); err != nil { 277 return err 278 } 279 res, _, err := r.doRequest(req) 280 if err != nil { 281 return err 282 } 283 defer res.Body.Close() 284 285 // All 2xx and 3xx responses can be accepted for a put. 286 if res.StatusCode >= 400 { 287 if res.StatusCode == 401 { 288 return errLoginRequired 289 } 290 errBody, err := ioutil.ReadAll(res.Body) 291 if err != nil { 292 return err 293 } 294 log.Debugf("Unexpected response from server: %q %#v", errBody, res.Header) 295 return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res) 296 } 297 298 return nil 299 } 300 301 type remoteTags struct { 302 name string 303 tags []string 304 } 305 306 // Given a repository name, returns a json array of string tags 307 func (r *Session) GetV2RemoteTags(ep *Endpoint, imageName string, auth *RequestAuthorization) ([]string, error) { 308 routeURL, err := getV2Builder(ep).BuildTagsURL(imageName) 309 if err != nil { 310 return nil, err 311 } 312 313 method := "GET" 314 log.Debugf("[registry] Calling %q %s", method, routeURL) 315 316 req, err := r.reqFactory.NewRequest(method, routeURL, nil) 317 if err != nil { 318 return nil, err 319 } 320 if err := auth.Authorize(req); err != nil { 321 return nil, err 322 } 323 res, _, err := r.doRequest(req) 324 if err != nil { 325 return nil, err 326 } 327 defer res.Body.Close() 328 if res.StatusCode != 200 { 329 if res.StatusCode == 401 { 330 return nil, errLoginRequired 331 } else if res.StatusCode == 404 { 332 return nil, ErrDoesNotExist 333 } 334 return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s", res.StatusCode, imageName), res) 335 } 336 337 decoder := json.NewDecoder(res.Body) 338 var remote remoteTags 339 err = decoder.Decode(&remote) 340 if err != nil { 341 return nil, fmt.Errorf("Error while decoding the http response: %s", err) 342 } 343 return remote.tags, nil 344 }