service.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package registry
  2. import (
  3. "github.com/docker/docker/engine"
  4. )
  5. // Service exposes registry capabilities in the standard Engine
  6. // interface. Once installed, it extends the engine with the
  7. // following calls:
  8. //
  9. // 'auth': Authenticate against the public registry
  10. // 'search': Search for images on the public registry
  11. // 'pull': Download images from any registry (TODO)
  12. // 'push': Upload images to any registry (TODO)
  13. type Service struct {
  14. Config *ServiceConfig
  15. }
  16. // NewService returns a new instance of Service ready to be
  17. // installed no an engine.
  18. func NewService(options *Options) *Service {
  19. return &Service{
  20. Config: NewServiceConfig(options),
  21. }
  22. }
  23. // Install installs registry capabilities to eng.
  24. func (s *Service) Install(eng *engine.Engine) error {
  25. eng.Register("auth", s.Auth)
  26. eng.Register("search", s.Search)
  27. eng.Register("resolve_repository", s.ResolveRepository)
  28. eng.Register("resolve_index", s.ResolveIndex)
  29. eng.Register("registry_config", s.GetRegistryConfig)
  30. return nil
  31. }
  32. // Auth contacts the public registry with the provided credentials,
  33. // and returns OK if authentication was sucessful.
  34. // It can be used to verify the validity of a client's credentials.
  35. func (s *Service) Auth(job *engine.Job) engine.Status {
  36. var authConfig = new(AuthConfig)
  37. job.GetenvJson("authConfig", authConfig)
  38. if authConfig.ServerAddress != "" {
  39. index, err := ResolveIndexInfo(job, authConfig.ServerAddress)
  40. if err != nil {
  41. return job.Error(err)
  42. }
  43. if !index.Official {
  44. endpoint, err := NewEndpoint(index)
  45. if err != nil {
  46. return job.Error(err)
  47. }
  48. authConfig.ServerAddress = endpoint.String()
  49. }
  50. }
  51. status, err := Login(authConfig, HTTPRequestFactory(nil))
  52. if err != nil {
  53. return job.Error(err)
  54. }
  55. job.Printf("%s\n", status)
  56. return engine.StatusOK
  57. }
  58. // Search queries the public registry for images matching the specified
  59. // search terms, and returns the results.
  60. //
  61. // Argument syntax: search TERM
  62. //
  63. // Option environment:
  64. // 'authConfig': json-encoded credentials to authenticate against the registry.
  65. // The search extends to images only accessible via the credentials.
  66. //
  67. // 'metaHeaders': extra HTTP headers to include in the request to the registry.
  68. // The headers should be passed as a json-encoded dictionary.
  69. //
  70. // Output:
  71. // Results are sent as a collection of structured messages (using engine.Table).
  72. // Each result is sent as a separate message.
  73. // Results are ordered by number of stars on the public registry.
  74. func (s *Service) Search(job *engine.Job) engine.Status {
  75. if n := len(job.Args); n != 1 {
  76. return job.Errorf("Usage: %s TERM", job.Name)
  77. }
  78. var (
  79. term = job.Args[0]
  80. metaHeaders = map[string][]string{}
  81. authConfig = &AuthConfig{}
  82. )
  83. job.GetenvJson("authConfig", authConfig)
  84. job.GetenvJson("metaHeaders", metaHeaders)
  85. repoInfo, err := ResolveRepositoryInfo(job, term)
  86. if err != nil {
  87. return job.Error(err)
  88. }
  89. // *TODO: Search multiple indexes.
  90. endpoint, err := repoInfo.GetEndpoint()
  91. if err != nil {
  92. return job.Error(err)
  93. }
  94. r, err := NewSession(authConfig, HTTPRequestFactory(metaHeaders), endpoint, true)
  95. if err != nil {
  96. return job.Error(err)
  97. }
  98. results, err := r.SearchRepositories(repoInfo.GetSearchTerm())
  99. if err != nil {
  100. return job.Error(err)
  101. }
  102. outs := engine.NewTable("star_count", 0)
  103. for _, result := range results.Results {
  104. out := &engine.Env{}
  105. out.Import(result)
  106. outs.Add(out)
  107. }
  108. outs.ReverseSort()
  109. if _, err := outs.WriteListTo(job.Stdout); err != nil {
  110. return job.Error(err)
  111. }
  112. return engine.StatusOK
  113. }
  114. // ResolveRepository splits a repository name into its components
  115. // and configuration of the associated registry.
  116. func (s *Service) ResolveRepository(job *engine.Job) engine.Status {
  117. var (
  118. reposName = job.Args[0]
  119. )
  120. repoInfo, err := s.Config.NewRepositoryInfo(reposName)
  121. if err != nil {
  122. return job.Error(err)
  123. }
  124. out := engine.Env{}
  125. err = out.SetJson("repository", repoInfo)
  126. if err != nil {
  127. return job.Error(err)
  128. }
  129. out.WriteTo(job.Stdout)
  130. return engine.StatusOK
  131. }
  132. // Convenience wrapper for calling resolve_repository Job from a running job.
  133. func ResolveRepositoryInfo(jobContext *engine.Job, reposName string) (*RepositoryInfo, error) {
  134. job := jobContext.Eng.Job("resolve_repository", reposName)
  135. env, err := job.Stdout.AddEnv()
  136. if err != nil {
  137. return nil, err
  138. }
  139. if err := job.Run(); err != nil {
  140. return nil, err
  141. }
  142. info := RepositoryInfo{}
  143. if err := env.GetJson("repository", &info); err != nil {
  144. return nil, err
  145. }
  146. return &info, nil
  147. }
  148. // ResolveIndex takes indexName and returns index info
  149. func (s *Service) ResolveIndex(job *engine.Job) engine.Status {
  150. var (
  151. indexName = job.Args[0]
  152. )
  153. index, err := s.Config.NewIndexInfo(indexName)
  154. if err != nil {
  155. return job.Error(err)
  156. }
  157. out := engine.Env{}
  158. err = out.SetJson("index", index)
  159. if err != nil {
  160. return job.Error(err)
  161. }
  162. out.WriteTo(job.Stdout)
  163. return engine.StatusOK
  164. }
  165. // Convenience wrapper for calling resolve_index Job from a running job.
  166. func ResolveIndexInfo(jobContext *engine.Job, indexName string) (*IndexInfo, error) {
  167. job := jobContext.Eng.Job("resolve_index", indexName)
  168. env, err := job.Stdout.AddEnv()
  169. if err != nil {
  170. return nil, err
  171. }
  172. if err := job.Run(); err != nil {
  173. return nil, err
  174. }
  175. info := IndexInfo{}
  176. if err := env.GetJson("index", &info); err != nil {
  177. return nil, err
  178. }
  179. return &info, nil
  180. }
  181. // GetRegistryConfig returns current registry configuration.
  182. func (s *Service) GetRegistryConfig(job *engine.Job) engine.Status {
  183. out := engine.Env{}
  184. err := out.SetJson("config", s.Config)
  185. if err != nil {
  186. return job.Error(err)
  187. }
  188. out.WriteTo(job.Stdout)
  189. return engine.StatusOK
  190. }