-
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
[Ingest Management] Agent supports capabilities definition #23848
Changes from all commits
e364446
51ff837
c78b8fe
5861d56
e5c76d8
d4f938d
cd7468f
c21a7c7
c1d244b
33f6329
595c253
716c4d6
8667e67
3214f2e
8ec47a0
03acaea
faacd96
2472827
0124574
8882956
29f3413
b094755
7fa392f
0037255
d53b4eb
c98252a
f3d0bc8
4edee85
a9e71d9
71e3492
4e23669
5b0bdca
75dc879
9a337b9
58a04ce
41443f9
ea33dff
02c88d8
6aa4ca0
c18b5cd
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 |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
// or more contributor license agreements. Licensed under the Elastic License; | ||
// you may not use this file except in compliance with the Elastic License. | ||
|
||
package capabilities | ||
|
||
import ( | ||
"errors" | ||
"os" | ||
|
||
"gopkg.in/yaml.v2" | ||
|
||
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger" | ||
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/status" | ||
) | ||
|
||
// Capability provides a way of applying predefined filter to object. | ||
// It's up to capability to determine if capability is applicable on object. | ||
type Capability interface { | ||
// Apply applies capabilities on input and returns true if input should be completely blocked | ||
// otherwise, false and updated input is returned | ||
Apply(interface{}) (interface{}, 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. I still would say the interface is doing to much, while not really abstracting things. The input and output types are The E.g.
Alternatively (in case we want transformations), we might want to pass the root configuration object to |
||
} | ||
|
||
var ( | ||
// ErrBlocked is returned when capability is blocking. | ||
ErrBlocked = errors.New("capability blocked") | ||
) | ||
|
||
type capabilitiesManager struct { | ||
caps []Capability | ||
reporter status.Reporter | ||
} | ||
|
||
type capabilityFactory func(*logger.Logger, *ruleDefinitions, status.Reporter) (Capability, error) | ||
|
||
// Load loads capabilities files and prepares manager. | ||
func Load(capsFile string, log *logger.Logger, sc status.Controller) (Capability, error) { | ||
handlers := []capabilityFactory{ | ||
newInputsCapability, | ||
newOutputsCapability, | ||
newUpgradesCapability, | ||
} | ||
|
||
cm := &capabilitiesManager{ | ||
caps: make([]Capability, 0), | ||
reporter: sc.RegisterWithPersistance("capabilities", true), | ||
} | ||
|
||
// load capabilities from file | ||
fd, err := os.Open(capsFile) | ||
if err != nil && !os.IsNotExist(err) { | ||
return cm, err | ||
} | ||
|
||
if os.IsNotExist(err) { | ||
log.Infof("capabilities file not found in %s", capsFile) | ||
return cm, nil | ||
} | ||
defer fd.Close() | ||
|
||
definitions := &ruleDefinitions{Capabilities: make([]ruler, 0)} | ||
dec := yaml.NewDecoder(fd) | ||
if err := dec.Decode(&definitions); err != nil { | ||
return cm, err | ||
} | ||
|
||
// make list of handlers out of capabilities definition | ||
for _, h := range handlers { | ||
cap, err := h(log, definitions, cm.reporter) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if cap == nil { | ||
continue | ||
} | ||
|
||
cm.caps = append(cm.caps, cap) | ||
} | ||
|
||
return cm, nil | ||
} | ||
|
||
func (mgr *capabilitiesManager) Apply(in interface{}) (interface{}, error) { | ||
var err error | ||
// reset health on start, child caps will update to fail if needed | ||
mgr.reporter.Update(status.Healthy) | ||
for _, cap := range mgr.caps { | ||
in, err = cap.Apply(in) | ||
if err != nil { | ||
return in, err | ||
} | ||
} | ||
|
||
return in, 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.
nit: The number of parameters gets a little out of hand. Do we really need this function, or can we just use the struct and have a separate "init" or "start" function/method?
Do we pass a tuple of
ctx, log, agentInfo
often? In the future we might even want to pass something for metrics and APM tracing. The 'tuple' could be combined into an appContext struct.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.
i'm +1 on this here. would be worth a small refactor across all the codebase, we have this pattern i think on multple places. these things were simple at first but got bloated over time
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.
The emitter function is actually become more of a wrapper for the
emitterController
with the addition of dynamic inputs and conditions.We should probably refactor that into a single controller.