-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Loading external fields.yml
files
#11199
Changes from all commits
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 |
---|---|---|
|
@@ -33,13 +33,13 @@ import ( | |
"time" | ||
|
||
"github.com/elastic/beats/libbeat/kibana" | ||
"github.com/elastic/beats/libbeat/mapping" | ||
|
||
"github.com/gofrs/uuid" | ||
errw "github.com/pkg/errors" | ||
"go.uber.org/zap" | ||
|
||
"github.com/elastic/beats/libbeat/api" | ||
"github.com/elastic/beats/libbeat/asset" | ||
"github.com/elastic/beats/libbeat/beat" | ||
"github.com/elastic/beats/libbeat/cfgfile" | ||
"github.com/elastic/beats/libbeat/cloudid" | ||
|
@@ -77,6 +77,8 @@ type Beat struct { | |
Config beatConfig | ||
RawConfig *common.Config // Raw config that can be unpacked to get Beat specific config data. | ||
|
||
Mapping mapping.Supporter // Get all fields of the Beat | ||
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. I so wish I hadn't named it 'Supporter' :) |
||
|
||
keystore keystore.Keystore | ||
index idxmgmt.Supporter | ||
|
||
|
@@ -193,11 +195,6 @@ func NewBeat(name, indexPrefix, v string) (*Beat, error) { | |
return nil, err | ||
} | ||
|
||
fields, err := asset.GetFields(name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
id, err := uuid.NewV4() | ||
if err != nil { | ||
return nil, err | ||
|
@@ -213,7 +210,6 @@ func NewBeat(name, indexPrefix, v string) (*Beat, error) { | |
ID: id, | ||
EphemeralID: ephemeralID, | ||
}, | ||
Fields: fields, | ||
} | ||
|
||
return &Beat{Beat: b}, nil | ||
|
@@ -457,8 +453,11 @@ func (b *Beat) Setup(settings Settings, bt beat.Creator, setup SetupSettings) er | |
} | ||
|
||
// prepare index by loading templates, lifecycle policies and write aliases | ||
|
||
m := b.index.Manager(esClient, idxmgmt.BeatsAssets(b.Fields)) | ||
fields, err := b.Mapping.GetBytes() | ||
if err != nil { | ||
return err | ||
} | ||
m := b.index.Manager(esClient, idxmgmt.BeatsAssets(fields)) | ||
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 'BeatsAssets' has been a place-holder, due to not having some better options availble. I'd be in favor of passing a more rich interface instead of a raw blob to be parsed and interpreted somewhere else. If possible we want to be able to install multiple templates in the future, each with it's own set of fields. A more generic type better being integrated with the index manager would be helpful. The index manager is supposed to be the only component/interface Beats should use for configuring and preparing indices (facade pattern). Maybe we can move the fields/templating support inside the index manager? |
||
err = m.Setup(setup.Template, setup.ILMPolicy) | ||
if err != nil { | ||
return err | ||
|
@@ -606,7 +605,11 @@ func (b *Beat) configure(settings Settings) error { | |
processingFactory = processing.MakeDefaultBeatSupport(true) | ||
} | ||
b.processing, err = processingFactory(b.Info, logp.L().Named("processors"), b.RawConfig) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
b.Mapping, err = mapping.DefaultSupport(nil, b.Beat.Info.Beat, b.RawConfig) | ||
return err | ||
} | ||
|
||
|
@@ -718,7 +721,11 @@ func (b *Beat) loadDashboards(ctx context.Context, force bool) error { | |
// but it's assumed that KB and ES have the same minor version. | ||
v := client.GetVersion() | ||
|
||
indexPattern, err := kibana.NewGenerator(b.Info.IndexPrefix, b.Info.Beat, b.Fields, b.Info.Version, v, withMigration) | ||
fieldBytes, err := b.Mapping.GetBytes() | ||
if err != nil { | ||
return err | ||
} | ||
indexPattern, err := kibana.NewGenerator(b.Info.IndexPrefix, b.Info.Beat, fieldBytes, b.Info.Version, v, withMigration) | ||
if err != nil { | ||
return fmt.Errorf("error creating index pattern generator: %v", err) | ||
} | ||
|
@@ -757,7 +764,12 @@ func (b *Beat) registerESIndexManagement() error { | |
// Build and return a callback to load index template into ES | ||
func (b *Beat) indexSetupCallback() func(esClient *elasticsearch.Client) error { | ||
return func(esClient *elasticsearch.Client) error { | ||
m := b.index.Manager(esClient, idxmgmt.BeatsAssets(b.Fields)) | ||
fieldBytes, err := b.Mapping.GetBytes() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
m := b.index.Manager(esClient, idxmgmt.BeatsAssets(fieldBytes)) | ||
return m.Setup(true, true) | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// 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 mapping | ||
|
||
import ( | ||
"io/ioutil" | ||
|
||
"github.com/elastic/beats/libbeat/asset" | ||
"github.com/elastic/beats/libbeat/common" | ||
"github.com/elastic/beats/libbeat/logp" | ||
) | ||
|
||
// Supporter returns the configured fields bytes | ||
type Supporter interface { | ||
GetBytes() ([]byte, error) | ||
} | ||
|
||
// fieldsSupport returns the default fields of a Beat | ||
type fieldsSupport struct { | ||
log *logp.Logger | ||
beat string | ||
} | ||
|
||
// customFieldsSupport returns the custom configured fields of a Beat | ||
type customFieldsSupport struct { | ||
log *logp.Logger | ||
beat string | ||
path string | ||
} | ||
|
||
// appendFieldsSupport return the default fields of a Beat | ||
// and the additional fields from append_fields | ||
type appendFieldsSupport struct { | ||
original Supporter | ||
appendedFields []byte | ||
} | ||
|
||
// externalFieldsSupport return the default fields of a Beat | ||
// and the additional fields from external_fields | ||
type externalFieldsSupport struct { | ||
original Supporter | ||
paths []string | ||
} | ||
|
||
func DefaultSupport(log *logp.Logger, beat string, cfg *common.Config) (Supporter, error) { | ||
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. exported function DefaultSupport should have comment or be unexported |
||
if log == nil { | ||
log = logp.NewLogger("mapping") | ||
} else { | ||
log = log.Named("mapping") | ||
} | ||
|
||
config := struct { | ||
Template struct { | ||
Fields string `config:"fields"` | ||
AppendFields []byte `config:"append_fields"` | ||
ExternalFields []string `config:"external_fields"` | ||
} `config:"setup.template"` | ||
}{} | ||
err := cfg.Unpack(&config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// load default fields.ymls of Beat | ||
var s Supporter | ||
s = &fieldsSupport{ | ||
log: log, | ||
beat: beat, | ||
} | ||
|
||
// custom fields.yml file is configured | ||
if config.Template.Fields != "" { | ||
s = &customFieldsSupport{ | ||
log: log, | ||
beat: beat, | ||
path: config.Template.Fields, | ||
} | ||
} | ||
|
||
// append_fields | ||
if len(config.Template.AppendFields) > 0 { | ||
s = &appendFieldsSupport{ | ||
original: s, | ||
appendedFields: config.Template.AppendFields, | ||
} | ||
} | ||
|
||
// external_fields | ||
if len(config.Template.ExternalFields) > 0 { | ||
s = &externalFieldsSupport{ | ||
original: s, | ||
paths: config.Template.ExternalFields, | ||
} | ||
} | ||
|
||
return s, nil | ||
} | ||
|
||
func (f *fieldsSupport) GetBytes() ([]byte, error) { | ||
return asset.GetFields(f.beat) | ||
} | ||
|
||
func (c *customFieldsSupport) GetBytes() ([]byte, error) { | ||
c.log.Debugf("Reading bytes custom fields.yml from %s", c.path) | ||
return ioutil.ReadFile(c.path) | ||
} | ||
|
||
func (a *appendFieldsSupport) GetBytes() ([]byte, error) { | ||
fields, err := a.original.GetBytes() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return append(fields, a.appendedFields...), nil | ||
} | ||
|
||
func (e *externalFieldsSupport) GetBytes() ([]byte, error) { | ||
fields, err := e.original.GetBytes() | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, path := range e.paths { | ||
f, err := ioutil.ReadFile(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
fields = append(fields, f...) | ||
} | ||
|
||
return fields, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me the name kind of clashes with
setup.template.fields
. Like: which one has priority, does one replace the other, are the two files combined, why not have setup.template.fields accept a list of files.