diff --git a/pkg/sdk/logging/api/v1beta1/syslogng_flow_types.go b/pkg/sdk/logging/api/v1beta1/syslogng_flow_types.go index 231c207dc..c3a3499e4 100644 --- a/pkg/sdk/logging/api/v1beta1/syslogng_flow_types.go +++ b/pkg/sdk/logging/api/v1beta1/syslogng_flow_types.go @@ -39,6 +39,11 @@ type SyslogNGFlowSpec struct { type SyslogNGMatch filter.MatchExpr +// IsEmpty returns true if the match is not specified, i.e. empty. +func (m *SyslogNGMatch) IsEmpty() bool { + return (*filter.MatchExpr)(m).IsEmpty() +} + // Filter definition for SyslogNGFlowSpec type SyslogNGFilter struct { ID string `json:"id,omitempty" syslog-ng:"ignore"` diff --git a/pkg/sdk/logging/model/syslogng/config/flow.go b/pkg/sdk/logging/model/syslogng/config/flow.go index 41053c4d7..35b329a90 100644 --- a/pkg/sdk/logging/model/syslogng/config/flow.go +++ b/pkg/sdk/logging/model/syslogng/config/flow.go @@ -20,11 +20,11 @@ import ( "strconv" "strings" + "github.com/cisco-open/operator-tools/pkg/secret" "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1" "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/syslogng/config/model" "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/syslogng/config/render" filter "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/syslogng/filter" - "github.com/cisco-open/operator-tools/pkg/secret" "github.com/siliconbrain/go-seqs/seqs" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -42,7 +42,7 @@ func renderClusterFlow(sourceName string, f v1beta1.SyslogNGClusterFlow, secretL []string{sourceName}, seqs.ToSlice(seqs.Concat( seqs.FromValues( - render.If(f.Spec.Match != nil, filterRefStmt(matchName)), + render.If(!f.Spec.Match.IsEmpty(), filterRefStmt(matchName)), ), seqs.MapWithIndex(seqs.FromSlice(f.Spec.Filters), func(idx int, flt v1beta1.SyslogNGFilter) render.Renderer { return parenDefStmt(filterKind(flt), render.Literal(filterID(flt, idx, baseName))) @@ -88,7 +88,7 @@ func renderFlow(controlNS string, sourceName string, keyDelim string, f v1beta1. } func renderFlowMatch(name string, m *v1beta1.SyslogNGMatch) render.Renderer { - if m == nil { + if m.IsEmpty() { return nil } return filterDefStmt(name, renderMatchExpr(filter.MatchExpr(*m))) diff --git a/pkg/sdk/logging/model/syslogng/config/flow_test.go b/pkg/sdk/logging/model/syslogng/config/flow_test.go new file mode 100644 index 000000000..d6ef5d7da --- /dev/null +++ b/pkg/sdk/logging/model/syslogng/config/flow_test.go @@ -0,0 +1,74 @@ +// Copyright © 2023 Kube logging authors +// +// Licensed 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 config + +import ( + "strings" + "testing" + + "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1" + "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/syslogng/config/render" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestRenderClusterFlow(t *testing.T) { + testCases := map[string]struct { + clusterFlow v1beta1.SyslogNGClusterFlow + expected string + }{ + "nil match": { + clusterFlow: v1beta1.SyslogNGClusterFlow{ + ObjectMeta: v1.ObjectMeta{ + Name: "test_clusterflow", + Namespace: "test_ns", + }, + Spec: v1beta1.SyslogNGClusterFlowSpec{ + Match: nil, + }, + }, + expected: Untab(`log { +source("test_input"); +}; +`), + }, + "empty match": { + clusterFlow: v1beta1.SyslogNGClusterFlow{ + ObjectMeta: v1.ObjectMeta{ + Name: "test_clusterflow", + Namespace: "test_ns", + }, + Spec: v1beta1.SyslogNGClusterFlowSpec{ + Match: &v1beta1.SyslogNGMatch{}, + }, + }, + expected: Untab(`log { +source("test_input"); +}; +`), + }, + } + for name, testCase := range testCases { + testCase := testCase + t.Run(name, func(t *testing.T) { + out := strings.Builder{} + require.NoError(t, renderClusterFlow("test_input", testCase.clusterFlow, nil)(render.RenderContext{ + Out: &out, + })) + assert.Equal(t, testCase.expected, out.String()) + }) + } +} diff --git a/pkg/sdk/logging/model/syslogng/filter/match.go b/pkg/sdk/logging/model/syslogng/filter/match.go index 6a5859a04..3299e38d7 100644 --- a/pkg/sdk/logging/model/syslogng/filter/match.go +++ b/pkg/sdk/logging/model/syslogng/filter/match.go @@ -49,6 +49,11 @@ type _metaMatch interface{} //nolint:deadcode,unused // +kubebuilder:object:generate=true type MatchConfig MatchExpr +// IsEmpty returns true if the config is not specified, i.e. empty. +func (c *MatchConfig) IsEmpty() bool { + return (*MatchExpr)(c).IsEmpty() +} + // +kubebuilder:object:generate=true type MatchExpr struct { // +kubebuilder:pruning:PreserveUnknownFields @@ -64,6 +69,11 @@ type MatchExpr struct { Or []MatchExpr `json:"or,omitempty"` } +// IsEmpty returns true if the expression is not specified, i.e. empty. +func (expr *MatchExpr) IsEmpty() bool { + return expr == nil || (len(expr.And) == 0 && expr.Not == nil && len(expr.Or) == 0 && expr.Regexp == nil) +} + // +kubebuilder:object:generate=true // +docName:"Regexp Directive" // Specify filtering rule. For details, see the [syslog-ng documentation](https://www.syslog-ng.com/technical-documents/doc/syslog-ng-open-source-edition/3.37/administration-guide/68#TOPIC-1829171).