Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 24 additions & 1 deletion pipeline/doif/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ pipelines:
case_sensitive: true
```


## Field operations
**`Equal`** checks whether the field value is equal to one of the elements in the values list.

Expand Down Expand Up @@ -102,6 +101,30 @@ result:

<br>

**`ContainsAny`** checks whether the field value contains any of the value characters.

Example:
```yaml
pipelines:
test:
actions:
- type: discard
do_if:
op: contains_any
field: service
values: ['!$#']
```

result:
```
{"pod":"test-pod","service":"test-service!"} # discarded
{"pod":"test-pod","service":"#my_service#"} # discarded
{"pod":"test-pod","service":"$$$"} # discarded
{"pod":"test-pod","service":"test-service-1"} # not discarded
```

<br>

**`Prefix`** checks whether the field value has prefix equal to one of the elements in the values list.

Example:
Expand Down
2 changes: 2 additions & 0 deletions pipeline/doif/check_type_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ result:
```
}*/

const checkTypeOpTag = "check_type"

type checkTypeVal int

const (
Expand Down
18 changes: 5 additions & 13 deletions pipeline/doif/ctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,15 @@ func extractDoIfNode(node map[string]any) (Node, error) {
}

switch opName {
case "and", "or", "not":
case logicalAndTag, logicalOrTag, logicalNotTag:
return extractLogicalOpNode(opName, node)
case
"equal",
"contains",
"prefix",
"suffix",
"regex":
case fieldEqualOpTag, fieldContainsOpTag, fieldContainsAnyOpTag, fieldPrefixOpTag, fieldSuffixOpTag, fieldRegexOpTag:
return extractFieldOpNode(opName, node)
case
"byte_len_cmp",
"array_len_cmp",
"int_val_cmp":
case byteLenCmpOpTag, arrayLenCmpOpTag, intValCmpOpTag:
return extractLengthCmpOpNode(opName, node)
case "ts_cmp":
case tsCmpOpTag:
return extractTsCmpOpNode(opName, node)
case "check_type":
case checkTypeOpTag:
return extractCheckTypeOpNode(opName, node)
default:
return nil, fmt.Errorf("unknown op: %s", opName)
Expand Down
32 changes: 32 additions & 0 deletions pipeline/doif/do_if_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,24 @@ func TestBuildNodes(t *testing.T) {
},
wantErr: true,
},
{
name: "err_field_op_node_containsany_invalid_values_len",
tree: treeNode{
fieldOp: "contains_any",
fieldName: "pod",
values: [][]byte{[]byte(`1`), []byte(`2`)},
},
wantErr: true,
},
{
name: "err_field_op_node_containsany_empty_value",
tree: treeNode{
fieldOp: "contains_any",
fieldName: "pod",
values: [][]byte{[]byte("")},
},
wantErr: true,
},
{
name: "err_field_op_node_invalid_op_type",
tree: treeNode{
Expand Down Expand Up @@ -581,6 +599,20 @@ func TestCheck(t *testing.T) {
{`{"pod":"my-TEST-2-pod"}`, false},
},
},
{
name: "contains_any",
tree: treeNode{
fieldOp: "contains_any",
fieldName: "pod",
values: [][]byte{[]byte("!#$")},
},
data: []argsResp{
{`{"pod":"my-test-pod!"}`, true},
{`{"pod":"#my-test-pod#"}`, true},
{`{"pod":"$$$"}`, true},
{`{"pod":"my-test-pod"}`, false},
},
},
{
name: "prefix",
tree: treeNode{
Expand Down
50 changes: 43 additions & 7 deletions pipeline/doif/field_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
fieldUnknownOp fieldOpType = iota
fieldEqualOp
fieldContainsOp
fieldContainsAnyOp
fieldPrefixOp
fieldSuffixOp
fieldRegexOp
Expand All @@ -27,15 +28,17 @@ const (
func (t fieldOpType) String() string {
switch t {
case fieldEqualOp:
return "equal"
return fieldEqualOpTag
case fieldContainsOp:
return "contains"
return fieldContainsOpTag
case fieldContainsAnyOp:
return fieldContainsAnyOpTag
case fieldPrefixOp:
return "prefix"
return fieldPrefixOpTag
case fieldSuffixOp:
return "suffix"
return fieldSuffixOpTag
case fieldRegexOp:
return "regex"
return fieldRegexOpTag
default:
return "unknown"
}
Expand Down Expand Up @@ -88,6 +91,29 @@ const (
// > ```
fieldContainsOpTag = "contains" // *

// > checks whether the field value contains any of the value characters.
// >
// > Example:
// > ```yaml
// > pipelines:
// > test:
// > actions:
// > - type: discard
// > do_if:
// > op: contains_any
// > field: service
// > values: ['!$#']
// > ```
// >
// > result:
// > ```
// > {"pod":"test-pod","service":"test-service!"} # discarded
// > {"pod":"test-pod","service":"#my_service#"} # discarded
// > {"pod":"test-pod","service":"$$$"} # discarded
// > {"pod":"test-pod","service":"test-service-1"} # not discarded
// > ```
fieldContainsAnyOpTag = "contains_any" // *

// > checks whether the field value has prefix equal to one of the elements in the values list.
// >
// > Example:
Expand Down Expand Up @@ -184,7 +210,6 @@ pipelines:
values: [pod-1, pod-2]
case_sensitive: true
```

}*/

type fieldOpNode struct {
Expand Down Expand Up @@ -217,6 +242,11 @@ func NewFieldOpNode(op string, field string, caseSensitive bool, values [][]byte
fop = fieldEqualOp
case fieldContainsOpTag:
fop = fieldContainsOp
case fieldContainsAnyOpTag:
fop = fieldContainsAnyOp
if len(values) != 1 || len(values[0]) == 0 {
return nil, errors.New("contains_any op must have only 1 non-empty value")
}
case fieldPrefixOpTag:
fop = fieldPrefixOp
case fieldSuffixOpTag:
Expand Down Expand Up @@ -286,7 +316,8 @@ func (n *fieldOpNode) Type() NodeType {
func (n *fieldOpNode) Check(data Data) bool {
eventData := data.Get(n.fieldPath...)
// fast check for data
if n.op != fieldRegexOp && len(eventData) < n.minValLen {
if n.op != fieldRegexOp && n.op != fieldContainsAnyOp &&
len(eventData) < n.minValLen {
return false
}
switch n.op {
Expand Down Expand Up @@ -317,6 +348,11 @@ func (n *fieldOpNode) Check(data Data) bool {
return true
}
}
case fieldContainsAnyOp:
if !n.caseSensitive {
eventData = bytes.ToLower(eventData)
}
return bytes.ContainsAny(eventData, string(n.values[0]))
case fieldPrefixOp:
// check only necessary amount of bytes
if len(eventData) > n.maxValLen {
Expand Down
2 changes: 2 additions & 0 deletions pipeline/doif/ts_cmp_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ Result:
```
}*/

const tsCmpOpTag = "ts_cmp"

type cmpValueChangingMode int

const (
Expand Down
Loading