github.com/ralexstokes/docker@v1.6.2/registry/service.go (about)

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