Skip to content

Conversation

blind-oracle
Copy link
Contributor

Signed-off-by: Igor Novgorodov [email protected]

What this PR does:
Adds an ability to load a comma-separated list of modules instead of a single module or 'all'.
This should be backwards-compatible with the current behaviour.

The moduleManager is extended a bit to keep track of already loaded modules.
I don't really like having All as a module, but I'll leave it for now as-is to keep changes compact.
And single-binary detection depends on this in a couple of places.
Ideally we should just alias the word all to a predefined list of modules and load them like they were specified on the command line or in config file.

Which issue(s) this PR fixes:
Fixes #3272

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]

Signed-off-by: Igor Novgorodov <[email protected]>
Copy link
Contributor

@pracucci pracucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! I left few comments. @pstibrany what do you think?

CHANGELOG.md Outdated
Comment on lines 5 to 7
* [FEATURE] Implement an ability to load multiple Cortex modules using a comma-separated list. #3272
- Should be backwards compatible with the current behavior.
- Target list like 'all,compactor' can be used to load the single-binary modules plus some other modules.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest a little rephrasing to simplify it:

Suggested change
* [FEATURE] Implement an ability to load multiple Cortex modules using a comma-separated list. #3272
- Should be backwards compatible with the current behavior.
- Target list like 'all,compactor' can be used to load the single-binary modules plus some other modules.
* [ENHANCEMENT] Allow to specify multiple comma-separated Cortex services to `-target` CLI option (or its respective YAML config option). For example, `-target=all,compactor` can be used to start Cortex single-binary with compactor as well. #3272

We consider these improvements "enhancement" and not new core features. Please move the changelog entry to the right place (entries are grouped by type).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, forgot that they're grouped.

// whenever it's not running as an internal dependency (ie. querier or
// ruler's dependency)
canJoinDistributorsRing := (t.Cfg.Target == All || t.Cfg.Target == Distributor)
canJoinDistributorsRing := t.Cfg.Modules[Distributor] || t.Cfg.Modules[All]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should do a similar change in initAlertManager() too.

