Update the registry app to use the new storage interfaces
Signed-off-by: Stephen J Day <stephen.day@docker.com>master
							parent
							
								
									ea5b999fc0
								
							
						
					
					
						commit
						ff4a1700cc
					
				|  | @ -26,8 +26,8 @@ type App struct { | |||
| 	// driver maintains the app global storage driver instance.
 | ||||
| 	driver storagedriver.StorageDriver | ||||
| 
 | ||||
| 	// services contains the main services instance for the application.
 | ||||
| 	services *storage.Services | ||||
| 	// registry is the primary registry backend for the app instance.
 | ||||
| 	registry storage.Registry | ||||
| 
 | ||||
| 	layerHandler storage.LayerHandler | ||||
| 
 | ||||
|  | @ -63,7 +63,7 @@ func NewApp(configuration configuration.Configuration) *App { | |||
| 	} | ||||
| 
 | ||||
| 	app.driver = driver | ||||
| 	app.services = storage.NewServices(app.driver) | ||||
| 	app.registry = storage.NewRegistryWithDriver(app.driver) | ||||
| 	authType := configuration.Auth.Type() | ||||
| 
 | ||||
| 	if authType != "" { | ||||
|  | @ -136,11 +136,11 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler { | |||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		context := app.context(r) | ||||
| 
 | ||||
| 		if err := app.authorized(w, r, context); err != nil { | ||||
| 		if err := app.authorized(w, r, context, context.vars["name"]); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		context.log = log.WithField("name", context.Name) | ||||
| 		context.log = log.WithField("name", context.Repository.Name()) | ||||
| 		handler := dispatch(context, r) | ||||
| 
 | ||||
| 		ssrw := &singleStatusResponseWriter{ResponseWriter: w} | ||||
|  | @ -165,7 +165,6 @@ func (app *App) context(r *http.Request) *Context { | |||
| 	vars := mux.Vars(r) | ||||
| 	context := &Context{ | ||||
| 		App:        app, | ||||
| 		Name:       vars["name"], | ||||
| 		urlBuilder: v2.NewURLBuilderFromRequest(r), | ||||
| 	} | ||||
| 
 | ||||
|  | @ -175,19 +174,23 @@ func (app *App) context(r *http.Request) *Context { | |||
| 	return context | ||||
| } | ||||
| 
 | ||||
| // authorized checks if the request can proceed with with request access-
 | ||||
| // level. If it cannot, the method will return an error.
 | ||||
| func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Context) error { | ||||
| // authorized checks if the request can proceed with access to the requested
 | ||||
| // repository. If it succeeds, the repository will be available on the
 | ||||
| // context. An error will be if access is not available.
 | ||||
| func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Context, repo string) error { | ||||
| 	if app.accessController == nil { | ||||
| 		// No access controller, so we simply provide access.
 | ||||
| 		context.Repository = app.registry.Repository(repo) | ||||
| 
 | ||||
| 		return nil // access controller is not enabled.
 | ||||
| 	} | ||||
| 
 | ||||
| 	var accessRecords []auth.Access | ||||
| 
 | ||||
| 	if context.Name != "" { | ||||
| 	if repo != "" { | ||||
| 		resource := auth.Resource{ | ||||
| 			Type: "repository", | ||||
| 			Name: context.Name, | ||||
| 			Name: repo, | ||||
| 		} | ||||
| 
 | ||||
| 		switch r.Method { | ||||
|  | @ -256,6 +259,10 @@ func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Cont | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// At this point, the request should have access to the repository under
 | ||||
| 	// the requested operation. Make is available on the context.
 | ||||
| 	context.Repository = app.registry.Repository(repo) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ import ( | |||
| 	"github.com/docker/distribution/api/v2" | ||||
| 	_ "github.com/docker/distribution/auth/silly" | ||||
| 	"github.com/docker/distribution/configuration" | ||||
| 	"github.com/docker/distribution/storage" | ||||
| 	"github.com/docker/distribution/storagedriver/inmemory" | ||||
| ) | ||||
| 
 | ||||
| // TestAppDispatcher builds an application with a test dispatcher and ensures
 | ||||
|  | @ -17,9 +19,12 @@ import ( | |||
| // This only tests the dispatch mechanism. The underlying dispatchers must be
 | ||||
| // tested individually.
 | ||||
| func TestAppDispatcher(t *testing.T) { | ||||
| 	driver := inmemory.New() | ||||
| 	app := &App{ | ||||
| 		Config:   configuration.Configuration{}, | ||||
| 		router:   v2.Router(), | ||||
| 		driver:   driver, | ||||
| 		registry: storage.NewRegistryWithDriver(driver), | ||||
| 	} | ||||
| 	server := httptest.NewServer(app) | ||||
| 	router := v2.Router() | ||||
|  | @ -32,8 +37,8 @@ func TestAppDispatcher(t *testing.T) { | |||
| 	varCheckingDispatcher := func(expectedVars map[string]string) dispatchFunc { | ||||
| 		return func(ctx *Context, r *http.Request) http.Handler { | ||||
| 			// Always checks the same name context
 | ||||
| 			if ctx.Name != ctx.vars["name"] { | ||||
| 				t.Fatalf("unexpected name: %q != %q", ctx.Name, "foo/bar") | ||||
| 			if ctx.Repository.Name() != ctx.vars["name"] { | ||||
| 				t.Fatalf("unexpected name: %q != %q", ctx.Repository.Name(), "foo/bar") | ||||
| 			} | ||||
| 
 | ||||
| 			// Check that we have all that is expected
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ package registry | |||
| import ( | ||||
| 	"github.com/Sirupsen/logrus" | ||||
| 	"github.com/docker/distribution/api/v2" | ||||
| 	"github.com/docker/distribution/storage" | ||||
| ) | ||||
| 
 | ||||
| // Context should contain the request specific context for use in across
 | ||||
|  | @ -12,9 +13,9 @@ type Context struct { | |||
| 	// App points to the application structure that created this context.
 | ||||
| 	*App | ||||
| 
 | ||||
| 	// Name is the prefix for the current request. Corresponds to the
 | ||||
| 	// namespace/repository associated with the image.
 | ||||
| 	Name string | ||||
| 	// Repository is the repository for the current request. All requests
 | ||||
| 	// should be scoped to a single repository. This field may be nil.
 | ||||
| 	Repository storage.Repository | ||||
| 
 | ||||
| 	// Errors is a collection of errors encountered during the request to be
 | ||||
| 	// returned to the client API. If errors are added to the collection, the
 | ||||
|  |  | |||
|  | @ -38,8 +38,8 @@ type imageManifestHandler struct { | |||
| 
 | ||||
| // GetImageManifest fetches the image manifest from the storage backend, if it exists.
 | ||||
| func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Request) { | ||||
| 	manifests := imh.services.Manifests() | ||||
| 	manifest, err := manifests.Get(imh.Name, imh.Tag) | ||||
| 	manifests := imh.Repository.Manifests() | ||||
| 	manifest, err := manifests.Get(imh.Tag) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		imh.Errors.Push(v2.ErrorCodeManifestUnknown, err) | ||||
|  | @ -54,7 +54,7 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http | |||
| 
 | ||||
| // PutImageManifest validates and stores and image in the registry.
 | ||||
| func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http.Request) { | ||||
| 	manifests := imh.services.Manifests() | ||||
| 	manifests := imh.Repository.Manifests() | ||||
| 	dec := json.NewDecoder(r.Body) | ||||
| 
 | ||||
| 	var manifest manifest.SignedManifest | ||||
|  | @ -64,7 +64,7 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if err := manifests.Put(imh.Name, imh.Tag, &manifest); err != nil { | ||||
| 	if err := manifests.Put(imh.Tag, &manifest); err != nil { | ||||
| 		// TODO(stevvooe): These error handling switches really need to be
 | ||||
| 		// handled by an app global mapper.
 | ||||
| 		switch err := err.(type) { | ||||
|  | @ -96,8 +96,8 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http | |||
| 
 | ||||
| // DeleteImageManifest removes the image with the given tag from the registry.
 | ||||
| func (imh *imageManifestHandler) DeleteImageManifest(w http.ResponseWriter, r *http.Request) { | ||||
| 	manifests := imh.services.Manifests() | ||||
| 	if err := manifests.Delete(imh.Name, imh.Tag); err != nil { | ||||
| 	manifests := imh.Repository.Manifests() | ||||
| 	if err := manifests.Delete(imh.Tag); err != nil { | ||||
| 		switch err := err.(type) { | ||||
| 		case storage.ErrUnknownManifest: | ||||
| 			imh.Errors.Push(v2.ErrorCodeManifestUnknown, err) | ||||
|  |  | |||
|  | @ -42,9 +42,8 @@ type layerHandler struct { | |||
| // GetLayer fetches the binary data from backend storage returns it in the
 | ||||
| // response.
 | ||||
| func (lh *layerHandler) GetLayer(w http.ResponseWriter, r *http.Request) { | ||||
| 	layers := lh.services.Layers() | ||||
| 
 | ||||
| 	layer, err := layers.Fetch(lh.Name, lh.Digest) | ||||
| 	layers := lh.Repository.Layers() | ||||
| 	layer, err := layers.Fetch(lh.Digest) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		switch err := err.(type) { | ||||
|  |  | |||
|  | @ -43,6 +43,14 @@ func layerUploadDispatcher(ctx *Context, r *http.Request) http.Handler { | |||
| 		} | ||||
| 		luh.State = state | ||||
| 
 | ||||
| 		if state.Name != ctx.Repository.Name() { | ||||
| 			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 				ctx.log.Infof("mismatched repository name in upload state: %q != %q", state.Name, luh.Repository.Name()) | ||||
| 				w.WriteHeader(http.StatusBadRequest) | ||||
| 				luh.Errors.Push(v2.ErrorCodeBlobUploadInvalid, err) | ||||
| 			}) | ||||
| 		} | ||||
| 
 | ||||
| 		if state.UUID != luh.UUID { | ||||
| 			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 				ctx.log.Infof("mismatched uuid in upload state: %q != %q", state.UUID, luh.UUID) | ||||
|  | @ -51,8 +59,8 @@ func layerUploadDispatcher(ctx *Context, r *http.Request) http.Handler { | |||
| 			}) | ||||
| 		} | ||||
| 
 | ||||
| 		layers := ctx.services.Layers() | ||||
| 		upload, err := layers.Resume(luh.Name, luh.UUID) | ||||
| 		layers := ctx.Repository.Layers() | ||||
| 		upload, err := layers.Resume(luh.UUID) | ||||
| 		if err != nil { | ||||
| 			ctx.log.Errorf("error resolving upload: %v", err) | ||||
| 			if err == storage.ErrLayerUploadUnknown { | ||||
|  | @ -114,8 +122,8 @@ type layerUploadHandler struct { | |||
| // StartLayerUpload begins the layer upload process and allocates a server-
 | ||||
| // side upload session.
 | ||||
| func (luh *layerUploadHandler) StartLayerUpload(w http.ResponseWriter, r *http.Request) { | ||||
| 	layers := luh.services.Layers() | ||||
| 	upload, err := layers.Upload(luh.Name) | ||||
| 	layers := luh.Repository.Layers() | ||||
| 	upload, err := layers.Upload() | ||||
| 	if err != nil { | ||||
| 		w.WriteHeader(http.StatusInternalServerError) // Error conditions here?
 | ||||
| 		luh.Errors.Push(v2.ErrorCodeUnknown, err) | ||||
|  | @ -222,7 +230,7 @@ func (luh *layerUploadHandler) layerUploadResponse(w http.ResponseWriter, r *htt | |||
| 	} | ||||
| 
 | ||||
| 	// TODO(stevvooe): Need a better way to manage the upload state automatically.
 | ||||
| 	luh.State.Name = luh.Name | ||||
| 	luh.State.Name = luh.Repository.Name() | ||||
| 	luh.State.UUID = luh.Upload.UUID() | ||||
| 	luh.State.Offset = offset | ||||
| 	luh.State.StartedAt = luh.Upload.StartedAt() | ||||
|  |  | |||
|  | @ -33,14 +33,14 @@ type tagsAPIResponse struct { | |||
| // GetTags returns a json list of tags for a specific image name.
 | ||||
| func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) { | ||||
| 	defer r.Body.Close() | ||||
| 	manifests := th.services.Manifests() | ||||
| 	manifests := th.Repository.Manifests() | ||||
| 
 | ||||
| 	tags, err := manifests.Tags(th.Name) | ||||
| 	tags, err := manifests.Tags() | ||||
| 	if err != nil { | ||||
| 		switch err := err.(type) { | ||||
| 		case storage.ErrUnknownRepository: | ||||
| 			w.WriteHeader(404) | ||||
| 			th.Errors.Push(v2.ErrorCodeNameUnknown, map[string]string{"name": th.Name}) | ||||
| 			th.Errors.Push(v2.ErrorCodeNameUnknown, map[string]string{"name": th.Repository.Name()}) | ||||
| 		default: | ||||
| 			th.Errors.PushErr(err) | ||||
| 		} | ||||
|  | @ -51,7 +51,7 @@ func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) { | |||
| 
 | ||||
| 	enc := json.NewEncoder(w) | ||||
| 	if err := enc.Encode(tagsAPIResponse{ | ||||
| 		Name: th.Name, | ||||
| 		Name: th.Repository.Name(), | ||||
| 		Tags: tags, | ||||
| 	}); err != nil { | ||||
| 		th.Errors.PushErr(err) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue