Browse code

Remove jobs from registry.Service

This makes `registry.Service` a first class type and does not use jobs
to interact with this type.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Michael Crosby authored on 2015/04/01 08:21:37
Showing 13 changed files
... ...
@@ -49,6 +49,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
49 49
 	if _, err := outs.ReadListFrom(rawBody); err != nil {
50 50
 		return err
51 51
 	}
52
+	outs.ReverseSort()
52 53
 	w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
53 54
 	fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n")
54 55
 	for _, out := range outs.Data {
... ...
@@ -8,7 +8,6 @@ import (
8 8
 	"encoding/json"
9 9
 	"fmt"
10 10
 	"io"
11
-	"io/ioutil"
12 11
 	"net"
13 12
 	"net/http"
14 13
 	"os"
... ...
@@ -21,6 +20,7 @@ import (
21 21
 	"github.com/Sirupsen/logrus"
22 22
 	"github.com/docker/docker/api"
23 23
 	"github.com/docker/docker/api/types"
24
+	"github.com/docker/docker/daemon"
24 25
 	"github.com/docker/docker/daemon/networkdriver/bridge"
25 26
 	"github.com/docker/docker/engine"
26 27
 	"github.com/docker/docker/pkg/parsers"
... ...
@@ -169,29 +169,25 @@ func getBoolParam(value string) (bool, error) {
169 169
 	return ret, nil
170 170
 }
171 171
 
172
+func getDaemon(eng *engine.Engine) *daemon.Daemon {
173
+	return eng.HackGetGlobalVar("httpapi.daemon").(*daemon.Daemon)
174
+}
175
+
172 176
 func postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
173
-	var (
174
-		authConfig, err = ioutil.ReadAll(r.Body)
175
-		job             = eng.Job("auth")
176
-		stdoutBuffer    = bytes.NewBuffer(nil)
177
-	)
177
+	var config *registry.AuthConfig
178
+	err := json.NewDecoder(r.Body).Decode(&config)
179
+	r.Body.Close()
178 180
 	if err != nil {
179 181
 		return err
180 182
 	}
181
-	job.Setenv("authConfig", string(authConfig))
182
-	job.Stdout.Add(stdoutBuffer)
183
-	if err = job.Run(); err != nil {
183
+	d := getDaemon(eng)
184
+	status, err := d.RegistryService.Auth(config)
185
+	if err != nil {
184 186
 		return err
185 187
 	}
186
-	if status := engine.Tail(stdoutBuffer, 1); status != "" {
187
-		var env engine.Env
188
-		env.Set("Status", status)
189
-		return writeJSON(w, http.StatusOK, &types.AuthResponse{
190
-			Status: status,
191
-		})
192
-	}
193
-	w.WriteHeader(http.StatusNoContent)
194
-	return nil
188
+	return writeJSON(w, http.StatusOK, &types.AuthResponse{
189
+		Status: status,
190
+	})
195 191
 }
196 192
 
197 193
 func getVersion(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
... ...
@@ -601,31 +597,30 @@ func getImagesSearch(eng *engine.Engine, version version.Version, w http.Respons
601 601
 		return err
602 602
 	}
603 603
 	var (
604
+		config      *registry.AuthConfig
604 605
 		authEncoded = r.Header.Get("X-Registry-Auth")
605
-		authConfig  = &registry.AuthConfig{}
606
-		metaHeaders = map[string][]string{}
606
+		headers     = map[string][]string{}
607 607
 	)
608 608
 
609 609
 	if authEncoded != "" {
610 610
 		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
611
-		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
611
+		if err := json.NewDecoder(authJson).Decode(&config); err != nil {
612 612
 			// for a search it is not an error if no auth was given
613 613
 			// to increase compatibility with the existing api it is defaulting to be empty
614
-			authConfig = &registry.AuthConfig{}
614
+			config = &registry.AuthConfig{}
615 615
 		}
616 616
 	}
617 617
 	for k, v := range r.Header {
618 618
 		if strings.HasPrefix(k, "X-Meta-") {
619
-			metaHeaders[k] = v
619
+			headers[k] = v
620 620
 		}
621 621
 	}
622
-
623
-	var job = eng.Job("search", r.Form.Get("term"))
624
-	job.SetenvJson("metaHeaders", metaHeaders)
625
-	job.SetenvJson("authConfig", authConfig)
626
-	streamJSON(job, w, false)
627
-
628
-	return job.Run()
622
+	d := getDaemon(eng)
623
+	query, err := d.RegistryService.Search(r.Form.Get("term"), config, headers)
624
+	if err != nil {
625
+		return err
626
+	}
627
+	return json.NewEncoder(w).Encode(query.Results)
629 628
 }
630 629
 
631 630
 func postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
... ...
@@ -34,7 +34,6 @@ import (
34 34
 	"github.com/docker/docker/pkg/system"
35 35
 	"github.com/docker/docker/pkg/tarsum"
36 36
 	"github.com/docker/docker/pkg/urlutil"
37
-	"github.com/docker/docker/registry"
38 37
 	"github.com/docker/docker/runconfig"
39 38
 	"github.com/docker/docker/utils"
40 39
 )
... ...
@@ -439,7 +438,7 @@ func (b *Builder) pullImage(name string) (*imagepkg.Image, error) {
439 439
 	pullRegistryAuth := b.AuthConfig
440 440
 	if len(b.AuthConfigFile.Configs) > 0 {
441 441
 		// The request came with a full auth config file, we prefer to use that
442
-		repoInfo, err := registry.ResolveRepositoryInfo(job, remote)
442
+		repoInfo, err := b.Daemon.RegistryService.ResolveRepository(remote)
443 443
 		if err != nil {
444 444
 			return nil, err
445 445
 		}
... ...
@@ -40,6 +40,7 @@ import (
40 40
 	"github.com/docker/docker/pkg/stringid"
41 41
 	"github.com/docker/docker/pkg/sysinfo"
42 42
 	"github.com/docker/docker/pkg/truncindex"
43
+	"github.com/docker/docker/registry"
43 44
 	"github.com/docker/docker/runconfig"
44 45
 	"github.com/docker/docker/trust"
45 46
 	"github.com/docker/docker/utils"
... ...
@@ -107,6 +108,7 @@ type Daemon struct {
107 107
 	trustStore       *trust.TrustStore
108 108
 	statsCollector   *statsCollector
109 109
 	defaultLogConfig runconfig.LogConfig
110
+	RegistryService  *registry.Service
110 111
 }
111 112
 
112 113
 // Install installs daemon capabilities to eng.
... ...
@@ -793,15 +795,15 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
793 793
 }
794 794
 
795 795
 // FIXME: harmonize with NewGraph()
796
-func NewDaemon(config *Config, eng *engine.Engine) (*Daemon, error) {
797
-	daemon, err := NewDaemonFromDirectory(config, eng)
796
+func NewDaemon(config *Config, eng *engine.Engine, registryService *registry.Service) (*Daemon, error) {
797
+	daemon, err := NewDaemonFromDirectory(config, eng, registryService)
798 798
 	if err != nil {
799 799
 		return nil, err
800 800
 	}
801 801
 	return daemon, nil
802 802
 }
803 803
 
804
-func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) {
804
+func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService *registry.Service) (*Daemon, error) {
805 805
 	if config.Mtu == 0 {
806 806
 		config.Mtu = getDefaultNetworkMtu()
807 807
 	}
... ...
@@ -931,7 +933,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
931 931
 	}
932 932
 
933 933
 	logrus.Debug("Creating repository list")
934
-	repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g, trustKey)
934
+	repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g, trustKey, registryService)
935 935
 	if err != nil {
936 936
 		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
937 937
 	}
... ...
@@ -1022,6 +1024,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
1022 1022
 		trustStore:       t,
1023 1023
 		statsCollector:   newStatsCollector(1 * time.Second),
1024 1024
 		defaultLogConfig: config.LogConfig,
1025
+		RegistryService:  registryService,
1025 1026
 	}
1026 1027
 
1027 1028
 	eng.OnShutdown(func() {
... ...
@@ -56,15 +56,6 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) error {
56 56
 	if err := cjob.Run(); err != nil {
57 57
 		return err
58 58
 	}
59
-	registryJob := job.Eng.Job("registry_config")
60
-	registryEnv, _ := registryJob.Stdout.AddEnv()
61
-	if err := registryJob.Run(); err != nil {
62
-		return err
63
-	}
64
-	registryConfig := registry.ServiceConfig{}
65
-	if err := registryEnv.GetJson("config", &registryConfig); err != nil {
66
-		return err
67
-	}
68 59
 	v := &engine.Env{}
69 60
 	v.SetJson("ID", daemon.ID)
70 61
 	v.SetInt("Containers", len(daemon.List()))
... ...
@@ -83,7 +74,7 @@ func (daemon *Daemon) CmdInfo(job *engine.Job) error {
83 83
 	v.Set("KernelVersion", kernelVersion)
84 84
 	v.Set("OperatingSystem", operatingSystem)
85 85
 	v.Set("IndexServerAddress", registry.IndexServerAddress())
86
-	v.SetJson("RegistryConfig", registryConfig)
86
+	v.SetJson("RegistryConfig", daemon.RegistryService.Config)
87 87
 	v.Set("InitSha1", dockerversion.INITSHA1)
88 88
 	v.Set("InitPath", initPath)
89 89
 	v.SetInt("NCPU", runtime.NumCPU())
... ...
@@ -98,17 +98,13 @@ func mainDaemon() {
98 98
 		logrus.Fatal(err)
99 99
 	}
100 100
 
101
-	// load registry service
102
-	if err := registry.NewService(registryCfg).Install(eng); err != nil {
103
-		logrus.Fatal(err)
104
-	}
105
-
101
+	registryService := registry.NewService(registryCfg)
106 102
 	// load the daemon in the background so we can immediately start
107 103
 	// the http api so that connections don't fail while the daemon
108 104
 	// is booting
109 105
 	daemonInitWait := make(chan error)
110 106
 	go func() {
111
-		d, err := daemon.NewDaemon(daemonCfg, eng)
107
+		d, err := daemon.NewDaemon(daemonCfg, eng, registryService)
112 108
 		if err != nil {
113 109
 			daemonInitWait <- err
114 110
 			return
... ...
@@ -35,7 +35,7 @@ func (s *TagStore) CmdPull(job *engine.Job) error {
35 35
 	)
36 36
 
37 37
 	// Resolve the Repository name from fqn to RepositoryInfo
38
-	repoInfo, err := registry.ResolveRepositoryInfo(job, localName)
38
+	repoInfo, err := s.registryService.ResolveRepository(localName)
39 39
 	if err != nil {
40 40
 		return err
41 41
 	}
... ...
@@ -498,7 +498,7 @@ func (s *TagStore) CmdPush(job *engine.Job) error {
498 498
 	)
499 499
 
500 500
 	// Resolve the Repository name from fqn to RepositoryInfo
501
-	repoInfo, err := registry.ResolveRepositoryInfo(job, localName)
501
+	repoInfo, err := s.registryService.ResolveRepository(localName)
502 502
 	if err != nil {
503 503
 		return err
504 504
 	}
... ...
@@ -36,8 +36,9 @@ type TagStore struct {
36 36
 	sync.Mutex
37 37
 	// FIXME: move push/pull-related fields
38 38
 	// to a helper type
39
-	pullingPool map[string]chan struct{}
40
-	pushingPool map[string]chan struct{}
39
+	pullingPool     map[string]chan struct{}
40
+	pushingPool     map[string]chan struct{}
41
+	registryService *registry.Service
41 42
 }
42 43
 
43 44
 type Repository map[string]string
... ...
@@ -60,19 +61,20 @@ func (r Repository) Contains(u Repository) bool {
60 60
 	return true
61 61
 }
62 62
 
63
-func NewTagStore(path string, graph *Graph, key libtrust.PrivateKey) (*TagStore, error) {
63
+func NewTagStore(path string, graph *Graph, key libtrust.PrivateKey, registryService *registry.Service) (*TagStore, error) {
64 64
 	abspath, err := filepath.Abs(path)
65 65
 	if err != nil {
66 66
 		return nil, err
67 67
 	}
68 68
 
69 69
 	store := &TagStore{
70
-		path:         abspath,
71
-		graph:        graph,
72
-		trustKey:     key,
73
-		Repositories: make(map[string]Repository),
74
-		pullingPool:  make(map[string]chan struct{}),
75
-		pushingPool:  make(map[string]chan struct{}),
70
+		path:            abspath,
71
+		graph:           graph,
72
+		trustKey:        key,
73
+		Repositories:    make(map[string]Repository),
74
+		pullingPool:     make(map[string]chan struct{}),
75
+		pushingPool:     make(map[string]chan struct{}),
76
+		registryService: registryService,
76 77
 	}
77 78
 	// Load the json file if it exists, otherwise create it.
78 79
 	if err := store.reload(); os.IsNotExist(err) {
... ...
@@ -59,7 +59,7 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
59 59
 	if err != nil {
60 60
 		t.Fatal(err)
61 61
 	}
62
-	store, err := NewTagStore(path.Join(root, "tags"), graph, nil)
62
+	store, err := NewTagStore(path.Join(root, "tags"), graph, nil, nil)
63 63
 	if err != nil {
64 64
 		t.Fatal(err)
65 65
 	}
... ...
@@ -177,10 +177,6 @@ func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine {
177 177
 	if err := builtins.Register(eng); err != nil {
178 178
 		t.Fatal(err)
179 179
 	}
180
-	// load registry service
181
-	if err := registry.NewService(nil).Install(eng); err != nil {
182
-		t.Fatal(err)
183
-	}
184 180
 
185 181
 	// (This is manually copied and modified from main() until we have a more generic plugin system)
186 182
 	cfg := &daemon.Config{
... ...
@@ -193,7 +189,7 @@ func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine {
193 193
 		TrustKeyPath:                filepath.Join(root, "key.json"),
194 194
 		LogConfig:                   runconfig.LogConfig{Type: "json-file"},
195 195
 	}
196
-	d, err := daemon.NewDaemon(cfg, eng)
196
+	d, err := daemon.NewDaemon(cfg, eng, registry.NewService(nil))
197 197
 	if err != nil {
198 198
 		t.Fatal(err)
199 199
 	}
... ...
@@ -230,7 +230,6 @@ func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestd
230 230
 	if registryEndpoint.Version == APIVersion2 {
231 231
 		return loginV2(authConfig, registryEndpoint, factory)
232 232
 	}
233
-
234 233
 	return loginV1(authConfig, registryEndpoint, factory)
235 234
 }
236 235
 
... ...
@@ -1,20 +1,5 @@
1 1
 package registry
2 2
 
3
-import (
4
-	"fmt"
5
-
6
-	"github.com/Sirupsen/logrus"
7
-	"github.com/docker/docker/engine"
8
-)
9
-
10
-// Service exposes registry capabilities in the standard Engine
11
-// interface. Once installed, it extends the engine with the
12
-// following calls:
13
-//
14
-//  'auth': Authenticate against the public registry
15
-//  'search': Search for images on the public registry
16
-//  'pull': Download images from any registry (TODO)
17
-//  'push': Upload images to any registry (TODO)
18 3
 type Service struct {
19 4
 	Config *ServiceConfig
20 5
 }
... ...
@@ -27,201 +12,53 @@ func NewService(options *Options) *Service {
27 27
 	}
28 28
 }
29 29
 
30
-// Install installs registry capabilities to eng.
31
-func (s *Service) Install(eng *engine.Engine) error {
32
-	eng.Register("auth", s.Auth)
33
-	eng.Register("search", s.Search)
34
-	eng.Register("resolve_repository", s.ResolveRepository)
35
-	eng.Register("resolve_index", s.ResolveIndex)
36
-	eng.Register("registry_config", s.GetRegistryConfig)
37
-	return nil
38
-}
39
-
40 30
 // Auth contacts the public registry with the provided credentials,
41 31
 // and returns OK if authentication was sucessful.
42 32
 // It can be used to verify the validity of a client's credentials.
43
-func (s *Service) Auth(job *engine.Job) error {
44
-	var (
45
-		authConfig = new(AuthConfig)
46
-		endpoint   *Endpoint
47
-		index      *IndexInfo
48
-		status     string
49
-		err        error
50
-	)
51
-
52
-	job.GetenvJson("authConfig", authConfig)
53
-
33
+func (s *Service) Auth(authConfig *AuthConfig) (string, error) {
54 34
 	addr := authConfig.ServerAddress
55 35
 	if addr == "" {
56 36
 		// Use the official registry address if not specified.
57 37
 		addr = IndexServerAddress()
58 38
 	}
59
-
60
-	if index, err = ResolveIndexInfo(job, addr); err != nil {
61
-		return err
39
+	index, err := s.ResolveIndex(addr)
40
+	if err != nil {
41
+		return "", err
62 42
 	}
63
-
64
-	if endpoint, err = NewEndpoint(index); err != nil {
65
-		logrus.Errorf("unable to get new registry endpoint: %s", err)
66
-		return err
43
+	endpoint, err := NewEndpoint(index)
44
+	if err != nil {
45
+		return "", err
67 46
 	}
68
-
69 47
 	authConfig.ServerAddress = endpoint.String()
70
-
71
-	if status, err = Login(authConfig, endpoint, HTTPRequestFactory(nil)); err != nil {
72
-		logrus.Errorf("unable to login against registry endpoint %s: %s", endpoint, err)
73
-		return err
74
-	}
75
-
76
-	logrus.Infof("successful registry login for endpoint %s: %s", endpoint, status)
77
-	job.Printf("%s\n", status)
78
-
79
-	return nil
48
+	return Login(authConfig, endpoint, HTTPRequestFactory(nil))
80 49
 }
81 50
 
82 51
 // Search queries the public registry for images matching the specified
83 52
 // search terms, and returns the results.
84
-//
85
-// Argument syntax: search TERM
86
-//
87
-// Option environment:
88
-//	'authConfig': json-encoded credentials to authenticate against the registry.
89
-//		The search extends to images only accessible via the credentials.
90
-//
91
-//	'metaHeaders': extra HTTP headers to include in the request to the registry.
92
-//		The headers should be passed as a json-encoded dictionary.
93
-//
94
-// Output:
95
-//	Results are sent as a collection of structured messages (using engine.Table).
96
-//	Each result is sent as a separate message.
97
-//	Results are ordered by number of stars on the public registry.
98
-func (s *Service) Search(job *engine.Job) error {
99
-	if n := len(job.Args); n != 1 {
100
-		return fmt.Errorf("Usage: %s TERM", job.Name)
101
-	}
102
-	var (
103
-		term        = job.Args[0]
104
-		metaHeaders = map[string][]string{}
105
-		authConfig  = &AuthConfig{}
106
-	)
107
-	job.GetenvJson("authConfig", authConfig)
108
-	job.GetenvJson("metaHeaders", metaHeaders)
109
-
110
-	repoInfo, err := ResolveRepositoryInfo(job, term)
53
+func (s *Service) Search(term string, authConfig *AuthConfig, headers map[string][]string) (*SearchResults, error) {
54
+	repoInfo, err := s.ResolveRepository(term)
111 55
 	if err != nil {
112
-		return err
56
+		return nil, err
113 57
 	}
114 58
 	// *TODO: Search multiple indexes.
115 59
 	endpoint, err := repoInfo.GetEndpoint()
116 60
 	if err != nil {
117
-		return err
118
-	}
119
-	r, err := NewSession(authConfig, HTTPRequestFactory(metaHeaders), endpoint, true)
120
-	if err != nil {
121
-		return err
61
+		return nil, err
122 62
 	}
123
-	results, err := r.SearchRepositories(repoInfo.GetSearchTerm())
63
+	r, err := NewSession(authConfig, HTTPRequestFactory(headers), endpoint, true)
124 64
 	if err != nil {
125
-		return err
126
-	}
127
-	outs := engine.NewTable("star_count", 0)
128
-	for _, result := range results.Results {
129
-		out := &engine.Env{}
130
-		out.Import(result)
131
-		outs.Add(out)
132
-	}
133
-	outs.ReverseSort()
134
-	if _, err := outs.WriteListTo(job.Stdout); err != nil {
135
-		return err
65
+		return nil, err
136 66
 	}
137
-	return nil
67
+	return r.SearchRepositories(repoInfo.GetSearchTerm())
138 68
 }
139 69
 
140 70
 // ResolveRepository splits a repository name into its components
141 71
 // and configuration of the associated registry.
142
-func (s *Service) ResolveRepository(job *engine.Job) error {
143
-	var (
144
-		reposName = job.Args[0]
145
-	)
146
-
147
-	repoInfo, err := s.Config.NewRepositoryInfo(reposName)
148
-	if err != nil {
149
-		return err
150
-	}
151
-
152
-	out := engine.Env{}
153
-	err = out.SetJson("repository", repoInfo)
154
-	if err != nil {
155
-		return err
156
-	}
157
-	out.WriteTo(job.Stdout)
158
-
159
-	return nil
160
-}
161
-
162
-// Convenience wrapper for calling resolve_repository Job from a running job.
163
-func ResolveRepositoryInfo(jobContext *engine.Job, reposName string) (*RepositoryInfo, error) {
164
-	job := jobContext.Eng.Job("resolve_repository", reposName)
165
-	env, err := job.Stdout.AddEnv()
166
-	if err != nil {
167
-		return nil, err
168
-	}
169
-	if err := job.Run(); err != nil {
170
-		return nil, err
171
-	}
172
-	info := RepositoryInfo{}
173
-	if err := env.GetJson("repository", &info); err != nil {
174
-		return nil, err
175
-	}
176
-	return &info, nil
72
+func (s *Service) ResolveRepository(name string) (*RepositoryInfo, error) {
73
+	return s.Config.NewRepositoryInfo(name)
177 74
 }
178 75
 
179 76
 // ResolveIndex takes indexName and returns index info
180
-func (s *Service) ResolveIndex(job *engine.Job) error {
181
-	var (
182
-		indexName = job.Args[0]
183
-	)
184
-
185
-	index, err := s.Config.NewIndexInfo(indexName)
186
-	if err != nil {
187
-		return err
188
-	}
189
-
190
-	out := engine.Env{}
191
-	err = out.SetJson("index", index)
192
-	if err != nil {
193
-		return err
194
-	}
195
-	out.WriteTo(job.Stdout)
196
-
197
-	return nil
198
-}
199
-
200
-// Convenience wrapper for calling resolve_index Job from a running job.
201
-func ResolveIndexInfo(jobContext *engine.Job, indexName string) (*IndexInfo, error) {
202
-	job := jobContext.Eng.Job("resolve_index", indexName)
203
-	env, err := job.Stdout.AddEnv()
204
-	if err != nil {
205
-		return nil, err
206
-	}
207
-	if err := job.Run(); err != nil {
208
-		return nil, err
209
-	}
210
-	info := IndexInfo{}
211
-	if err := env.GetJson("index", &info); err != nil {
212
-		return nil, err
213
-	}
214
-	return &info, nil
215
-}
216
-
217
-// GetRegistryConfig returns current registry configuration.
218
-func (s *Service) GetRegistryConfig(job *engine.Job) error {
219
-	out := engine.Env{}
220
-	err := out.SetJson("config", s.Config)
221
-	if err != nil {
222
-		return err
223
-	}
224
-	out.WriteTo(job.Stdout)
225
-
226
-	return nil
77
+func (s *Service) ResolveIndex(name string) (*IndexInfo, error) {
78
+	return s.Config.NewIndexInfo(name)
227 79
 }