PrintConfig bool `yaml:"-"`
HTTPPrefix string `yaml:"http_prefix"`
Target string `yaml:"target"`
Modules map[string]bool `yaml:"-"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think keeping both Target string and the new Modules map[string]bool may lead to bugs in the future. We may forget to check Modules instead of Target. A better option may be define a CLI flag custom type in pkg/util/flagext which is a []string but implements flag.Value and yaml.Marshaller/Unmarshaller to marshal/unmarshal a comma separated string.

We wouldn't have a map, but checking if a module is within the []string would be as easy as calling util.StringsContain().

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already flagext.StringSlice, should I just use it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flagext.StringSlice doesn't support comma-separated argument, only argument with multiple flags. I'm afraid that would be incompatible change in YAML config.

modules map[string]*module

// Modules that are already initialized
modulesLoaded map[string]bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rename "loaded" into "initialised", which is the naming we use here.

}

// GetServicesMap returns services map
func (m *Manager) GetServicesMap() map[string]services.Service {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may call it GetInitialisedServices() and update the comment accordingly.


for ix, n := range deps {
// Skip already loaded modules
if m.modulesLoaded[n] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't we just check m.servicesMap?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That wouldn't work... not all modules have a service.

Copy link
Contributor

@pstibrany pstibrany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this! I suggest we keep the changes to modules.Manager backwards compatible and not introduce new public API to it (it's always easy to add new methods, and difficult to remove them once they get used), since there are several other projects using this other than Cortex.

func (m *Manager) InitModuleServices(target string) (map[string]services.Service, error) {
if _, ok := m.modules[target]; !ok {
return nil, fmt.Errorf("unrecognised module name: %s", target)
func (m *Manager) InitModuleServices(name string) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make it work with this signature instead?

Suggested change
func (m *Manager) InitModuleServices(name string) error {
func (m *Manager) InitModuleServices(names ...string) (map[string]services.Service, error)

There are multiple projects using this system, and this is backwards compatible, while your suggestion isn't. Furthermore it keeps the state of initialization outside of this manager.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, didn't know that anything else other than Cortex used it.

}

// IsModuleRegistered returns true if given module was registered
func (m *Manager) IsModuleRegistered(mod string) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not introduce new public methods to manager, that are not needed externally.

Signed-off-by: Igor Novgorodov <[email protected]>
Signed-off-by: Igor Novgorodov <[email protected]>
Signed-off-by: Igor Novgorodov <[email protected]>
@blind-oracle
Copy link
Contributor Author

Thanks for the comments everyone.
I've tried to take all of them into account and improve accordingly:

  • I've created a new type flagext.StringSliceCSV which implements serialisation to/from comma-separated string + tests.
    I also had to add a workaround for this type to the doc-generator as it considers it a "list of strings".
  • Reverted the API of module loader to be backwards-compatible without extra public methods
  • Workaround Jaeger name generation as before it was suffixed by Target.
    Now it will be suffixed only if there's only one module listed in Target, otherwise it will be just cortex. This should be backwards-compatible also.
  • Fixed the CHANGELOG

Copy link
Contributor

@pstibrany pstibrany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for addressing my feedback! I have left more comments in the spirit of “minimize state”.

Signed-off-by: Igor Novgorodov <[email protected]>
Copy link
Contributor

@pstibrany pstibrany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you a lot for your patience. This is on the right track, few more minor nits.

Comment on lines 117 to 120
f.Var((*flagext.StringSliceCSV)(&c.Target), "target", "List of Cortex modules to load, comma separated. "+
"The alias 'all' can be used in the list to load a number of core modules and will enable single-binary mode. "+
"Use '-modules' command line flag to get a list of available modules, and to see which modules are included in 'all'.")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
f.Var((*flagext.StringSliceCSV)(&c.Target), "target", "List of Cortex modules to load, comma separated. "+
"The alias 'all' can be used in the list to load a number of core modules and will enable single-binary mode. "+
"Use '-modules' command line flag to get a list of available modules, and to see which modules are included in 'all'.")
f.Var(&c.Target, "target", "Comma-separated list of Cortex modules to load. "+
"The alias 'all' can be used in the list to load a number of core modules and will enable single-binary mode. "+
"Use '-modules' command line flag to get a list of available modules, and to see which modules are included in 'all'.")

Comment on lines 113 to 116
// Set the default module list to 'all'
// Make linter happy
c.Target.Set(All) //nolint:errcheck

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Set the default module list to 'all'
// Make linter happy
c.Target.Set(All) //nolint:errcheck
c.Target = []string{All}

svcs, err = mm.InitModuleServices("service_unknown")
assert.Nil(t, svcs)
assert.Error(t, err, fmt.Errorf("unrecognised module name: service_unknown"))
// Test loading of the module second time (should be noop)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be noop -- it should in fact create new services. Can we extend the test to verify that services from first and second invocation of mm.InitModuleServices("serviceC") are different?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the noop part is left from the previous stateful ModuleManager. Fixed

@blind-oracle
Copy link
Contributor Author

Integration test failed, but looking at the logs it looks like some other transient issue.

Copy link
Contributor

@pstibrany pstibrany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have left some non-blocking nitpicky comments (mostly to minimize the diff), but LGTM. Thank you!

Signed-off-by: Igor Novgorodov <[email protected]>
@blind-oracle
Copy link
Contributor Author

Done mentioned fixes

Copy link
Contributor

@pstibrany pstibrany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much!

@blind-oracle
Copy link
Contributor Author

There's a conflict with newer PR #3287, I've merged current master and fixed.

@blind-oracle
Copy link
Contributor Author

Looks like tests are unstable.
I also occasionally get failed etcd-related tests when running go test ./... locally.

But now it's something else:

--- FAIL: TestShuffleShardWithCaching (5.03s)
    ring_test.go:790: lifecycler 0 failed: failed to pick tokens in the KV store, ring: test: failed to CAS test
    ring_test.go:834: 6 != 5
FAIL

@pstibrany
Copy link
Contributor

Looks like tests are unstable.
I also occasionally get failed etcd-related tests when running go test ./... locally.

Yes, this test is flaky. We need to fix it.

Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Copy link
Contributor

@pracucci pracucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You did great! LGTM! Will merge as soon as the CI passes.

Signed-off-by: Marco Pracucci <[email protected]>
@pracucci pracucci merged commit 1734c75 into cortexproject:master Oct 9, 2020
@blind-oracle blind-oracle deleted the module-separate branch October 9, 2020 12:18
roidelapluie pushed a commit to inuits/ansible-cortex that referenced this pull request Nov 17, 2020
Add support for by explictely specifying a target in the servcies
config. cortexproject/cortex#3275

Signed-off-by: Julien Pivotto <[email protected]>
roidelapluie pushed a commit to inuits/ansible-cortex that referenced this pull request Nov 17, 2020
Add support for by explictely specifying a target in the servcies
config. cortexproject/cortex#3275

Signed-off-by: Julien Pivotto <[email protected]>
roidelapluie pushed a commit to inuits/ansible-cortex that referenced this pull request Nov 17, 2020
Add support for by explictely specifying a target in the servcies
config. cortexproject/cortex#3275

Signed-off-by: Julien Pivotto <[email protected]>
roidelapluie pushed a commit to inuits/ansible-cortex that referenced this pull request Nov 17, 2020
Add support for by explictely specifying a target in the servcies
config. cortexproject/cortex#3275

Signed-off-by: Julien Pivotto <[email protected]>
roidelapluie pushed a commit to inuits/ansible-cortex that referenced this pull request Nov 17, 2020
Add support for by explictely specifying a target in the servcies
config. cortexproject/cortex#3275

Signed-off-by: Julien Pivotto <[email protected]>
roidelapluie added a commit to cloudalchemy/ansible-cortex that referenced this pull request Nov 17, 2020
* Update cortex and add support for multiple modules

Add support for by explictely specifying a target in the servcies
config. cortexproject/cortex#3275

Signed-off-by: Julien Pivotto <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an ability to run mixed number of modules in one instance

3 participants