From 766db7514b7c12c20d9e6171da9af255a49da68a Mon Sep 17 00:00:00 2001 From: Josh Hawn Date: Thu, 28 Aug 2014 16:42:25 -0700 Subject: [PATCH] Retrofit of registry v2 client --- registry/session_prov.go | 149 ++++++++++++++++++++++------------- registry/v2/routes/router.go | 1 + 2 files changed, 96 insertions(+), 54 deletions(-) diff --git a/registry/session_prov.go b/registry/session_prov.go index b6ac7d6de2261..db7351a15172a 100644 --- a/registry/session_prov.go +++ b/registry/session_prov.go @@ -1,46 +1,61 @@ package registry import ( + "encoding/json" "fmt" "io" "io/ioutil" "log" + "net/url" "strings" + "github.com/docker/docker/registry/v2/routes" "github.com/docker/docker/utils" ) // APIVersion2 /v2/ -var v2HTTPRoutes = map[string]map[string]HTTPRoute{ - "GET": { - "Version": HTTPRoute("version"), // XXX DONE - "ImageManifest": HTTPRoute("manifest/{imgname:.*}/{tagname}"), // XXX DONE - "ImageTags": HTTPRoute("tags/{imgname:.*}"), // XXX - "ImageBlobSum": HTTPRoute("blob/{imgname:.*}/{sumtype}/{sum}"), // XXX - }, - "PUT": { - "ImageManifest": HTTPRoute("manifest/{imgname:.*}/{tagname}"), // XXX - "ImageBlobSum": HTTPRoute("blob/{imgname:.*}/{sumtype}/{sum}"), // XXX - }, - "POST": { - "ImageBlob": HTTPRoute("blob/{imgname:.*}/{sumtype}"), // XXX DONE - "ImageMountBlob": HTTPRoute("mountblob/{imgname:.*}/{sumtype}/{sum}"), // XXX DONE - }, - "DELETE": { - "ImageManifest": HTTPRoute("manifest/{imgname:.*}/{tagname}"), // XXX - }, +var v2HTTPRoutes = routes.NewRegistryRouter() + +func getV2URL(e Endpoint, routeName string, vars map[string]string) (*url.URL, error) { + route := v2HTTPRoutes.Get(routeName) + if route == nil { + return nil, fmt.Errorf("unknown regisry v2 route name: %q", routeName) + } + + varReplace := make([]string, 0, len(vars)*2) + for key, val := range vars { + varReplace = append(varReplace, key, val) + } + + routePath, err := route.URLPath(varReplace...) + if err != nil { + return nil, fmt.Errorf("unable to make registry route %q with vars %v: %s", routeName, vars, err) + } + + return &url.URL{ + Scheme: e.URL.Scheme, + Host: e.URL.Host, + Path: routePath.Path, + } } +// V2 Provenance POC + func (r *Session) GetV2Version(token []string) (*RegistryInfo, error) { if r.indexEndpoint.Version != APIVersion2 { return nil, ErrIncorrectAPIVersion } + routeURL, err := getV2URL(r.indexEndpoint, routes.VersionRoutename, nil) + if err != nil { + return nil, err + } + method := "GET" hr := v2HTTPRoutes[method]["Version"] - log.Printf("[registry] Calling %q %s", method, r.indexEndpoint.String()+string(hr)) + log.Printf("[registry] Calling %q %s", method, routeURL.String()) - req, err := r.reqFactory.NewRequest(method, r.indexEndpoint.String()+string(hr), nil) + req, err := r.reqFactory.NewRequest(method, routeURL.String(), nil) if err != nil { return nil, err } @@ -61,7 +76,6 @@ func (r *Session) GetV2Version(token []string) (*RegistryInfo, error) { return &RegistryInfo{Version: strings.TrimSpace(string(buf))}, nil } -// V2 Provenance POC // // 1) Check if TarSum of each layer exists /v2/ // 1.a) if 200, continue @@ -74,15 +88,20 @@ func (r *Session) GetV2ImageManifest(imageName, tagName string, token []string) return nil, ErrIncorrectAPIVersion } - method := "GET" - hr := v2HTTPRoutes[method]["ImageManifest"] - values := map[string]string{ - "imgname": imageName, - "tagname": tagName, + vars := map[string]string{ + "imagename": imageName, + "tagname": tagName, + } + + routeURL, err := getV2URL(r.indexEndpoint, routes.ManifestsRouteName, vars) + if err != nil { + return nil, err } - log.Printf("[registry] Calling %q %s", method, r.indexEndpoint.String()+hr.Format(values)) - req, err := r.reqFactory.NewRequest(method, r.indexEndpoint.String()+hr.Format(values), nil) + method := "GET" + log.Printf("[registry] Calling %q %s", method, routeURL.String()) + + req, err := r.reqFactory.NewRequest(method, routeURL.String(), nil) if err != nil { return nil, err } @@ -114,16 +133,21 @@ func (r *Session) PostV2ImageMountBlob(imageName, sumType, sum string, token []s return false, ErrIncorrectAPIVersion } - method := "POST" - hr := v2HTTPRoutes[method]["ImageMountBlob"] - values := map[string]string{ - "imgname": imageName, - "sumtype": sumType, - "sum": sum, + vars := map[string]string{ + "imagename": imageName, + "sumtype": sumType, + "sum": sum, } - log.Printf("[registry] Calling %q %s", method, r.indexEndpoint.String()+hr.Format(values)) - req, err := r.reqFactory.NewRequest(method, r.indexEndpoint.String()+hr.Format(values), nil) + routeURL, err := getV2URL(r.indexEndpoint, routes.MountBlobRouteName, vars) + if err != nil { + return nil, err + } + + method := "POST" + log.Printf("[registry] Calling %q %s", method, routeURL.String()) + + req, err := r.reqFactory.NewRequest(method, routeURL.String(), nil) if err != nil { return false, err } @@ -147,19 +171,24 @@ func (r *Session) PostV2ImageMountBlob(imageName, sumType, sum string, token []s // Push the image to the server for storage. // 'layer' is an uncompressed reader of the blob to be pushed. // The server will generate it's own checksum calculation. -func (r *Session) PostV2ImageBlob(imageName, sumType string, blobRdr io.Reader, token []string) (serverChecksum string, err error) { +func (r *Session) PutV2ImageBlob(imageName, sumType string, blobRdr io.Reader, token []string) (serverChecksum string, err error) { if r.indexEndpoint.Version != APIVersion2 { return "", ErrIncorrectAPIVersion } - method := "POST" - hr := v2HTTPRoutes[method]["ImageBlob"] - values := map[string]string{ - "imgname": imageName, - "sumtype": sumType, + vars := map[string]string{ + "imagename": imageName, + "sumtype": sumType, } - log.Printf("[registry] Calling %q %s", method, r.indexEndpoint.String()+hr.Format(values)) - req, err := r.reqFactory.NewRequest(method, r.indexEndpoint.String()+hr.Format(values), blobRdr) + + routeURL, err := getV2URL(r.indexEndpoint, routes.UploadBlobRouteName, vars) + if err != nil { + return nil, err + } + + method := "PUT" + log.Printf("[registry] Calling %q %s", method, routeURL.String()) + req, err := r.reqFactory.NewRequest(method, routeURL.String(), blobRdr) if err != nil { return "", err } @@ -176,13 +205,20 @@ func (r *Session) PostV2ImageBlob(imageName, sumType string, blobRdr io.Reader, return "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob", res.StatusCode, imageName), res) } - jsonBuf, err := ioutil.ReadAll(res.Body) + type sumReturn struct { + Checksum string `json:"checksum"` + } + + decoder := json.NewDecoder(res.Body) + var sumInfo sumReturn + + err = decoder.Decode(&sumInfo) if err != nil { - return "", fmt.Errorf("Error while reading the http response: %s", err) + return "", fmt.Errorf("unable to decode PutV2ImageBlob JSON response: %s", err) } // XXX this is a json struct from the registry, with its checksum - return string(jsonBuf), nil + return sumInfo.Checksum, nil } // Finally Push the (signed) manifest of the blobs we've just pushed @@ -191,14 +227,19 @@ func (r *Session) PutV2ImageManifest(imageName, tagName string, manifestRdr io.R return ErrIncorrectAPIVersion } - method := "PUT" - hr := v2HTTPRoutes[method]["ImageManifest"] - values := map[string]string{ - "imgname": imageName, - "tagname": tagName, + vars := map[string]string{ + "imagename": imageName, + "tagname": tagName, } - log.Printf("[registry] Calling %q %s", method, r.indexEndpoint.String()+hr.Format(values)) - req, err := r.reqFactory.NewRequest(method, r.indexEndpoint.String()+hr.Format(values), manifestRdr) + + routeURL, err := getV2URL(r.indexEndpoint, routes.ManifestsRouteName, vars) + if err != nil { + return nil, err + } + + method := "PUT" + log.Printf("[registry] Calling %q %s", method, routeURL.String()) + req, err := r.reqFactory.NewRequest(method, routeURL.String(), manifestRdr) if err != nil { return err } diff --git a/registry/v2/routes/router.go b/registry/v2/routes/router.go index 6b182140773aa..72ac966d84908 100644 --- a/registry/v2/routes/router.go +++ b/registry/v2/routes/router.go @@ -10,6 +10,7 @@ const ( DownloadBlobRouteName = "downloadBlob" UploadBlobRouteName = "uploadBlob" MountBlobRouteName = "mountBlob" + VersionRoutename = "version" ) func NewRegistryRouter() *mux.Router {