diff --git a/internal/reconciler/logpipeline/fluentbit/reconciler_test.go b/internal/reconciler/logpipeline/fluentbit/reconciler_test.go index a4f72565b..2786f2b1e 100644 --- a/internal/reconciler/logpipeline/fluentbit/reconciler_test.go +++ b/internal/reconciler/logpipeline/fluentbit/reconciler_test.go @@ -4,6 +4,9 @@ import ( "context" "errors" "fmt" + "os" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" "testing" "time" @@ -1076,3 +1079,60 @@ func TestCalculateChecksum(t *testing.T) { require.NotEqualf(t, checksum, newChecksum, "Checksum not changed by updating certificate secret") }) } + +func TestCreateOrUpdateFluentBit(t *testing.T) { + var objects []client.Object + var logPipe telemetryv1alpha1.LogPipeline + scheme := runtime.NewScheme() + _ = clientgoscheme.AddToScheme(scheme) + _ = telemetryv1alpha1.AddToScheme(scheme) + pipeline := testutils.NewLogPipelineBuilder().WithName("test-fluentbit-resources").WithFinalizer("FLUENT_BIT_SECTIONS_CONFIG_MAP").WithCustomFilter("Name grep").Build() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&pipeline).WithStatusSubresource(&pipeline).WithInterceptorFuncs(interceptor.Funcs{ + Create: func(ctx context.Context, c client.WithWatch, obj client.Object, _ ...client.CreateOption) error { + objects = append(objects, obj) + return c.Create(ctx, obj) + }, + }).Build() + + proberStub := commonStatusStubs.NewDaemonSetProber(nil) + + flowHealthProberStub := &logpipelinemocks.FlowHealthProber{} + flowHealthProberStub.On("Probe", mock.Anything, pipeline.Name).Return(prober.LogPipelineProbeResult{}, nil) + + istioStatusCheckerStub := &stubs.IstioStatusChecker{IsActive: false} + + pipelineValidatorWithStubs := &Validator{ + EndpointValidator: stubs.NewEndpointValidator(nil), + TLSCertValidator: stubs.NewTLSCertValidator(nil), + SecretRefValidator: stubs.NewSecretRefValidator(nil), + } + + testConfig := Config{ + DaemonSet: types.NamespacedName{Name: "test-telemetry-fluent-bit", Namespace: "default"}, + SectionsConfigMap: types.NamespacedName{Name: "test-telemetry-fluent-bit-sections", Namespace: "default"}, + FilesConfigMap: types.NamespacedName{Name: "test-telemetry-fluent-bit-files", Namespace: "default"}, + LuaConfigMap: types.NamespacedName{Name: "test-telemetry-fluent-bit-lua", Namespace: "default"}, + ParsersConfigMap: types.NamespacedName{Name: "test-telemetry-fluent-bit-parsers", Namespace: "default"}, + EnvConfigSecret: types.NamespacedName{Name: "test-telemetry-fluent-bit-env", Namespace: "default"}, + TLSFileConfigSecret: types.NamespacedName{Name: "test-telemetry-fluent-bit-output-tls-config", Namespace: "default"}, + DaemonSetConfig: fluentbit.DaemonSetConfig{ + FluentBitImage: "fluent/bit:latest", + ExporterImage: "exporter:latest", + }, + } + errToMsgStub := &logpipelinemocks.ErrorToMessageConverter{} + + sut := New(fakeClient, testConfig, proberStub, flowHealthProberStub, istioStatusCheckerStub, pipelineValidatorWithStubs, errToMsgStub) + require.NoError(t, fakeClient.Get(context.Background(), types.NamespacedName{Name: pipeline.Name}, &logPipe)) + + err := sut.Reconcile(context.Background(), &logPipe) + require.NoError(t, err) + + bytes, err := testutils.MarshalYAML(scheme, objects) + require.NoError(t, err) + + goldenFileBytes, err := os.ReadFile("testdata/fluent-bit.yaml") + require.NoError(t, err) + + require.Equal(t, string(goldenFileBytes), string(bytes)) +} diff --git a/internal/reconciler/logpipeline/fluentbit/testdata/fluent-bit.yaml b/internal/reconciler/logpipeline/fluentbit/testdata/fluent-bit.yaml new file mode 100644 index 000000000..3f7ddfd3e --- /dev/null +++ b/internal/reconciler/logpipeline/fluentbit/testdata/fluent-bit.yaml @@ -0,0 +1,464 @@ +apiVersion: v1 +data: + custom_parsers.conf: |2 + + [PARSER] + Name docker_no_time + Format json + Time_Keep Off + Time_Key time + Time_Format %Y-%m-%dT%H:%M:%S.%L + fluent-bit.conf: |2 + + [SERVICE] + Daemon Off + Flush 1 + Log_Level warn + Parsers_File custom_parsers.conf + Parsers_File dynamic-parsers/parsers.conf + HTTP_Server On + HTTP_Listen 0.0.0.0 + HTTP_Port 2020 + storage.path /data/flb-storage/ + storage.metrics on + + @INCLUDE dynamic/*.conf +kind: ConfigMap +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + name: test-telemetry-fluent-bit + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +--- +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: null + name: test-telemetry-fluent-bit-files + namespace: default + resourceVersion: "1" +--- +apiVersion: v1 +data: + filter-script.lua: |2 + + function kubernetes_map_keys(tag, timestamp, record) + if record.kubernetes == nil then + return 0 + end + map_keys(record.kubernetes.annotations) + map_keys(record.kubernetes.labels) + return 1, timestamp, record + end + function map_keys(table) + if table == nil then + return + end + local new_table = {} + local changed_keys = {} + for key, val in pairs(table) do + local mapped_key = string.gsub(key, "[%/%.]", "_") + if mapped_key ~= key then + new_table[mapped_key] = val + changed_keys[key] = true + end + end + for key in pairs(changed_keys) do + table[key] = nil + end + for key, val in pairs(new_table) do + table[key] = val + end + end +kind: ConfigMap +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + name: test-telemetry-fluent-bit-lua + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +--- +apiVersion: v1 +data: + parsers.conf: "" +kind: ConfigMap +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + name: test-telemetry-fluent-bit-parsers + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +--- +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: null + name: test-telemetry-fluent-bit-sections + namespace: default + resourceVersion: "1" +--- +apiVersion: v1 +kind: Secret +metadata: + creationTimestamp: null + name: test-telemetry-fluent-bit-env + namespace: default + resourceVersion: "1" +--- +apiVersion: v1 +kind: Secret +metadata: + creationTimestamp: null + name: test-telemetry-fluent-bit-output-tls-config + namespace: default + resourceVersion: "1" +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/port: "2021" + prometheus.io/scheme: http + prometheus.io/scrape: "true" + creationTimestamp: null + labels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + telemetry.kyma-project.io/self-monitor: enabled + name: test-telemetry-fluent-bit-exporter-metrics + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +spec: + ports: + - name: http-metrics + port: 2021 + protocol: TCP + targetPort: http-metrics + selector: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + type: ClusterIP +status: + loadBalancer: {} +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/path: /api/v2/metrics/prometheus + prometheus.io/port: "2020" + prometheus.io/scheme: http + prometheus.io/scrape: "true" + creationTimestamp: null + labels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + telemetry.kyma-project.io/self-monitor: enabled + name: test-telemetry-fluent-bit-metrics + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +spec: + ports: + - name: http + port: 2020 + protocol: TCP + targetPort: http + selector: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + type: ClusterIP +status: + loadBalancer: {} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + creationTimestamp: null + name: test-telemetry-fluent-bit + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + name: test-telemetry-fluent-bit + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +spec: + selector: + matchLabels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + template: + metadata: + annotations: + checksum/logpipeline-config: 52bae9e75e172cfba38acdcb7da0e183a3450464ec2b7d821a46cb46dfd11e6f + traffic.sidecar.istio.io/excludeInboundPorts: 2020,2021 + creationTimestamp: null + labels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + sidecar.istio.io/inject: "true" + telemetry.kyma-project.io/log-export: "true" + spec: + containers: + - envFrom: + - secretRef: + name: test-telemetry-fluent-bit-env + optional: true + image: fluent/bit:latest + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: / + port: http + name: fluent-bit + ports: + - containerPort: 2020 + name: http + protocol: TCP + readinessProbe: + httpGet: + path: /api/v1/health + port: http + resources: + limits: + cpu: "0" + memory: "0" + requests: + cpu: "0" + memory: "0" + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - FOWNER + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /fluent-bit/etc + name: shared-fluent-bit-config + - mountPath: /fluent-bit/etc/fluent-bit.conf + name: config + subPath: fluent-bit.conf + - mountPath: /fluent-bit/etc/dynamic/ + name: dynamic-config + - mountPath: /fluent-bit/etc/dynamic-parsers/ + name: dynamic-parsers-config + - mountPath: /fluent-bit/etc/custom_parsers.conf + name: config + subPath: custom_parsers.conf + - mountPath: /fluent-bit/scripts/filter-script.lua + name: luascripts + subPath: filter-script.lua + - mountPath: /var/log + name: varlog + readOnly: true + - mountPath: /data + name: varfluentbit + - mountPath: /files + name: dynamic-files + - mountPath: /fluent-bit/etc/output-tls-config/ + name: output-tls-config + readOnly: true + - args: + - --storage-path=/data/flb-storage/ + - --metric-name=telemetry_fsbuffer_usage_bytes + image: exporter:latest + name: exporter + ports: + - containerPort: 2021 + name: http-metrics + protocol: TCP + resources: + limits: + cpu: 100m + memory: 50Mi + requests: + cpu: 1m + memory: 5Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /data + name: varfluentbit + securityContext: + runAsNonRoot: false + seccompProfile: + type: RuntimeDefault + serviceAccountName: test-telemetry-fluent-bit + volumes: + - configMap: + name: test-telemetry-fluent-bit + name: config + - configMap: + name: test-telemetry-fluent-bit-luascripts + name: luascripts + - hostPath: + path: /var/log + name: varlog + - emptyDir: {} + name: shared-fluent-bit-config + - configMap: + name: test-telemetry-fluent-bit-sections + optional: true + name: dynamic-config + - configMap: + name: test-telemetry-fluent-bit-parsers + optional: true + name: dynamic-parsers-config + - configMap: + name: test-telemetry-fluent-bit-files + optional: true + name: dynamic-files + - hostPath: + path: /var/test-telemetry-fluent-bit + name: varfluentbit + - name: output-tls-config + secret: + secretName: test-telemetry-fluent-bit-output-tls-config + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + name: test-telemetry-fluent-bit + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +spec: + egress: + - to: + - ipBlock: + cidr: 0.0.0.0/0 + - ipBlock: + cidr: ::/0 + ingress: + - from: + - ipBlock: + cidr: 0.0.0.0/0 + - ipBlock: + cidr: ::/0 + ports: + - port: 2021 + protocol: TCP + - port: 2020 + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/instance: telemetry + app.kubernetes.io/name: fluent-bit + policyTypes: + - Ingress + - Egress +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: test-telemetry-fluent-bit + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +rules: +- apiGroups: + - "" + resources: + - namespaces + - pods + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + creationTimestamp: null + name: test-telemetry-fluent-bit + namespace: default + ownerReferences: + - apiVersion: telemetry.kyma-project.io/v1alpha1 + kind: LogPipeline + name: test-fluentbit-resources + uid: "" + resourceVersion: "1" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: test-telemetry-fluent-bit +subjects: +- kind: ServiceAccount + name: test-telemetry-fluent-bit + namespace: default +---