| package registry |
| |
| import ( |
| log "github.com/Sirupsen/logrus" |
| "github.com/docker/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 |
| // 'pull': Download images from any registry (TODO) |
| // 'push': Upload images to any registry (TODO) |
| type Service struct { |
| Config *ServiceConfig |
| } |
| |
| // NewService returns a new instance of Service ready to be |
| // installed no an engine. |
| func NewService(options *Options) *Service { |
| return &Service{ |
| Config: NewServiceConfig(options), |
| } |
| } |
| |
| // Install installs registry capabilities to eng. |
| func (s *Service) Install(eng *engine.Engine) error { |
| eng.Register("auth", s.Auth) |
| eng.Register("search", s.Search) |
| eng.Register("resolve_repository", s.ResolveRepository) |
| eng.Register("resolve_index", s.ResolveIndex) |
| eng.Register("registry_config", s.GetRegistryConfig) |
| 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 ( |
| authConfig = new(AuthConfig) |
| endpoint *Endpoint |
| index *IndexInfo |
| status string |
| err error |
| ) |
| |
| job.GetenvJson("authConfig", authConfig) |
| |
| addr := authConfig.ServerAddress |
| if addr == "" { |
| // Use the official registry address if not specified. |
| addr = IndexServerAddress() |
| } |
| |
| if index, err = ResolveIndexInfo(job, addr); err != nil { |
| return job.Error(err) |
| } |
| |
| if endpoint, err = NewEndpoint(index); err != nil { |
| log.Errorf("unable to get new registry endpoint: %s", err) |
| return job.Error(err) |
| } |
| |
| authConfig.ServerAddress = endpoint.String() |
| |
| if status, err = Login(authConfig, endpoint, HTTPRequestFactory(nil)); err != nil { |
| log.Errorf("unable to login against registry endpoint %s: %s", endpoint, err) |
| return job.Error(err) |
| } |
| |
| log.Infof("successful registry login for endpoint %s: %s", endpoint, status) |
| job.Printf("%s\n", status) |
| |
| return engine.StatusOK |
| } |
| |
| // Search queries the public registry for images matching the specified |
| // search terms, and returns the results. |
| // |
| // Argument syntax: search TERM |
| // |
| // Option environment: |
| // 'authConfig': json-encoded credentials to authenticate against the registry. |
| // The search extends to images only accessible via the credentials. |
| // |
| // 'metaHeaders': extra HTTP headers to include in the request to the registry. |
| // The headers should be passed as a json-encoded dictionary. |
| // |
| // Output: |
| // Results are sent as a collection of structured messages (using engine.Table). |
| // Each result is sent as a separate message. |
| // Results are ordered by number of stars on the public registry. |
| func (s *Service) Search(job *engine.Job) engine.Status { |
| if n := len(job.Args); n != 1 { |
| return job.Errorf("Usage: %s TERM", job.Name) |
| } |
| var ( |
| term = job.Args[0] |
| metaHeaders = map[string][]string{} |
| authConfig = &AuthConfig{} |
| ) |
| job.GetenvJson("authConfig", authConfig) |
| job.GetenvJson("metaHeaders", metaHeaders) |
| |
| repoInfo, err := ResolveRepositoryInfo(job, term) |
| if err != nil { |
| return job.Error(err) |
| } |
| // *TODO: Search multiple indexes. |
| endpoint, err := repoInfo.GetEndpoint() |
| if err != nil { |
| return job.Error(err) |
| } |
| r, err := NewSession(authConfig, HTTPRequestFactory(metaHeaders), endpoint, true) |
| if err != nil { |
| return job.Error(err) |
| } |
| results, err := r.SearchRepositories(repoInfo.GetSearchTerm()) |
| if err != nil { |
| return job.Error(err) |
| } |
| outs := engine.NewTable("star_count", 0) |
| for _, result := range results.Results { |
| out := &engine.Env{} |
| out.Import(result) |
| outs.Add(out) |
| } |
| outs.ReverseSort() |
| if _, err := outs.WriteListTo(job.Stdout); err != nil { |
| return job.Error(err) |
| } |
| return engine.StatusOK |
| } |
| |
| // ResolveRepository splits a repository name into its components |
| // and configuration of the associated registry. |
| func (s *Service) ResolveRepository(job *engine.Job) engine.Status { |
| var ( |
| reposName = job.Args[0] |
| ) |
| |
| repoInfo, err := s.Config.NewRepositoryInfo(reposName) |
| if err != nil { |
| return job.Error(err) |
| } |
| |
| out := engine.Env{} |
| err = out.SetJson("repository", repoInfo) |
| if err != nil { |
| return job.Error(err) |
| } |
| out.WriteTo(job.Stdout) |
| |
| return engine.StatusOK |
| } |
| |
| // Convenience wrapper for calling resolve_repository Job from a running job. |
| func ResolveRepositoryInfo(jobContext *engine.Job, reposName string) (*RepositoryInfo, error) { |
| job := jobContext.Eng.Job("resolve_repository", reposName) |
| env, err := job.Stdout.AddEnv() |
| if err != nil { |
| return nil, err |
| } |
| if err := job.Run(); err != nil { |
| return nil, err |
| } |
| info := RepositoryInfo{} |
| if err := env.GetJson("repository", &info); err != nil { |
| return nil, err |
| } |
| return &info, nil |
| } |
| |
| // ResolveIndex takes indexName and returns index info |
| func (s *Service) ResolveIndex(job *engine.Job) engine.Status { |
| var ( |
| indexName = job.Args[0] |
| ) |
| |
| index, err := s.Config.NewIndexInfo(indexName) |
| if err != nil { |
| return job.Error(err) |
| } |
| |
| out := engine.Env{} |
| err = out.SetJson("index", index) |
| if err != nil { |
| return job.Error(err) |
| } |
| out.WriteTo(job.Stdout) |
| |
| return engine.StatusOK |
| } |
| |
| // Convenience wrapper for calling resolve_index Job from a running job. |
| func ResolveIndexInfo(jobContext *engine.Job, indexName string) (*IndexInfo, error) { |
| job := jobContext.Eng.Job("resolve_index", indexName) |
| env, err := job.Stdout.AddEnv() |
| if err != nil { |
| return nil, err |
| } |
| if err := job.Run(); err != nil { |
| return nil, err |
| } |
| info := IndexInfo{} |
| if err := env.GetJson("index", &info); err != nil { |
| return nil, err |
| } |
| return &info, nil |
| } |
| |
| // GetRegistryConfig returns current registry configuration. |
| func (s *Service) GetRegistryConfig(job *engine.Job) engine.Status { |
| out := engine.Env{} |
| err := out.SetJson("config", s.Config) |
| if err != nil { |
| return job.Error(err) |
| } |
| out.WriteTo(job.Stdout) |
| |
| return engine.StatusOK |
| } |