Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cmd/icinga-notifications-daemon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/icinga/icinga-notifications/internal/channel"
"github.com/icinga/icinga-notifications/internal/config"
"github.com/icinga/icinga-notifications/internal/daemon"
"github.com/icinga/icinga-notifications/internal/incident"
"github.com/icinga/icinga-notifications/internal/listener"
"github.com/icinga/icingadb/pkg/logging"
"github.com/icinga/icingadb/pkg/utils"
Expand Down Expand Up @@ -91,6 +92,11 @@ func main() {

go runtimeConfig.PeriodicUpdates(ctx, 1*time.Second)

err = incident.LoadOpenIncidents(ctx, db, logs.GetChildLogger("incident"), runtimeConfig)
if err != nil {
logger.Fatalw("Can't load incidents from database", zap.Error(err))
}

if err := listener.NewListener(db, runtimeConfig, logs).Run(ctx); err != nil {
logger.Errorw("Listener has finished with an error", zap.Error(err))
} else {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/icinga/icinga-notifications

go 1.20
go 1.21

require (
github.com/creasty/defaults v1.7.0
Expand Down
1 change: 1 addition & 0 deletions internal/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Event struct {
const (
TypeState = "state"
TypeAcknowledgement = "acknowledgement"
TypeInternal = "internal"
)

func (e *Event) String() string {
Expand Down
1 change: 1 addition & 0 deletions internal/filter/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ type Filterable interface {
// Filter is implemented by every filter chains and filter conditions.
type Filter interface {
Eval(filterable Filterable) (bool, error)
ExtractConditions() []*Condition
}
32 changes: 16 additions & 16 deletions internal/filter/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Parser struct {
func Parse(expression string) (Filter, error) {
parser := &Parser{tag: expression, length: len(expression)}
if parser.length == 0 {
return &All{}, nil
return &Chain{op: All}, nil
}

return parser.readFilter(0, "", nil)
Expand Down Expand Up @@ -97,7 +97,7 @@ func (p *Parser) readFilter(nestingLevel int, operator string, rules []Filter) (
if operator != "!" && (next == "&" || next == "|") {
if operator == "&" {
if len(rules) > 1 {
rules = []Filter{&All{rules: rules}}
rules = []Filter{&Chain{op: All, rules: rules}}
}

operator = next
Expand All @@ -122,7 +122,7 @@ func (p *Parser) readFilter(nestingLevel int, operator string, rules []Filter) (
} else {
if negate {
negate = false
rules = append(rules, &None{rules: []Filter{condition}})
rules = append(rules, &Chain{op: None, rules: []Filter{condition}})
} else {
rules = append(rules, condition)
}
Expand Down Expand Up @@ -154,7 +154,7 @@ func (p *Parser) readFilter(nestingLevel int, operator string, rules []Filter) (
if next == "&" || next == "|" {
if operator == "" || operator == "&" {
if operator == "&" && len(rules) > 1 {
all := &All{rules: rules}
all := &Chain{op: All, rules: rules}
rules = []Filter{all}
}

Expand Down Expand Up @@ -195,18 +195,18 @@ func (p *Parser) readFilter(nestingLevel int, operator string, rules []Filter) (
var chain Filter
switch operator {
case "&":
chain = &All{rules: rules}
chain = &Chain{op: All, rules: rules}
case "|":
chain = &Any{rules: rules}
chain = &Chain{op: Any, rules: rules}
case "!":
chain = &None{rules: rules}
chain = &Chain{op: None, rules: rules}
case "":
if nestingLevel == 0 && rules != nil {
// There is only one filter tag, no chain
return rules[0], nil
}

chain = &All{rules: rules}
chain = &Chain{op: All, rules: rules}
default:
return nil, p.parseError(operator, "")
}
Expand Down Expand Up @@ -257,24 +257,24 @@ func (p *Parser) createCondition(column string, operator string, value string) (
switch operator {
case "=":
if strings.Contains(value, "*") {
return &Like{column: column, value: value}, nil
return &Condition{op: Like, column: column, value: value}, nil
}

return &Equal{column: column, value: value}, nil
return &Condition{op: Equal, column: column, value: value}, nil
case "!=":
if strings.Contains(value, "*") {
return &Unlike{column: column, value: value}, nil
return &Condition{op: UnLike, column: column, value: value}, nil
}

return &UnEqual{column: column, value: value}, nil
return &Condition{op: UnEqual, column: column, value: value}, nil
case ">":
return &GreaterThan{column: column, value: value}, nil
return &Condition{op: GreaterThan, column: column, value: value}, nil
case ">=":
return &GreaterThanOrEqual{column: column, value: value}, nil
return &Condition{op: GreaterThanEqual, column: column, value: value}, nil
case "<":
return &LessThan{column: column, value: value}, nil
return &Condition{op: LessThan, column: column, value: value}, nil
case "<=":
return &LessThanOrEqual{column: column, value: value}, nil
return &Condition{op: LessThanEqual, column: column, value: value}, nil
default:
return nil, fmt.Errorf("invalid operator %s provided", operator)
}
Expand Down
68 changes: 40 additions & 28 deletions internal/filter/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,101 +62,113 @@ func TestFilter(t *testing.T) {
t.Run("ParserIdentifiesAllKindOfFilters", func(t *testing.T) {
rule, err := Parse("foo=bar")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &Equal{}, rule)
expected := &Condition{op: Equal, column: "foo", value: "bar"}
assert.Equal(t, expected, rule)

rule, err = Parse("foo!=bar")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &UnEqual{}, rule)
expected = &Condition{op: UnEqual, column: "foo", value: "bar"}
assert.Equal(t, expected, rule)

rule, err = Parse("foo=bar*")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &Like{}, rule)
expected = &Condition{op: Like, column: "foo", value: "bar*"}
assert.Equal(t, expected, rule)

rule, err = Parse("foo!=bar*")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &Unlike{}, rule)
expected = &Condition{op: UnLike, column: "foo", value: "bar*"}
assert.Equal(t, expected, rule)

rule, err = Parse("foo<bar")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &LessThan{}, rule)
expected = &Condition{op: LessThan, column: "foo", value: "bar"}
assert.Equal(t, expected, rule)

rule, err = Parse("foo<=bar")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &LessThanOrEqual{}, rule)
expected = &Condition{op: LessThanEqual, column: "foo", value: "bar"}
assert.Equal(t, expected, rule)

rule, err = Parse("foo>bar")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &GreaterThan{}, rule)
expected = &Condition{op: GreaterThan, column: "foo", value: "bar"}
assert.Equal(t, expected, rule)

rule, err = Parse("foo>=bar")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &GreaterThanOrEqual{}, rule)
expected = &Condition{op: GreaterThanEqual, column: "foo", value: "bar"}
assert.Equal(t, expected, rule)

rule, err = Parse("foo=bar&bar=foo")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &All{}, rule)
assert.IsType(t, &Chain{}, rule)

rule, err = Parse("foo=bar|bar=foo")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &Any{}, rule)
assert.IsType(t, &Chain{}, rule)

rule, err = Parse("!(foo=bar|bar=foo)")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.IsType(t, &None{}, rule)
assert.IsType(t, &Chain{}, rule)
Comment on lines 103 to +113
Copy link
Collaborator

Choose a reason for hiding this comment

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

These should now also check rule.op.

Copy link
Member Author

Choose a reason for hiding this comment

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

Just ignore theses! There's an extended test case in the other PR.


rule, err = Parse("!foo")
assert.Nil(t, err, "There should be no errors but got: %s", err)

assert.Equal(t, &None{rules: []Filter{NewExists("foo")}}, rule)
assert.Equal(t, &Chain{op: None, rules: []Filter{NewExists("foo")}}, rule)

rule, err = Parse("foo")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.Equal(t, NewExists("foo"), rule)
assert.Equal(t, &Exists{column: "foo"}, rule)

rule, err = Parse("!(foo=bar|bar=foo)&(foo=bar|bar=foo)")
assert.Nil(t, err, "There should be no errors but got: %s", err)

expected := &All{rules: []Filter{
&None{rules: []Filter{
&Equal{column: "foo", value: "bar"},
&Equal{column: "bar", value: "foo"},
expectedChain := &Chain{op: All, rules: []Filter{
&Chain{op: None, rules: []Filter{
&Condition{op: Equal, column: "foo", value: "bar"},
&Condition{op: Equal, column: "bar", value: "foo"},
}},
&Any{rules: []Filter{
&Equal{column: "foo", value: "bar"},
&Equal{column: "bar", value: "foo"},
&Chain{op: Any, rules: []Filter{
&Condition{op: Equal, column: "foo", value: "bar"},
&Condition{op: Equal, column: "bar", value: "foo"},
}},
}}
assert.Equal(t, expected, rule)
assert.Equal(t, expectedChain, rule)
})

t.Run("ParserIdentifiesSingleCondition", func(t *testing.T) {
rule, err := Parse("foo=bar")
assert.Nil(t, err, "There should be no errors but got: %s", err)

expected := &Equal{column: "foo", value: "bar"}
expected := &Condition{op: Equal, column: "foo", value: "bar"}
assert.Equal(t, expected, rule, "Parser doesn't parse single condition correctly")
})

t.Run("UrlEncodedFilterExpression", func(t *testing.T) {
rule, err := Parse("col%3Cumn<val%3Cue")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.Equal(t, &LessThan{column: "col<umn", value: "val<ue"}, rule)
expected := &Condition{op: LessThan, column: "col<umn", value: "val<ue"}
assert.Equal(t, expected, rule)

rule, err = Parse("col%7Cumn=val%7Cue")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.Equal(t, &Equal{column: "col|umn", value: "val|ue"}, rule)
expected = &Condition{op: Equal, column: "col|umn", value: "val|ue"}
assert.Equal(t, expected, rule)

rule, err = Parse("col%26umn<=val%26ue")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.Equal(t, &LessThanOrEqual{column: "col&umn", value: "val&ue"}, rule)
expected = &Condition{op: LessThanEqual, column: "col&umn", value: "val&ue"}
assert.Equal(t, expected, rule)

rule, err = Parse("col%28umn>val%28ue")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.Equal(t, &GreaterThan{column: "col(umn", value: "val(ue"}, rule)
expected = &Condition{op: GreaterThan, column: "col(umn", value: "val(ue"}
assert.Equal(t, expected, rule)

rule, err = Parse("col%29umn>=val%29ue")
assert.Nil(t, err, "There should be no errors but got: %s", err)
assert.Equal(t, &GreaterThanOrEqual{column: "col)umn", value: "val)ue"}, rule)
expected = &Condition{op: GreaterThanEqual, column: "col)umn", value: "val)ue"}
assert.Equal(t, expected, rule)
})
}

Expand Down
Loading