From 3d605683b3d272982399635a55ee81b2a7535e81 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Sun, 27 Apr 2014 15:06:09 -0700 Subject: [PATCH] Move 'auth' to the registry subsystem This is the first step towards separating the registry subsystem from the deprecated `Server` object. * New service `github.com/dotcloud/docker/registry/Service` * The service is installed by default in `builtins` * The service only exposes `auth` for now... * ...Soon to be followed by `pull`, `push` and `search`. Docker-DCO-1.1-Signed-off-by: Solomon Hykes (github: shykes) --- builtins/builtins.go | 4 +++ registry/registry.go | 39 ++++++++++++++++++++++++++ registry/service.go | 54 ++++++++++++++++++++++++++++++++++++ server/server.go | 66 ++------------------------------------------ 4 files changed, 100 insertions(+), 63 deletions(-) create mode 100644 registry/service.go diff --git a/builtins/builtins.go b/builtins/builtins.go index 374bd48701..bd3b33d0d3 100644 --- a/builtins/builtins.go +++ b/builtins/builtins.go @@ -4,12 +4,16 @@ import ( api "github.com/dotcloud/docker/api/server" "github.com/dotcloud/docker/daemon/networkdriver/bridge" "github.com/dotcloud/docker/engine" + "github.com/dotcloud/docker/registry" "github.com/dotcloud/docker/server" ) func Register(eng *engine.Engine) { daemon(eng) remote(eng) + // FIXME: engine.Installer.Install can fail. These errors + // should be passed up. + registry.NewService().Install(eng) } // remote: a RESTful api for cross-docker communication diff --git a/registry/registry.go b/registry/registry.go index 1bd73cdeb5..55154e364b 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -13,10 +13,12 @@ import ( "net/http/cookiejar" "net/url" "regexp" + "runtime" "strconv" "strings" "time" + "github.com/dotcloud/docker/dockerversion" "github.com/dotcloud/docker/utils" ) @@ -757,3 +759,40 @@ func NewRegistry(authConfig *AuthConfig, factory *utils.HTTPRequestFactory, inde r.reqFactory = factory return r, nil } + +func HTTPRequestFactory(metaHeaders map[string][]string) *utils.HTTPRequestFactory { + // FIXME: this replicates the 'info' job. + httpVersion := make([]utils.VersionInfo, 0, 4) + httpVersion = append(httpVersion, &simpleVersionInfo{"docker", dockerversion.VERSION}) + httpVersion = append(httpVersion, &simpleVersionInfo{"go", runtime.Version()}) + httpVersion = append(httpVersion, &simpleVersionInfo{"git-commit", dockerversion.GITCOMMIT}) + if kernelVersion, err := utils.GetKernelVersion(); err == nil { + httpVersion = append(httpVersion, &simpleVersionInfo{"kernel", kernelVersion.String()}) + } + httpVersion = append(httpVersion, &simpleVersionInfo{"os", runtime.GOOS}) + httpVersion = append(httpVersion, &simpleVersionInfo{"arch", runtime.GOARCH}) + ud := utils.NewHTTPUserAgentDecorator(httpVersion...) + md := &utils.HTTPMetaHeadersDecorator{ + Headers: metaHeaders, + } + factory := utils.NewHTTPRequestFactory(ud, md) + return factory +} + +// simpleVersionInfo is a simple implementation of +// the interface VersionInfo, which is used +// to provide version information for some product, +// component, etc. It stores the product name and the version +// in string and returns them on calls to Name() and Version(). +type simpleVersionInfo struct { + name string + version string +} + +func (v *simpleVersionInfo) Name() string { + return v.name +} + +func (v *simpleVersionInfo) Version() string { + return v.version +} diff --git a/registry/service.go b/registry/service.go new file mode 100644 index 0000000000..530a7f7afe --- /dev/null +++ b/registry/service.go @@ -0,0 +1,54 @@ +package registry + +import ( + "github.com/dotcloud/docker/engine" +) + +// Service exposes registry capabilities in the standard Engine +// interface. Once installed, it extends the engine with the +// following calls: +// +// 'auth': Authenticate against the public registry +// 'search': Search for images on the public registry (TODO) +// 'pull': Download images from any registry (TODO) +// 'push': Upload images to any registry (TODO) +type Service struct { +} + +// NewService returns a new instance of Service ready to be +// installed no an engine. +func NewService() *Service { + return &Service{} +} + +// Install installs registry capabilities to eng. +func (s *Service) Install(eng *engine.Engine) error { + eng.Register("auth", s.Auth) + return nil +} + +// Auth contacts the public registry with the provided credentials, +// and returns OK if authentication was sucessful. +// It can be used to verify the validity of a client's credentials. +func (s *Service) Auth(job *engine.Job) engine.Status { + var ( + err error + authConfig = &AuthConfig{} + ) + + job.GetenvJson("authConfig", authConfig) + // TODO: this is only done here because auth and registry need to be merged into one pkg + if addr := authConfig.ServerAddress; addr != "" && addr != IndexServerAddress() { + addr, err = ExpandAndVerifyRegistryUrl(addr) + if err != nil { + return job.Error(err) + } + authConfig.ServerAddress = addr + } + status, err := Login(authConfig, HTTPRequestFactory(nil)) + if err != nil { + return job.Error(err) + } + job.Printf("%s\n", status) + return engine.StatusOK +} diff --git a/server/server.go b/server/server.go index f55107d3bd..16f9129311 100644 --- a/server/server.go +++ b/server/server.go @@ -139,7 +139,6 @@ func InitServer(job *engine.Job) engine.Status { "events": srv.Events, "push": srv.ImagePush, "containers": srv.Containers, - "auth": srv.Auth, } { if err := job.Eng.Register(name, handler); err != nil { return job.Error(err) @@ -148,24 +147,6 @@ func InitServer(job *engine.Job) engine.Status { return engine.StatusOK } -// simpleVersionInfo is a simple implementation of -// the interface VersionInfo, which is used -// to provide version information for some product, -// component, etc. It stores the product name and the version -// in string and returns them on calls to Name() and Version(). -type simpleVersionInfo struct { - name string - version string -} - -func (v *simpleVersionInfo) Name() string { - return v.name -} - -func (v *simpleVersionInfo) Version() string { - return v.version -} - // ContainerKill send signal to the container // If no signal is given (sig 0), then Kill with SIGKILL and wait // for the container to exit. @@ -215,29 +196,6 @@ func (srv *Server) ContainerKill(job *engine.Job) engine.Status { return engine.StatusOK } -func (srv *Server) Auth(job *engine.Job) engine.Status { - var ( - err error - authConfig = ®istry.AuthConfig{} - ) - - job.GetenvJson("authConfig", authConfig) - // TODO: this is only done here because auth and registry need to be merged into one pkg - if addr := authConfig.ServerAddress; addr != "" && addr != registry.IndexServerAddress() { - addr, err = registry.ExpandAndVerifyRegistryUrl(addr) - if err != nil { - return job.Error(err) - } - authConfig.ServerAddress = addr - } - status, err := registry.Login(authConfig, srv.HTTPRequestFactory(nil)) - if err != nil { - return job.Error(err) - } - job.Printf("%s\n", status) - return engine.StatusOK -} - func (srv *Server) Events(job *engine.Job) engine.Status { if len(job.Args) != 1 { return job.Errorf("Usage: %s FROM", job.Name) @@ -654,7 +612,7 @@ func (srv *Server) ImagesSearch(job *engine.Job) engine.Status { job.GetenvJson("authConfig", authConfig) job.GetenvJson("metaHeaders", metaHeaders) - r, err := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), registry.IndexServerAddress()) + r, err := registry.NewRegistry(authConfig, registry.HTTPRequestFactory(metaHeaders), registry.IndexServerAddress()) if err != nil { return job.Error(err) } @@ -1457,7 +1415,7 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status { return job.Error(err) } - r, err := registry.NewRegistry(&authConfig, srv.HTTPRequestFactory(metaHeaders), endpoint) + r, err := registry.NewRegistry(&authConfig, registry.HTTPRequestFactory(metaHeaders), endpoint) if err != nil { return job.Error(err) } @@ -1680,7 +1638,7 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status { } img, err := srv.daemon.Graph().Get(localName) - r, err2 := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), endpoint) + r, err2 := registry.NewRegistry(authConfig, registry.HTTPRequestFactory(metaHeaders), endpoint) if err2 != nil { return job.Error(err2) } @@ -2558,24 +2516,6 @@ func NewServer(eng *engine.Engine, config *daemonconfig.Config) (*Server, error) return srv, nil } -func (srv *Server) HTTPRequestFactory(metaHeaders map[string][]string) *utils.HTTPRequestFactory { - httpVersion := make([]utils.VersionInfo, 0, 4) - httpVersion = append(httpVersion, &simpleVersionInfo{"docker", dockerversion.VERSION}) - httpVersion = append(httpVersion, &simpleVersionInfo{"go", goruntime.Version()}) - httpVersion = append(httpVersion, &simpleVersionInfo{"git-commit", dockerversion.GITCOMMIT}) - if kernelVersion, err := utils.GetKernelVersion(); err == nil { - httpVersion = append(httpVersion, &simpleVersionInfo{"kernel", kernelVersion.String()}) - } - httpVersion = append(httpVersion, &simpleVersionInfo{"os", goruntime.GOOS}) - httpVersion = append(httpVersion, &simpleVersionInfo{"arch", goruntime.GOARCH}) - ud := utils.NewHTTPUserAgentDecorator(httpVersion...) - md := &utils.HTTPMetaHeadersDecorator{ - Headers: metaHeaders, - } - factory := utils.NewHTTPRequestFactory(ud, md) - return factory -} - func (srv *Server) LogEvent(action, id, from string) *utils.JSONMessage { now := time.Now().UTC().Unix() jm := utils.JSONMessage{Status: action, ID: id, From: from, Time: now}