Skip to content

Commit

Permalink
[Heartbeat] Fix hint-based monitor gen (#34376)
Browse files Browse the repository at this point in the history
* ignore matching event port with hints port

* fixed compilation error

* Refactor hint-based monitor gen

* Update heartbeat/autodiscover/builder/hints/monitors.go

* Remove host-port matching from hint generator

* Add changelog

---------

Co-authored-by: gsantoro <giuseppe.santoro@elastic.co>
Co-authored-by: Andrew Cholakian <andrewvc@elastic.co>
(cherry picked from commit 9d9f8dc)

# Conflicts:
#	heartbeat/autodiscover/builder/hints/monitors.go
#	heartbeat/autodiscover/builder/hints/monitors_test.go
  • Loading branch information
emilioalvap authored and mergify[bot] committed Mar 7, 2023
1 parent 6c1af3b commit d2f2de0
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Expand Up @@ -82,6 +82,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d

*Heartbeat*

- Remove host and port matching restrictions on hint-generated monitors. {pull}34376[34376]

*Metricbeat*

Expand Down
61 changes: 46 additions & 15 deletions heartbeat/autodiscover/builder/hints/monitors.go
Expand Up @@ -40,6 +40,7 @@ const (
schedule = "schedule"
hosts = "hosts"
processors = "processors"
scheme = "type"
)

type heartbeatHints struct {
Expand All @@ -60,8 +61,17 @@ func NewHeartbeatHints(cfg *common.Config) (autodiscover.Builder, error) {
}

// Create config based on input hints in the bus event
<<<<<<< HEAD
func (hb *heartbeatHints) CreateConfig(event bus.Event, options ...ucfg.Option) []*common.Config {
var hints common.MapStr
=======
func (hb *heartbeatHints) CreateConfig(event bus.Event, options ...ucfg.Option) []*conf.C {
var (
hints mapstr.M
podEvent bool
)

>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
hIface, ok := event["hints"]
if ok {
hints, _ = hIface.(common.MapStr)
Expand All @@ -75,7 +85,10 @@ func (hb *heartbeatHints) CreateConfig(event bus.Event, options ...ucfg.Option)
return []*common.Config{}
}

port, _ := common.TryToInt(event["port"])
port, ok := common.TryToInt(event["port"])
if !ok {
podEvent = true
}

host, _ := event["host"].(string)
if host == "" {
Expand Down Expand Up @@ -108,7 +121,12 @@ func (hb *heartbeatHints) CreateConfig(event bus.Event, options ...ucfg.Option)
monitor[processors] = procs
}

h := hb.getHostsWithPort(monitor, port)
h, err := hb.getHostsWithPort(monitor, port, podEvent)
if err != nil {
hb.logger.Warnf("unable to find valid hosts for %+v: %w", monitor, err)
continue
}

monitor[hosts] = h

config, err := common.NewConfigFrom(monitor)
Expand All @@ -132,6 +150,7 @@ func (hb *heartbeatHints) getSchedule(hints common.MapStr) []string {
return builder.GetHintAsList(hints, hb.config.Key, schedule)
}

<<<<<<< HEAD
func (hb *heartbeatHints) getRawConfigs(hints common.MapStr) []common.MapStr {
return builder.GetHintAsConfigs(hints, hb.config.Key)
}
Expand All @@ -145,23 +164,35 @@ func (hb *heartbeatHints) getHostsWithPort(hints common.MapStr, port int) []stri
thosts := builder.GetHintAsList(hints, "", hosts)
// Only pick hosts that have ${data.port} or the port on current event. This will make
// sure that incorrect meta mapping doesn't happen
=======
func (hb *heartbeatHints) getHostsWithPort(hints mapstr.M, port int, podEvent bool) ([]string, error) {
thosts := utils.GetHintAsList(hints, "", hosts)
mType := utils.GetHintString(hints, "", scheme)

// We can't reliable detect duplicated monitors since we don't have all ports/hosts,
// relying on runner deduping monitors, see https://github.com/elastic/beats/pull/29041
hostSet := map[string]struct{}{}
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
for _, h := range thosts {
if strings.Contains(h, "data.port") || strings.Contains(h, fmt.Sprintf(":%d", port)) ||
// Use the event that has no port config if there is a ${data.host}:9090 like input
(port == 0 && strings.Contains(h, "data.host")) {
result = append(result, h)
} else if port == 0 && !strings.Contains(h, ":") {
// For ICMP like use cases allow only host to be passed if there is no port
result = append(result, h)
} else {
hb.logger.Warn("unable to frame a host from input host: %s", h)
if mType == "icmp" && strings.Contains(h, ":") {
hb.logger.Warnf("ICMP scheme does not support port specification: %s", h)
continue
} else if strings.Contains(h, "${data.port}") && podEvent {
// Pod events don't contain port metadata, skip
continue
}

hostSet[h] = struct{}{}
}

if len(hostSet) == 0 {
return nil, fmt.Errorf("no hosts selected for port %d with hints: %+v", port, thosts)
}

if len(thosts) > 0 && len(result) == 0 {
hb.logger.Debugf("no hosts selected for port %d with hints: %+v", port, thosts)
return nil
var result []string
for host := range hostSet {
result = append(result, host)
}

return result
return result, nil
}
98 changes: 93 additions & 5 deletions heartbeat/autodiscover/builder/hints/monitors_test.go
Expand Up @@ -57,19 +57,26 @@ func TestGenerateHints(t *testing.T) {
{
message: "Hints without host should return nothing",
event: bus.Event{
<<<<<<< HEAD
"hints": common.MapStr{
"monitor": common.MapStr{
"type": "icmp",
=======
"hints": mapstr.M{
"monitor": mapstr.M{
"type": "http",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
},
},
},
len: 0,
result: common.MapStr{},
},
{
message: "Hints without matching port should return nothing in the hosts section",
message: "Hints without port should return nothing if ${data.port} is used",
event: bus.Event{
"host": "1.2.3.4",
<<<<<<< HEAD
"port": 9090,
"hints": common.MapStr{
"monitor": common.MapStr{
Expand All @@ -84,12 +91,24 @@ func TestGenerateHints(t *testing.T) {
"type": "icmp",
"hosts": []interface{}{},
},
=======
"hints": mapstr.M{
"monitor": mapstr.M{
"type": "http",
"hosts": "${data.host}:${data.port},test:${data.port}",
},
},
},
len: 0,
result: mapstr.M{},
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
},
{
message: "Hints with multiple hosts return only the matching one",
message: "Hints with multiple hosts returns all with the template",
event: bus.Event{
"host": "1.2.3.4",
"port": 9090,
<<<<<<< HEAD
"hints": common.MapStr{
"monitor": common.MapStr{
"type": "icmp",
Expand All @@ -112,30 +131,51 @@ func TestGenerateHints(t *testing.T) {
"hints": common.MapStr{
"monitor": common.MapStr{
"type": "icmp",
=======
"hints": mapstr.M{
"monitor": mapstr.M{
"type": "http",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
"hosts": "${data.host}:8888,${data.host}:${data.port}",
},
},
},
len: 1,
<<<<<<< HEAD
result: common.MapStr{
"type": "icmp",
=======
result: mapstr.M{
"type": "http",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
"schedule": "@every 5s",
"hosts": []interface{}{"1.2.3.4:9090"},
"hosts": []interface{}{"1.2.3.4:8888", "1.2.3.4:9090"},
},
},
{
message: "Monitor defined in monitors as a JSON string should return a config",
event: bus.Event{
"host": "1.2.3.4",
<<<<<<< HEAD
"hints": common.MapStr{
"monitor": common.MapStr{
"raw": "{\"enabled\":true,\"type\":\"icmp\",\"schedule\":\"@every 20s\",\"timeout\":\"3s\"}",
=======
"hints": mapstr.M{
"monitor": mapstr.M{
"raw": "{\"enabled\":true,\"type\":\"http\",\"schedule\":\"@every 20s\",\"timeout\":\"3s\"}",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
},
},
},
len: 1,
<<<<<<< HEAD
result: common.MapStr{
"type": "icmp",
=======
result: mapstr.M{
"type": "http",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
"timeout": "3s",
"schedule": "@every 20s",
"enabled": true,
Expand All @@ -146,9 +186,15 @@ func TestGenerateHints(t *testing.T) {
event: bus.Event{
"host": "1.2.3.4",
"port": 9090,
<<<<<<< HEAD
"hints": common.MapStr{
"monitor": common.MapStr{
"type": "icmp",
=======
"hints": mapstr.M{
"monitor": mapstr.M{
"type": "http",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
"hosts": "${data.host}:9090",
"processors": common.MapStr{
"add_locale": common.MapStr{
Expand All @@ -159,8 +205,13 @@ func TestGenerateHints(t *testing.T) {
},
},
len: 1,
<<<<<<< HEAD
result: common.MapStr{
"type": "icmp",
=======
result: mapstr.M{
"type": "http",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
"hosts": []interface{}{"1.2.3.4:9090"},
"schedule": "@every 5s",
"processors": []interface{}{
Expand All @@ -177,6 +228,7 @@ func TestGenerateHints(t *testing.T) {
event: bus.Event{
"host": "1.2.3.4",
"port": 9090,
<<<<<<< HEAD
"hints": common.MapStr{
"monitor": common.MapStr{
"1": common.MapStr{
Expand All @@ -185,18 +237,54 @@ func TestGenerateHints(t *testing.T) {
},
"2": common.MapStr{
"type": "icmp",
=======
"hints": mapstr.M{
"monitor": mapstr.M{
"1": mapstr.M{
"type": "http",
"hosts": "${data.host}:8888,${data.host}:9090",
},
"2": mapstr.M{
"type": "http",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
"hosts": "${data.host}:8888,${data.host}:9090",
},
},
},
},
len: 2,
<<<<<<< HEAD
result: common.MapStr{
"type": "icmp",
=======
result: mapstr.M{
"type": "http",
>>>>>>> 9d9f8dc5a1 ([Heartbeat] Fix hint-based monitor gen (#34376))
"schedule": "@every 5s",
"hosts": []interface{}{"1.2.3.4:9090"},
"hosts": []interface{}{"1.2.3.4:8888", "1.2.3.4:9090"},
},
},
{
message: "Hints for ICMP with port should return nothing",
event: bus.Event{
"host": "1.2.3.4",
"port": 9090,
"hints": mapstr.M{
"monitor": mapstr.M{
"1": mapstr.M{
"type": "icmp",
"hosts": "${data.host}:9090",
},
"2": mapstr.M{
"type": "icmp",
"hosts": "${data.host}:${data.port}",
},
},
},
},
len: 0,
result: mapstr.M{},
},
}
for _, test := range tests {

Expand All @@ -205,7 +293,7 @@ func TestGenerateHints(t *testing.T) {
logger: logp.L(),
}
cfgs := m.CreateConfig(test.event)
assert.Equal(t, len(cfgs), test.len, test.message)
assert.Equal(t, test.len, len(cfgs), test.message)

if len(cfgs) != 0 {
config := common.MapStr{}
Expand Down

0 comments on commit d2f2de0

Please sign in to comment.