-
Notifications
You must be signed in to change notification settings - Fork 5k
Add secondary source of modules to Metricbeat to read light modules #12465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c100145
8ba9a38
758afb2
0a6b190
c181e51
4ceab7b
3a1768e
5f85188
e23df08
c138347
ae9c7e2
d64ccb1
b53acb3
1e9272c
a25ec8c
0135353
8b8521a
29c55b2
8652a0c
db6d303
ae9e00f
3f3d046
6af6437
af38b6b
6f38790
2af1d4c
49f5648
8722e1a
6bfb015
53bbabd
a70c415
9a6c336
edcd41b
38ee770
724f41a
84cba87
9e2cdb8
d701bff
b3dbfda
f175eb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,8 @@ import ( | |
| "github.com/elastic/beats/libbeat/cmd" | ||
| ) | ||
|
|
||
| func buildModulesManager(beat *beat.Beat) (cmd.ModulesManager, error) { | ||
| // BuildModulesManager adds support for modules management to a beat | ||
| func BuildModulesManager(beat *beat.Beat) (cmd.ModulesManager, error) { | ||
|
jsoriano marked this conversation as resolved.
jsoriano marked this conversation as resolved.
jsoriano marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: naming.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only change made here is to make this method public so it can be used from x-pack, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I noticed this symbol becoming public here. But with it becoming public, the descriptive nature of the names used is even more important (a.k.a naming is hard). |
||
| config := beat.BeatConfig | ||
|
|
||
| glob, err := config.String("config.modules.path", -1) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| // Licensed to Elasticsearch B.V. under one or more contributor | ||
| // license agreements. See the NOTICE file distributed with | ||
| // this work for additional information regarding copyright | ||
| // ownership. Elasticsearch B.V. licenses this file to you under | ||
| // the Apache License, Version 2.0 (the "License"); you may | ||
| // not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, | ||
| // software distributed under the License is distributed on an | ||
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| // KIND, either express or implied. See the License for the | ||
| // specific language governing permissions and limitations | ||
| // under the License. | ||
|
|
||
| package mb | ||
|
|
||
| import ( | ||
| "github.com/pkg/errors" | ||
|
|
||
| "github.com/elastic/beats/libbeat/common" | ||
| ) | ||
|
|
||
| // LightMetricSet contains the definition of a non-registered metric set | ||
| type LightMetricSet struct { | ||
| Name string | ||
| Module string | ||
| Default bool `config:"default"` | ||
| Input struct { | ||
| Module string `config:"module" validate:"required"` | ||
| MetricSet string `config:"metricset" validate:"required"` | ||
| Defaults interface{} `config:"defaults"` | ||
|
jsoriano marked this conversation as resolved.
|
||
| } `config:"input" validate:"required"` | ||
| } | ||
|
|
||
| // Registration obtains a metric set registration for this light metric set, this registration | ||
| // contains a metric set factory that reprocess metric set creation taking into account the | ||
| // light metric set defaults | ||
| func (m *LightMetricSet) Registration(r *Register) (MetricSetRegistration, error) { | ||
| registration, err := r.metricSetRegistration(m.Input.Module, m.Input.MetricSet) | ||
| if err != nil { | ||
| return registration, errors.Wrapf(err, | ||
| "failed to start light metricset '%s/%s' using '%s/%s' metricset as input", | ||
| m.Module, m.Name, | ||
| m.Input.Module, m.Input.MetricSet) | ||
| } | ||
|
|
||
| originalFactory := registration.Factory | ||
| registration.IsDefault = m.Default | ||
|
|
||
| // Light modules factory has to override defaults and reproduce builder | ||
| // functionality with the resulting configuration, it does: | ||
| // - Override defaults | ||
| // - Call module factory if registered (it wouldn't have been called | ||
| // if light module is really a registered mixed module) | ||
| // - Call host parser if defined (it would have already been called | ||
| // without the light module defaults) | ||
| // - Finally, call the original factory for the registered metricset | ||
| registration.Factory = func(base BaseMetricSet) (MetricSet, error) { | ||
| // Override default config on base module and metricset | ||
| base.name = m.Name | ||
| baseModule, err := m.baseModule(base.module) | ||
| if err != nil { | ||
| return nil, errors.Wrapf(err, "failed to create base module for light module '%s', using base module '%s'", m.Module, base.module.Name()) | ||
| } | ||
| base.module = baseModule | ||
|
|
||
| // Run module factory if registered, it will be called once per | ||
| // metricset, but it should be idempotent | ||
| moduleFactory := r.moduleFactory(m.Input.Module) | ||
| if moduleFactory != nil { | ||
| module, err := moduleFactory(*baseModule) | ||
| if err != nil { | ||
| return nil, errors.Wrapf(err, "module factory for module '%s' failed while creating light metricset '%s/%s'", m.Input.Module, m.Module, m.Name) | ||
| } | ||
| base.module = module | ||
| } | ||
|
|
||
| // At this point host parser was already run, we need to run this again | ||
| // with the overriden defaults | ||
| if registration.HostParser != nil { | ||
| base.hostData, err = registration.HostParser(base.module, base.host) | ||
| if err != nil { | ||
| return nil, errors.Wrapf(err, "host parser failed on light metricset factory for '%s/%s'", m.Module, m.Name) | ||
| } | ||
| base.host = base.hostData.Host | ||
| } | ||
|
|
||
| return originalFactory(base) | ||
| } | ||
|
|
||
| return registration, nil | ||
| } | ||
|
|
||
| // baseModule does the configuration overrides in the base module configuration | ||
| // taking into account the light metric set default configurations | ||
| func (m *LightMetricSet) baseModule(from Module) (*BaseModule, error) { | ||
| baseModule := BaseModule{ | ||
| name: m.Module, | ||
| } | ||
| var err error | ||
| // Set defaults | ||
| if baseModule.rawConfig, err = common.NewConfigFrom(m.Input.Defaults); err != nil { | ||
| return nil, errors.Wrap(err, "invalid input defaults") | ||
| } | ||
| // Copy values from user configuration | ||
| if err = from.UnpackConfig(baseModule.rawConfig); err != nil { | ||
| return nil, errors.Wrap(err, "failed to copy values from user configuration") | ||
| } | ||
| // Update module configuration | ||
| if err = baseModule.UnpackConfig(&baseModule.config); err != nil { | ||
| return nil, errors.Wrap(err, "failed to set module configuration") | ||
| } | ||
| return &baseModule, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| // Licensed to Elasticsearch B.V. under one or more contributor | ||
| // license agreements. See the NOTICE file distributed with | ||
| // this work for additional information regarding copyright | ||
| // ownership. Elasticsearch B.V. licenses this file to you under | ||
| // the Apache License, Version 2.0 (the "License"); you may | ||
| // not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, | ||
| // software distributed under the License is distributed on an | ||
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| // KIND, either express or implied. See the License for the | ||
| // specific language governing permissions and limitations | ||
| // under the License. | ||
|
|
||
| package mb | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
|
|
||
| "github.com/elastic/beats/libbeat/common" | ||
| ) | ||
|
|
||
| func TestLightMetricSetRegistration(t *testing.T) { | ||
| cases := map[string]struct { | ||
| module string | ||
| metricSet string | ||
| isDefault bool | ||
| fail bool | ||
| }{ | ||
| "metricset is registered": { | ||
| module: "foo", | ||
| metricSet: "bar", | ||
| fail: false, | ||
| }, | ||
| "metricset is registered and is default": { | ||
| module: "foo", | ||
| metricSet: "bar", | ||
| isDefault: true, | ||
| fail: false, | ||
| }, | ||
| "module is not registered": { | ||
| module: "notexists", | ||
| metricSet: "notexists", | ||
| fail: true, | ||
| }, | ||
| "metricset is not registered": { | ||
| module: "foo", | ||
| metricSet: "notexists", | ||
| fail: true, | ||
| }, | ||
| } | ||
|
|
||
| fakeMetricSetFactory := func(b BaseMetricSet) (MetricSet, error) { return &b, nil } | ||
|
|
||
| moduleName := "foo" | ||
| metricSetName := "bar" | ||
| lightMetricSetName := "metricset" | ||
| lightModuleName := "module" | ||
|
|
||
| r := NewRegister() | ||
| r.MustAddMetricSet(moduleName, metricSetName, fakeMetricSetFactory) | ||
|
|
||
| for title, c := range cases { | ||
| t.Run(title, func(t *testing.T) { | ||
| ms := LightMetricSet{ | ||
| Name: lightMetricSetName, | ||
| Module: lightModuleName, | ||
| Default: c.isDefault, | ||
| } | ||
| ms.Input.Module = c.module | ||
| ms.Input.MetricSet = c.metricSet | ||
| ms.Input.Defaults = common.MapStr{ | ||
| "query": common.MapStr{ | ||
| "extra": "something", | ||
| }, | ||
| } | ||
|
|
||
| registration, err := ms.Registration(r) | ||
| if c.fail { | ||
| assert.Error(t, err) | ||
| return | ||
| } | ||
| require.NoError(t, err) | ||
|
|
||
| // Check that registration has the light metricset settings | ||
| assert.Equal(t, c.metricSet, registration.Name) | ||
| assert.Equal(t, c.isDefault, registration.IsDefault) | ||
|
|
||
| // Check that calling the factory with a registered base module: | ||
| // - Does not modify original base module | ||
| // - Does the proper overrides in the resulting metricset | ||
| bm := baseModule(t, r, moduleName, metricSetName) | ||
| moduleConfigBefore := bm.Module().Config().String() | ||
| metricSet, err := registration.Factory(bm) | ||
|
|
||
| assert.Equal(t, moduleConfigBefore, bm.Module().Config().String(), | ||
| "original base module config should not change") | ||
| require.NoError(t, err) | ||
| require.NotNil(t, metricSet) | ||
|
|
||
| assert.Equal(t, lightModuleName, metricSet.Module().Name()) | ||
| assert.Equal(t, lightMetricSetName, metricSet.Name()) | ||
|
|
||
| expectedQuery := QueryParams{ | ||
| "default": "foo", | ||
| "extra": "something", | ||
| } | ||
| query := metricSet.Module().Config().Query | ||
| assert.Equal(t, expectedQuery, query) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func baseModule(t *testing.T, r *Register, module, metricSet string) BaseMetricSet { | ||
| origRegistration, err := r.metricSetRegistration(module, metricSet) | ||
| require.NoError(t, err) | ||
|
|
||
| c := DefaultModuleConfig() | ||
| c.Module = module | ||
| c.MetricSets = []string{metricSet} | ||
| c.Query = QueryParams{"default": "foo"} | ||
| raw, err := common.NewConfigFrom(c) | ||
| require.NoError(t, err) | ||
| baseModule, err := newBaseModuleFromConfig(raw) | ||
| require.NoError(t, err) | ||
|
|
||
| bm := BaseMetricSet{ | ||
| name: "bar", | ||
| module: &baseModule, | ||
| registration: origRegistration, | ||
| } | ||
| return bm | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.