Skip to content

Commit aa10e35

Browse files
authored
Generalise Modules Service to make it extensible (#2559)
* Generalise module service into separate package Signed-off-by: Annanay <[email protected]> * Fix build and tests Signed-off-by: Annanay <[email protected]> * Fix test Signed-off-by: Annanay <[email protected]> * Address review comments Signed-off-by: Annanay <[email protected]> * Cleanup cortex_test.go Signed-off-by: Annanay <[email protected]> * Fix module test Signed-off-by: Annanay <[email protected]> * Checkpoint Signed-off-by: Annanay <[email protected]> * Ignore inverse dependencies if module returns nil service Signed-off-by: Annanay <[email protected]> * Lint, fix tests Signed-off-by: Annanay <[email protected]> * Fix tests for unknown module name Signed-off-by: Annanay <[email protected]> * Create module service wrapper only if service is not nil Signed-off-by: Annanay <[email protected]>
1 parent eca6922 commit aa10e35

File tree

8 files changed

+312
-304
lines changed

8 files changed

+312
-304
lines changed

cmd/cortex/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func main() {
104104
util.InitEvents(eventSampleRate)
105105

106106
// Setting the environment variable JAEGER_AGENT_HOST enables tracing
107-
if trace, err := tracing.NewFromEnv("cortex-" + cfg.Target.String()); err != nil {
107+
if trace, err := tracing.NewFromEnv("cortex-" + cfg.Target); err != nil {
108108
level.Error(util.Logger).Log("msg", "Failed to setup tracing", "err", err.Error())
109109
} else {
110110
defer trace.Close()

cmd/cortex/main_test.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,6 @@ func TestFlagParsing(t *testing.T) {
2626
stderrMessage: configFileOption,
2727
},
2828

29-
// check that config file is used
30-
"config with unknown target": {
31-
yaml: "target: unknown",
32-
stderrMessage: "unrecognised module name: unknown",
33-
},
34-
35-
"argument with unknown target": {
36-
arguments: []string{"-target=unknown"},
37-
stderrMessage: "unrecognised module name: unknown",
38-
},
39-
4029
"unknown flag": {
4130
arguments: []string{"-unknown.flag"},
4231
stderrMessage: "-unknown.flag",
@@ -48,12 +37,6 @@ func TestFlagParsing(t *testing.T) {
4837
stdoutMessage: "target: ingester",
4938
},
5039

51-
"config with wrong argument override": {
52-
yaml: "target: ingester",
53-
arguments: []string{"-target=unknown"},
54-
stderrMessage: "unrecognised module name: unknown",
55-
},
56-
5740
"default values": {
5841
stdoutMessage: "target: all\n",
5942
},
@@ -63,11 +46,6 @@ func TestFlagParsing(t *testing.T) {
6346
stdoutMessage: "target: ingester\n",
6447
},
6548

66-
"config without expand-env": {
67-
yaml: "target: $TARGET",
68-
stderrMessage: "Error parsing config file: unrecognised module name: $TARGET\n",
69-
},
70-
7149
"config with expand-env": {
7250
arguments: []string{"-config.expand-env"},
7351
yaml: "target: $TARGET",

pkg/cortex/cortex.go

Lines changed: 16 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import (
4747
"github.com/cortexproject/cortex/pkg/storegateway"
4848
"github.com/cortexproject/cortex/pkg/util"
4949
"github.com/cortexproject/cortex/pkg/util/grpc/healthcheck"
50+
"github.com/cortexproject/cortex/pkg/util/modules"
5051
"github.com/cortexproject/cortex/pkg/util/runtimeconfig"
5152
"github.com/cortexproject/cortex/pkg/util/services"
5253
"github.com/cortexproject/cortex/pkg/util/validation"
@@ -71,10 +72,10 @@ import (
7172

7273
// Config is the root config for Cortex.
7374
type Config struct {
74-
Target ModuleName `yaml:"target"`
75-
AuthEnabled bool `yaml:"auth_enabled"`
76-
PrintConfig bool `yaml:"-"`
77-
HTTPPrefix string `yaml:"http_prefix"`
75+
Target string `yaml:"target"`
76+
AuthEnabled bool `yaml:"auth_enabled"`
77+
PrintConfig bool `yaml:"-"`
78+
HTTPPrefix string `yaml:"http_prefix"`
7879

7980
API api.Config `yaml:"api"`
8081
Server server.Config `yaml:"server"`
@@ -108,9 +109,8 @@ type Config struct {
108109
// RegisterFlags registers flag.
109110
func (c *Config) RegisterFlags(f *flag.FlagSet) {
110111
c.Server.MetricsNamespace = "cortex"
111-
c.Target = All
112112
c.Server.ExcludeRequestInLog = true
113-
f.Var(&c.Target, "target", "The Cortex service to run. Supported values are: all, distributor, ingester, querier, query-frontend, table-manager, ruler, alertmanager, configs.")
113+
f.StringVar(&c.Target, "target", All, "The Cortex service to run. Supported values are: all, distributor, ingester, querier, query-frontend, table-manager, ruler, alertmanager, configs.")
114114
f.BoolVar(&c.AuthEnabled, "auth.enabled", true, "Set to false to disable auth.")
115115
f.BoolVar(&c.PrintConfig, "print.config", false, "Print the config and exit.")
116116
f.StringVar(&c.HTTPPrefix, "http.prefix", "/api/prom", "HTTP path prefix for Cortex API.")
@@ -191,7 +191,8 @@ type Cortex struct {
191191
Cfg Config
192192

193193
// set during initialization
194-
ServiceMap map[ModuleName]services.Service
194+
ServiceMap map[string]services.Service
195+
ModuleManager *modules.Manager
195196

196197
API *api.API
197198
Server *server.Server
@@ -238,14 +239,10 @@ func New(cfg Config) (*Cortex, error) {
238239
cortex.setupAuthMiddleware()
239240
cortex.setupThanosTracing()
240241

241-
serviceMap, err := cortex.initModuleServices()
242-
if err != nil {
242+
if err := cortex.setupModuleManager(); err != nil {
243243
return nil, err
244244
}
245245

246-
cortex.ServiceMap = serviceMap
247-
cortex.API.RegisterServiceMapHandler(http.HandlerFunc(cortex.servicesHandler))
248-
249246
return cortex, nil
250247
}
251248

@@ -292,40 +289,16 @@ func (t *Cortex) setupThanosTracing() {
292289
)
293290
}
294291

295-
func (t *Cortex) initModuleServices() (map[ModuleName]services.Service, error) {
296-
servicesMap := map[ModuleName]services.Service{}
297-
298-
// initialize all of our dependencies first
299-
deps := orderedDeps(t.Cfg.Target)
300-
deps = append(deps, t.Cfg.Target) // lastly, initialize the requested module
301-
302-
for ix, n := range deps {
303-
mod := modules[n]
304-
305-
var serv services.Service
306-
307-
if mod.wrappedService != nil {
308-
s, err := mod.wrappedService(t)
309-
if err != nil {
310-
return nil, errors.Wrap(err, fmt.Sprintf("error initialising module: %s", n))
311-
}
312-
if s != nil {
313-
// We pass servicesMap, which isn't yet finished. By the time service starts,
314-
// it will be fully built, so there is no need for extra synchronization.
315-
serv = newModuleServiceWrapper(servicesMap, n, s, mod.deps, findInverseDependencies(n, deps[ix+1:]))
316-
}
317-
}
318-
319-
if serv != nil {
320-
servicesMap[n] = serv
321-
}
292+
// Run starts Cortex running, and blocks until a Cortex stops.
293+
func (t *Cortex) Run() error {
294+
serviceMap, err := t.ModuleManager.InitModuleServices(t.Cfg.Target)
295+
if err != nil {
296+
return err
322297
}
323298

324-
return servicesMap, nil
325-
}
299+
t.ServiceMap = serviceMap
300+
t.API.RegisterServiceMapHandler(http.HandlerFunc(t.servicesHandler))
326301

327-
// Run starts Cortex running, and blocks until a Cortex stops.
328-
func (t *Cortex) Run() error {
329302
// get all services, create service manager and tell it to start
330303
servs := []services.Service(nil)
331304
for _, s := range t.ServiceMap {
@@ -426,65 +399,3 @@ func (t *Cortex) readyHandler(sm *services.Manager) http.HandlerFunc {
426399
http.Error(w, "ready", http.StatusOK)
427400
}
428401
}
429-
430-
// listDeps recursively gets a list of dependencies for a passed moduleName
431-
func listDeps(m ModuleName) []ModuleName {
432-
deps := modules[m].deps
433-
for _, d := range modules[m].deps {
434-
deps = append(deps, listDeps(d)...)
435-
}
436-
return deps
437-
}
438-
439-
// orderedDeps gets a list of all dependencies ordered so that items are always after any of their dependencies.
440-
func orderedDeps(m ModuleName) []ModuleName {
441-
deps := listDeps(m)
442-
443-
// get a unique list of moduleNames, with a flag for whether they have been added to our result
444-
uniq := map[ModuleName]bool{}
445-
for _, dep := range deps {
446-
uniq[dep] = false
447-
}
448-
449-
result := make([]ModuleName, 0, len(uniq))
450-
451-
// keep looping through all modules until they have all been added to the result.
452-
453-
for len(result) < len(uniq) {
454-
OUTER:
455-
for name, added := range uniq {
456-
if added {
457-
continue
458-
}
459-
for _, dep := range modules[name].deps {
460-
// stop processing this module if one of its dependencies has
461-
// not been added to the result yet.
462-
if !uniq[dep] {
463-
continue OUTER
464-
}
465-
}
466-
467-
// if all of the module's dependencies have been added to the result slice,
468-
// then we can safely add this module to the result slice as well.
469-
uniq[name] = true
470-
result = append(result, name)
471-
}
472-
}
473-
return result
474-
}
475-
476-
// find modules in the supplied list, that depend on mod
477-
func findInverseDependencies(mod ModuleName, mods []ModuleName) []ModuleName {
478-
result := []ModuleName(nil)
479-
480-
for _, n := range mods {
481-
for _, d := range modules[n].deps {
482-
if d == mod {
483-
result = append(result, n)
484-
break
485-
}
486-
}
487-
}
488-
489-
return result
490-
}

pkg/cortex/cortex_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,19 @@ func TestCortex(t *testing.T) {
5252

5353
c, err := New(cfg)
5454
require.NoError(t, err)
55-
require.NotNil(t, c.ServiceMap)
5655

57-
for m, s := range c.ServiceMap {
56+
serviceMap, err := c.ModuleManager.InitModuleServices(c.Cfg.Target)
57+
require.NoError(t, err)
58+
require.NotNil(t, serviceMap)
59+
60+
for m, s := range serviceMap {
5861
// make sure each service is still New
5962
require.Equal(t, services.New, s.State(), "module: %s", m)
6063
}
6164

6265
// check random modules that we expect to be configured when using Target=All
63-
require.NotNil(t, c.ServiceMap[Server])
64-
require.NotNil(t, c.ServiceMap[Ingester])
65-
require.NotNil(t, c.ServiceMap[Ring])
66-
require.NotNil(t, c.ServiceMap[Distributor])
67-
68-
// check that findInverseDependencie for Ring -- querier and distributor depend on Ring, so should be returned.
69-
require.ElementsMatch(t, []ModuleName{Distributor, Querier}, findInverseDependencies(Ring, modules[cfg.Target].deps))
66+
require.NotNil(t, serviceMap[Server])
67+
require.NotNil(t, serviceMap[Ingester])
68+
require.NotNil(t, serviceMap[Ring])
69+
require.NotNil(t, serviceMap[Distributor])
7070
}

0 commit comments

Comments
 (0)