From 609eb0afe862c52b09ac075c96d10c1d33d5cd8c Mon Sep 17 00:00:00 2001 From: "Mohamed S. Mahmoud" Date: Wed, 28 Feb 2024 14:09:21 -0500 Subject: [PATCH] NETOBSERV-557: add eBPF agent metrics for troubleshooting (#582) * NETOBSERV-557: add eBPF agent metrics for troubleshooting Signed-off-by: Mohamed Mahmoud * Fix managed objects use with agent controller * some doc fixes --------- Signed-off-by: Mohamed Mahmoud Co-authored-by: Joel Takvorian --- .../v1beta1/flowcollector_types.go | 14 + .../v1beta1/zz_generated.conversion.go | 42 ++ .../v1beta1/zz_generated.deepcopy.go | 22 + .../v1beta2/flowcollector_types.go | 14 + .../v1beta2/zz_generated.deepcopy.go | 22 + .../flows.netobserv.io_flowcollectors.yaml | 218 ++++++++ ...observ-operator.clusterserviceversion.yaml | 14 + .../flows.netobserv.io_flowcollectors.yaml | 218 ++++++++ .../samples/flows_v1beta2_flowcollector.yaml | 4 + .../consoleplugin/consoleplugin_objects.go | 4 +- controllers/constants/constants.go | 10 +- controllers/ebpf/agent-metrics-test.go | 47 ++ controllers/ebpf/agent-metrics.go | 97 ++++ controllers/ebpf/agent_controller.go | 56 +- .../flowcollector_controller_ebpf_test.go | 18 + .../flowcollector_controller_iso_test.go | 10 + controllers/flp/flp_common_objects.go | 2 +- docs/FlowCollector.md | 488 ++++++++++++++++++ pkg/helper/flowcollector.go | 4 + 19 files changed, 1288 insertions(+), 16 deletions(-) create mode 100644 controllers/ebpf/agent-metrics-test.go create mode 100644 controllers/ebpf/agent-metrics.go diff --git a/apis/flowcollector/v1beta1/flowcollector_types.go b/apis/flowcollector/v1beta1/flowcollector_types.go index a53e39399..d442f6fa8 100644 --- a/apis/flowcollector/v1beta1/flowcollector_types.go +++ b/apis/flowcollector/v1beta1/flowcollector_types.go @@ -158,6 +158,16 @@ const ( FlowRTT AgentFeature = "FlowRTT" ) +// `EBPFMetrics` defines the desired eBPF agent configuration regarding metrics +type EBPFMetrics struct { + // Metrics server endpoint configuration for Prometheus scraper + // +optional + Server MetricsServerConfig `json:"server,omitempty"` + + // Set `enable` to `true` to enable eBPF agent metrics collection. + Enable *bool `json:"enable,omitempty"` +} + // `FlowCollectorEBPF` defines a FlowCollector that uses eBPF to collect the flows information type FlowCollectorEBPF struct { // Important: Run "make generate" to regenerate code after modifying this file @@ -239,6 +249,10 @@ type FlowCollectorEBPF struct { // - `FlowRTT` [unsupported (*)]: enable flow latency (RTT) calculations in the eBPF agent during TCP handshakes. This feature better works with `sampling` set to 1.
// +optional Features []AgentFeature `json:"features,omitempty"` + + // `metrics` defines the eBPF agent configuration regarding metrics + // +optional + Metrics EBPFMetrics `json:"metrics,omitempty"` } // `FlowCollectorKafka` defines the desired Kafka config of FlowCollector diff --git a/apis/flowcollector/v1beta1/zz_generated.conversion.go b/apis/flowcollector/v1beta1/zz_generated.conversion.go index 65897b2f2..3033edea0 100644 --- a/apis/flowcollector/v1beta1/zz_generated.conversion.go +++ b/apis/flowcollector/v1beta1/zz_generated.conversion.go @@ -78,6 +78,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*EBPFMetrics)(nil), (*v1beta2.EBPFMetrics)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_EBPFMetrics_To_v1beta2_EBPFMetrics(a.(*EBPFMetrics), b.(*v1beta2.EBPFMetrics), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta2.EBPFMetrics)(nil), (*EBPFMetrics)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_EBPFMetrics_To_v1beta1_EBPFMetrics(a.(*v1beta2.EBPFMetrics), b.(*EBPFMetrics), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*FileReference)(nil), (*v1beta2.FileReference)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_FileReference_To_v1beta2_FileReference(a.(*FileReference), b.(*v1beta2.FileReference), scope) }); err != nil { @@ -415,6 +425,32 @@ func Convert_v1beta2_ConsolePluginPortConfig_To_v1beta1_ConsolePluginPortConfig( return autoConvert_v1beta2_ConsolePluginPortConfig_To_v1beta1_ConsolePluginPortConfig(in, out, s) } +func autoConvert_v1beta1_EBPFMetrics_To_v1beta2_EBPFMetrics(in *EBPFMetrics, out *v1beta2.EBPFMetrics, s conversion.Scope) error { + if err := Convert_v1beta1_MetricsServerConfig_To_v1beta2_MetricsServerConfig(&in.Server, &out.Server, s); err != nil { + return err + } + out.Enable = (*bool)(unsafe.Pointer(in.Enable)) + return nil +} + +// Convert_v1beta1_EBPFMetrics_To_v1beta2_EBPFMetrics is an autogenerated conversion function. +func Convert_v1beta1_EBPFMetrics_To_v1beta2_EBPFMetrics(in *EBPFMetrics, out *v1beta2.EBPFMetrics, s conversion.Scope) error { + return autoConvert_v1beta1_EBPFMetrics_To_v1beta2_EBPFMetrics(in, out, s) +} + +func autoConvert_v1beta2_EBPFMetrics_To_v1beta1_EBPFMetrics(in *v1beta2.EBPFMetrics, out *EBPFMetrics, s conversion.Scope) error { + if err := Convert_v1beta2_MetricsServerConfig_To_v1beta1_MetricsServerConfig(&in.Server, &out.Server, s); err != nil { + return err + } + out.Enable = (*bool)(unsafe.Pointer(in.Enable)) + return nil +} + +// Convert_v1beta2_EBPFMetrics_To_v1beta1_EBPFMetrics is an autogenerated conversion function. +func Convert_v1beta2_EBPFMetrics_To_v1beta1_EBPFMetrics(in *v1beta2.EBPFMetrics, out *EBPFMetrics, s conversion.Scope) error { + return autoConvert_v1beta2_EBPFMetrics_To_v1beta1_EBPFMetrics(in, out, s) +} + func autoConvert_v1beta1_FLPMetrics_To_v1beta2_FLPMetrics(in *FLPMetrics, out *v1beta2.FLPMetrics, s conversion.Scope) error { if err := Convert_v1beta1_MetricsServerConfig_To_v1beta2_MetricsServerConfig(&in.Server, &out.Server, s); err != nil { return err @@ -552,6 +588,9 @@ func autoConvert_v1beta1_FlowCollectorEBPF_To_v1beta2_FlowCollectorEBPF(in *Flow out.KafkaBatchSize = in.KafkaBatchSize // WARNING: in.Debug requires manual conversion: does not exist in peer-type out.Features = *(*[]v1beta2.AgentFeature)(unsafe.Pointer(&in.Features)) + if err := Convert_v1beta1_EBPFMetrics_To_v1beta2_EBPFMetrics(&in.Metrics, &out.Metrics, s); err != nil { + return err + } return nil } @@ -568,6 +607,9 @@ func autoConvert_v1beta2_FlowCollectorEBPF_To_v1beta1_FlowCollectorEBPF(in *v1be out.KafkaBatchSize = in.KafkaBatchSize // WARNING: in.Advanced requires manual conversion: does not exist in peer-type out.Features = *(*[]AgentFeature)(unsafe.Pointer(&in.Features)) + if err := Convert_v1beta2_EBPFMetrics_To_v1beta1_EBPFMetrics(&in.Metrics, &out.Metrics, s); err != nil { + return err + } return nil } diff --git a/apis/flowcollector/v1beta1/zz_generated.deepcopy.go b/apis/flowcollector/v1beta1/zz_generated.deepcopy.go index 48ebf3e72..6df931c4b 100644 --- a/apis/flowcollector/v1beta1/zz_generated.deepcopy.go +++ b/apis/flowcollector/v1beta1/zz_generated.deepcopy.go @@ -123,6 +123,27 @@ func (in *DebugConfig) DeepCopy() *DebugConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EBPFMetrics) DeepCopyInto(out *EBPFMetrics) { + *out = *in + in.Server.DeepCopyInto(&out.Server) + if in.Enable != nil { + in, out := &in.Enable, &out.Enable + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EBPFMetrics. +func (in *EBPFMetrics) DeepCopy() *EBPFMetrics { + if in == nil { + return nil + } + out := new(EBPFMetrics) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FLPMetrics) DeepCopyInto(out *FLPMetrics) { *out = *in @@ -282,6 +303,7 @@ func (in *FlowCollectorEBPF) DeepCopyInto(out *FlowCollectorEBPF) { *out = make([]AgentFeature, len(*in)) copy(*out, *in) } + in.Metrics.DeepCopyInto(&out.Metrics) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowCollectorEBPF. diff --git a/apis/flowcollector/v1beta2/flowcollector_types.go b/apis/flowcollector/v1beta2/flowcollector_types.go index 00f4f24a1..b94163fca 100644 --- a/apis/flowcollector/v1beta2/flowcollector_types.go +++ b/apis/flowcollector/v1beta2/flowcollector_types.go @@ -165,6 +165,16 @@ const ( FlowRTT AgentFeature = "FlowRTT" ) +// `EBPFMetrics` defines the desired eBPF agent configuration regarding metrics +type EBPFMetrics struct { + // Metrics server endpoint configuration for Prometheus scraper + // +optional + Server MetricsServerConfig `json:"server,omitempty"` + + // Set `enable` to `true` to enable eBPF agent metrics collection. + Enable *bool `json:"enable,omitempty"` +} + // `FlowCollectorEBPF` defines a FlowCollector that uses eBPF to collect the flows information type FlowCollectorEBPF struct { // Important: Run "make generate" to regenerate code after modifying this file @@ -246,6 +256,10 @@ type FlowCollectorEBPF struct { // - `FlowRTT`: enable flow latency (RTT) calculations in the eBPF agent during TCP handshakes. This feature better works with `sampling` set to 1.
// +optional Features []AgentFeature `json:"features,omitempty"` + + // `metrics` defines the eBPF agent configuration regarding metrics + // +optional + Metrics EBPFMetrics `json:"metrics,omitempty"` } // `FlowCollectorKafka` defines the desired Kafka config of FlowCollector diff --git a/apis/flowcollector/v1beta2/zz_generated.deepcopy.go b/apis/flowcollector/v1beta2/zz_generated.deepcopy.go index d659b863a..395eaee64 100644 --- a/apis/flowcollector/v1beta2/zz_generated.deepcopy.go +++ b/apis/flowcollector/v1beta2/zz_generated.deepcopy.go @@ -259,6 +259,27 @@ func (in *ConsolePluginPortConfig) DeepCopy() *ConsolePluginPortConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EBPFMetrics) DeepCopyInto(out *EBPFMetrics) { + *out = *in + in.Server.DeepCopyInto(&out.Server) + if in.Enable != nil { + in, out := &in.Enable, &out.Enable + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EBPFMetrics. +func (in *EBPFMetrics) DeepCopy() *EBPFMetrics { + if in == nil { + return nil + } + out := new(EBPFMetrics) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FLPMetrics) DeepCopyInto(out *FLPMetrics) { *out = *in @@ -417,6 +438,7 @@ func (in *FlowCollectorEBPF) DeepCopyInto(out *FlowCollectorEBPF) { *out = make([]AgentFeature, len(*in)) copy(*out, *in) } + in.Metrics.DeepCopyInto(&out.Metrics) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowCollectorEBPF. diff --git a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml index 9d4e478dc..ba829a68b 100644 --- a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml +++ b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml @@ -187,6 +187,115 @@ spec: - fatal - panic type: string + metrics: + description: '`metrics` defines the eBPF agent configuration + regarding metrics' + properties: + enable: + description: Set `enable` to `true` to enable eBPF agent + metrics collection. + type: boolean + server: + description: Metrics server endpoint configuration for + Prometheus scraper + properties: + port: + default: 9102 + description: The prometheus HTTP port + format: int32 + maximum: 65535 + minimum: 1 + type: integer + tls: + description: TLS configuration. + properties: + insecureSkipVerify: + default: false + description: '`insecureSkipVerify` allows skipping + client-side verification of the provided certificate. + If set to `true`, the `providedCaFile` field + is ignored.' + type: boolean + provided: + description: TLS configuration when `type` is + set to `PROVIDED`. + properties: + certFile: + description: '`certFile` defines the path + to the certificate file name within the + config map or secret' + type: string + certKey: + description: '`certKey` defines the path to + the certificate private key file name within + the config map or secret. Omit when the + key is not necessary.' + type: string + name: + description: Name of the config map or secret + containing certificates + type: string + namespace: + default: "" + description: Namespace of the config map or + secret containing certificates. If omitted, + the default is to use the same namespace + as where NetObserv is deployed. If the namespace + is different, the config map or the secret + is copied so that it can be mounted as required. + type: string + type: + description: 'Type for the certificate reference: + `configmap` or `secret`' + enum: + - configmap + - secret + type: string + type: object + providedCaFile: + description: Reference to the CA file when `type` + is set to `PROVIDED`. + properties: + file: + description: File name within the config map + or secret + type: string + name: + description: Name of the config map or secret + containing the file + type: string + namespace: + default: "" + description: Namespace of the config map or + secret containing the file. If omitted, + the default is to use the same namespace + as where NetObserv is deployed. If the namespace + is different, the config map or the secret + is copied so that it can be mounted as required. + type: string + type: + description: 'Type for the file reference: + "configmap" or "secret"' + enum: + - configmap + - secret + type: string + type: object + type: + default: DISABLED + description: Select the type of TLS configuration:
+ - `DISABLED` (default) to not configure TLS + for the endpoint. - `PROVIDED` to manually provide + cert file and a key file. - `AUTO` to use OpenShift + auto generated certificate using annotations. + enum: + - DISABLED + - PROVIDED + - AUTO + type: string + type: object + type: object + type: object privileged: description: Privileged mode for the eBPF Agent container. When ignored or set to `false`, the operator sets granular @@ -2882,6 +2991,115 @@ spec: - fatal - panic type: string + metrics: + description: '`metrics` defines the eBPF agent configuration + regarding metrics' + properties: + enable: + description: Set `enable` to `true` to enable eBPF agent + metrics collection. + type: boolean + server: + description: Metrics server endpoint configuration for + Prometheus scraper + properties: + port: + default: 9102 + description: The prometheus HTTP port + format: int32 + maximum: 65535 + minimum: 1 + type: integer + tls: + description: TLS configuration. + properties: + insecureSkipVerify: + default: false + description: '`insecureSkipVerify` allows skipping + client-side verification of the provided certificate. + If set to `true`, the `providedCaFile` field + is ignored.' + type: boolean + provided: + description: TLS configuration when `type` is + set to `Provided`. + properties: + certFile: + description: '`certFile` defines the path + to the certificate file name within the + config map or secret' + type: string + certKey: + description: '`certKey` defines the path to + the certificate private key file name within + the config map or secret. Omit when the + key is not necessary.' + type: string + name: + description: Name of the config map or secret + containing certificates + type: string + namespace: + default: "" + description: Namespace of the config map or + secret containing certificates. If omitted, + the default is to use the same namespace + as where NetObserv is deployed. If the namespace + is different, the config map or the secret + is copied so that it can be mounted as required. + type: string + type: + description: 'Type for the certificate reference: + `configmap` or `secret`' + enum: + - configmap + - secret + type: string + type: object + providedCaFile: + description: Reference to the CA file when `type` + is set to `Provided`. + properties: + file: + description: File name within the config map + or secret + type: string + name: + description: Name of the config map or secret + containing the file + type: string + namespace: + default: "" + description: Namespace of the config map or + secret containing the file. If omitted, + the default is to use the same namespace + as where NetObserv is deployed. If the namespace + is different, the config map or the secret + is copied so that it can be mounted as required. + type: string + type: + description: 'Type for the file reference: + "configmap" or "secret"' + enum: + - configmap + - secret + type: string + type: object + type: + default: Disabled + description: Select the type of TLS configuration:
+ - `Disabled` (default) to not configure TLS + for the endpoint. - `Provided` to manually provide + cert file and a key file. - `Auto` to use OpenShift + auto generated certificate using annotations. + enum: + - Disabled + - Provided + - Auto + type: string + type: object + type: object + type: object privileged: description: Privileged mode for the eBPF Agent container. When ignored or set to `false`, the operator sets granular diff --git a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml index ea009312b..d87e4f6d2 100644 --- a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml +++ b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml @@ -242,6 +242,12 @@ metadata: "interfaces": [], "kafkaBatchSize": 1048576, "logLevel": "info", + "metrics": { + "enable": false, + "server": { + "port": 9090 + } + }, "privileged": false, "resources": { "limits": { @@ -691,6 +697,14 @@ spec: path: agent.ebpf.features - displayName: Interfaces path: agent.ebpf.interfaces + - displayName: Metrics + path: agent.ebpf.metrics + - displayName: Enable + path: agent.ebpf.metrics.enable + - displayName: Server + path: agent.ebpf.metrics.server + - displayName: Port + path: agent.ebpf.metrics.server.port - displayName: Sampling path: agent.ebpf.sampling - displayName: Enable diff --git a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml index 6a942d9aa..86fd1be99 100644 --- a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml +++ b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml @@ -174,6 +174,115 @@ spec: - fatal - panic type: string + metrics: + description: '`metrics` defines the eBPF agent configuration + regarding metrics' + properties: + enable: + description: Set `enable` to `true` to enable eBPF agent + metrics collection. + type: boolean + server: + description: Metrics server endpoint configuration for + Prometheus scraper + properties: + port: + default: 9102 + description: The prometheus HTTP port + format: int32 + maximum: 65535 + minimum: 1 + type: integer + tls: + description: TLS configuration. + properties: + insecureSkipVerify: + default: false + description: '`insecureSkipVerify` allows skipping + client-side verification of the provided certificate. + If set to `true`, the `providedCaFile` field + is ignored.' + type: boolean + provided: + description: TLS configuration when `type` is + set to `PROVIDED`. + properties: + certFile: + description: '`certFile` defines the path + to the certificate file name within the + config map or secret' + type: string + certKey: + description: '`certKey` defines the path to + the certificate private key file name within + the config map or secret. Omit when the + key is not necessary.' + type: string + name: + description: Name of the config map or secret + containing certificates + type: string + namespace: + default: "" + description: Namespace of the config map or + secret containing certificates. If omitted, + the default is to use the same namespace + as where NetObserv is deployed. If the namespace + is different, the config map or the secret + is copied so that it can be mounted as required. + type: string + type: + description: 'Type for the certificate reference: + `configmap` or `secret`' + enum: + - configmap + - secret + type: string + type: object + providedCaFile: + description: Reference to the CA file when `type` + is set to `PROVIDED`. + properties: + file: + description: File name within the config map + or secret + type: string + name: + description: Name of the config map or secret + containing the file + type: string + namespace: + default: "" + description: Namespace of the config map or + secret containing the file. If omitted, + the default is to use the same namespace + as where NetObserv is deployed. If the namespace + is different, the config map or the secret + is copied so that it can be mounted as required. + type: string + type: + description: 'Type for the file reference: + "configmap" or "secret"' + enum: + - configmap + - secret + type: string + type: object + type: + default: DISABLED + description: Select the type of TLS configuration:
+ - `DISABLED` (default) to not configure TLS + for the endpoint. - `PROVIDED` to manually provide + cert file and a key file. - `AUTO` to use OpenShift + auto generated certificate using annotations. + enum: + - DISABLED + - PROVIDED + - AUTO + type: string + type: object + type: object + type: object privileged: description: Privileged mode for the eBPF Agent container. When ignored or set to `false`, the operator sets granular @@ -2869,6 +2978,115 @@ spec: - fatal - panic type: string + metrics: + description: '`metrics` defines the eBPF agent configuration + regarding metrics' + properties: + enable: + description: Set `enable` to `true` to enable eBPF agent + metrics collection. + type: boolean + server: + description: Metrics server endpoint configuration for + Prometheus scraper + properties: + port: + default: 9102 + description: The prometheus HTTP port + format: int32 + maximum: 65535 + minimum: 1 + type: integer + tls: + description: TLS configuration. + properties: + insecureSkipVerify: + default: false + description: '`insecureSkipVerify` allows skipping + client-side verification of the provided certificate. + If set to `true`, the `providedCaFile` field + is ignored.' + type: boolean + provided: + description: TLS configuration when `type` is + set to `Provided`. + properties: + certFile: + description: '`certFile` defines the path + to the certificate file name within the + config map or secret' + type: string + certKey: + description: '`certKey` defines the path to + the certificate private key file name within + the config map or secret. Omit when the + key is not necessary.' + type: string + name: + description: Name of the config map or secret + containing certificates + type: string + namespace: + default: "" + description: Namespace of the config map or + secret containing certificates. If omitted, + the default is to use the same namespace + as where NetObserv is deployed. If the namespace + is different, the config map or the secret + is copied so that it can be mounted as required. + type: string + type: + description: 'Type for the certificate reference: + `configmap` or `secret`' + enum: + - configmap + - secret + type: string + type: object + providedCaFile: + description: Reference to the CA file when `type` + is set to `Provided`. + properties: + file: + description: File name within the config map + or secret + type: string + name: + description: Name of the config map or secret + containing the file + type: string + namespace: + default: "" + description: Namespace of the config map or + secret containing the file. If omitted, + the default is to use the same namespace + as where NetObserv is deployed. If the namespace + is different, the config map or the secret + is copied so that it can be mounted as required. + type: string + type: + description: 'Type for the file reference: + "configmap" or "secret"' + enum: + - configmap + - secret + type: string + type: object + type: + default: Disabled + description: Select the type of TLS configuration:
+ - `Disabled` (default) to not configure TLS + for the endpoint. - `Provided` to manually provide + cert file and a key file. - `Auto` to use OpenShift + auto generated certificate using annotations. + enum: + - Disabled + - Provided + - Auto + type: string + type: object + type: object + type: object privileged: description: Privileged mode for the eBPF Agent container. When ignored or set to `false`, the operator sets granular diff --git a/config/samples/flows_v1beta2_flowcollector.yaml b/config/samples/flows_v1beta2_flowcollector.yaml index 5956fed97..5b1a4b396 100644 --- a/config/samples/flows_v1beta2_flowcollector.yaml +++ b/config/samples/flows_v1beta2_flowcollector.yaml @@ -22,6 +22,10 @@ spec: interfaces: [] excludeInterfaces: ["lo"] kafkaBatchSize: 1048576 + metrics: + enable: false + server: + port: 9090 # Custom optionnal resources configuration resources: requests: diff --git a/controllers/consoleplugin/consoleplugin_objects.go b/controllers/consoleplugin/consoleplugin_objects.go index 808edccf5..86ffdcaef 100644 --- a/controllers/consoleplugin/consoleplugin_objects.go +++ b/controllers/consoleplugin/consoleplugin_objects.go @@ -278,7 +278,7 @@ func (b *builder) mainService() *corev1.Service { // Some Kubernetes versions might automatically set TargetPort to Port. We need to // explicitly set it here so the reconcile loop verifies that the owned service // is equal as the desired service - TargetPort: intstr.FromInt(int(*b.advanced.Port)), + TargetPort: intstr.FromInt32(*b.advanced.Port), }}, }, } @@ -300,7 +300,7 @@ func (b *builder) metricsService() *corev1.Service { // Some Kubernetes versions might automatically set TargetPort to Port. We need to // explicitly set it here so the reconcile loop verifies that the owned service // is equal as the desired service - TargetPort: intstr.FromInt(metricsPort), + TargetPort: intstr.FromInt32(metricsPort), }}, }, } diff --git a/controllers/constants/constants.go b/controllers/constants/constants.go index 90a87b404..352c8a52f 100644 --- a/controllers/constants/constants.go +++ b/controllers/constants/constants.go @@ -14,10 +14,12 @@ const ( PluginName = "netobserv-plugin" // EBPFAgentName and other constants for it - EBPFAgentName = "netobserv-ebpf-agent" - EBPFPrivilegedNSSuffix = "-privileged" - EBPFServiceAccount = EBPFAgentName - EBPFSecurityContext = EBPFAgentName + EBPFAgentName = "netobserv-ebpf-agent" + EBPFAgentMetricsSvcName = "ebpf-agent-svc-prom" + EBPFAgentMetricsSvcMonitoringName = "ebpf-agent-svc-monitor" + EBPFPrivilegedNSSuffix = "-privileged" + EBPFServiceAccount = EBPFAgentName + EBPFSecurityContext = EBPFAgentName OpenShiftCertificateAnnotation = "service.beta.openshift.io/serving-cert-secret-name" diff --git a/controllers/ebpf/agent-metrics-test.go b/controllers/ebpf/agent-metrics-test.go new file mode 100644 index 000000000..e09aed185 --- /dev/null +++ b/controllers/ebpf/agent-metrics-test.go @@ -0,0 +1,47 @@ +package ebpf + +import ( + "testing" + + flowslatest "github.com/netobserv/network-observability-operator/apis/flowcollector/v1beta2" + "github.com/netobserv/network-observability-operator/controllers/constants" + + "github.com/stretchr/testify/assert" // Import the testify library for assertions +) + +func TestPromService(t *testing.T) { + // Create a new instance of your controller + controller := &AgentController{} + + // Create a sample FlowCollectorEBPF object for testing + target := &flowslatest.FlowCollectorEBPF{ + Metrics: flowslatest.EBPFMetrics{ + Server: flowslatest.MetricsServerConfig{ + Port: 8080, // Sample port for testing + }, + }, + } + + // Call the promService function + service := controller.promService(target) + + // Assert that the returned service is not nil + assert.NotNil(t, service) + // Assert that the service name is as expected + assert.Equal(t, constants.EBPFAgentMetricsSvcName, service.ObjectMeta.Name) + // Add more assertions as needed for other properties of the service +} + +func TestPromServiceMonitoring(t *testing.T) { + // Create a new instance of your controller + controller := &AgentController{} + + // Call the promServiceMonitoring function + monitor := controller.promServiceMonitoring() + + // Assert that the returned monitor is not nil + assert.NotNil(t, monitor) + // Assert that the monitor name is as expected + assert.Equal(t, constants.EBPFAgentMetricsSvcMonitoringName, monitor.ObjectMeta.Name) + // Add more assertions as needed for other properties of the monitor +} diff --git a/controllers/ebpf/agent-metrics.go b/controllers/ebpf/agent-metrics.go new file mode 100644 index 000000000..2c9504044 --- /dev/null +++ b/controllers/ebpf/agent-metrics.go @@ -0,0 +1,97 @@ +package ebpf + +import ( + "context" + + flowslatest "github.com/netobserv/network-observability-operator/apis/flowcollector/v1beta2" + "github.com/netobserv/network-observability-operator/controllers/constants" + "github.com/netobserv/network-observability-operator/controllers/reconcilers" + "github.com/netobserv/network-observability-operator/pkg/helper" + + monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +func (c *AgentController) reconcileMetricsService(ctx context.Context, target *flowslatest.FlowCollectorEBPF) error { + report := helper.NewChangeReport("EBPF Agent prometheus service") + defer report.LogIfNeeded(ctx) + + if !helper.IsEBPFMetricsEnabled(target) { + c.Managed.TryDelete(ctx, c.promSvc) + if c.AvailableAPIs.HasSvcMonitor() { + c.Managed.TryDelete(ctx, c.serviceMonitor) + } + return nil + } + + if err := c.ReconcileService(ctx, c.promSvc, c.promService(target), &report); err != nil { + return err + } + if c.AvailableAPIs.HasSvcMonitor() { + serviceMonitor := c.promServiceMonitoring() + if err := reconcilers.GenericReconcile(ctx, c.Managed, &c.Client, c.serviceMonitor, + serviceMonitor, &report, helper.ServiceMonitorChanged); err != nil { + return err + } + } + return nil +} + +func (c *AgentController) promService(target *flowslatest.FlowCollectorEBPF) *corev1.Service { + svc := corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.EBPFAgentMetricsSvcName, + Namespace: c.PrivilegedNamespace(), + Labels: map[string]string{ + "app": constants.EBPFAgentName, + }, + }, + Spec: corev1.ServiceSpec{ + Selector: map[string]string{ + "app": constants.EBPFAgentName, + }, + Ports: []corev1.ServicePort{{ + Name: "metrics", + Port: target.Metrics.Server.Port, + Protocol: corev1.ProtocolTCP, + TargetPort: intstr.FromInt32(target.Metrics.Server.Port), + }}, + }, + } + return &svc +} + +func (c *AgentController) promServiceMonitoring() *monitoringv1.ServiceMonitor { + agentServiceMonitorObject := monitoringv1.ServiceMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: constants.EBPFAgentMetricsSvcMonitoringName, + Namespace: c.PrivilegedNamespace(), + Labels: map[string]string{ + "app": constants.EBPFAgentName, + }, + }, + Spec: monitoringv1.ServiceMonitorSpec{ + Endpoints: []monitoringv1.Endpoint{ + { + Port: "metrics", + Interval: "30s", + Scheme: "http", + }, + }, + NamespaceSelector: monitoringv1.NamespaceSelector{ + MatchNames: []string{ + c.PrivilegedNamespace(), + }, + }, + Selector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": constants.EBPFAgentName, + }, + }, + }, + } + + return &agentServiceMonitorObject +} diff --git a/controllers/ebpf/agent_controller.go b/controllers/ebpf/agent_controller.go index 500cf22ab..6de3b1c60 100644 --- a/controllers/ebpf/agent_controller.go +++ b/controllers/ebpf/agent_controller.go @@ -15,6 +15,7 @@ import ( "github.com/netobserv/network-observability-operator/pkg/watchers" "github.com/go-logr/logr" + monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" @@ -55,6 +56,9 @@ const ( envEnablePktDrop = "ENABLE_PKT_DROPS" envEnableDNSTracking = "ENABLE_DNS_TRACKING" envEnableFlowRTT = "ENABLE_RTT" + envEnableMetrics = "METRICS_ENABLE" + envMetricsPort = "METRICS_SERVER_PORT" + envMetricPrefix = "METRICS_PREFIX" envListSeparator = "," ) @@ -89,15 +93,23 @@ const ( // accounts, SecurityContextConstraints... type AgentController struct { *reconcilers.Instance - permissions permissions.Reconciler - volumes volumes.Builder + permissions permissions.Reconciler + volumes volumes.Builder + promSvc *corev1.Service + serviceMonitor *monitoringv1.ServiceMonitor } func NewAgentController(common *reconcilers.Instance) *AgentController { - return &AgentController{ + common.Managed.Namespace = common.PrivilegedNamespace() + agent := AgentController{ Instance: common, permissions: permissions.NewReconciler(common), + promSvc: common.Managed.NewService(constants.EBPFAgentMetricsSvcName), } + if common.AvailableAPIs.HasSvcMonitor() { + agent.serviceMonitor = common.Managed.NewServiceMonitor(constants.EBPFAgentMetricsSvcMonitoringName) + } + return &agent } func (c *AgentController) Reconcile(ctx context.Context, target *flowslatest.FlowCollector) error { @@ -107,16 +119,23 @@ func (c *AgentController) Reconcile(ctx context.Context, target *flowslatest.Flo if err != nil { return fmt.Errorf("fetching current eBPF agent: %w", err) } + + // Retrieve other owned objects + err = c.Managed.FetchAll(ctx) + if err != nil { + return err + } + if !helper.UseEBPF(&target.Spec) || c.PreviousPrivilegedNamespace() != c.PrivilegedNamespace() { + c.Managed.TryDeleteAll(ctx) + if current == nil { - rlog.Info("nothing to do, as the requested agent is not eBPF", - "currentAgent", target.Spec.Agent) + rlog.Info("nothing to do, as the requested agent is not eBPF", "currentAgent", target.Spec.Agent) return nil } // If the user has changed the agent type or changed the target namespace, we need to manually // undeploy the agent - rlog.Info("user changed the agent type, or the target namespace. Deleting eBPF agent", - "currentAgent", target.Spec.Agent) + rlog.Info("user changed the agent type, or the target namespace. Deleting eBPF agent", "currentAgent", target.Spec.Agent) if err := c.Delete(ctx, current); err != nil { if errors.IsNotFound(err) { return nil @@ -135,6 +154,11 @@ func (c *AgentController) Reconcile(ctx context.Context, target *flowslatest.Flo return err } + err = c.reconcileMetricsService(ctx, &target.Spec.Agent.EBPF) + if err != nil { + return fmt.Errorf("reconciling prometheus service: %w", err) + } + switch requiredAction(current, desired) { case actionCreate: rlog.Info("action: create agent") @@ -159,8 +183,7 @@ func (c *AgentController) current(ctx context.Context) (*v1.DaemonSet, error) { if errors.IsNotFound(err) { return nil, nil } - return nil, fmt.Errorf("can't read DaemonSet %s/%s: %w", - c.PreviousPrivilegedNamespace(), constants.EBPFAgentName, err) + return nil, fmt.Errorf("can't read DaemonSet %s/%s: %w", c.PreviousPrivilegedNamespace(), constants.EBPFAgentName, err) } return &agentDS, nil } @@ -465,6 +488,21 @@ func (c *AgentController) setEnvConfig(coll *flowslatest.FlowCollector) []corev1 }) } + if helper.IsEBPFMetricsEnabled(&coll.Spec.Agent.EBPF) { + config = append(config, corev1.EnvVar{ + Name: envEnableMetrics, + Value: "true", + }) + config = append(config, corev1.EnvVar{ + Name: envMetricsPort, + Value: strconv.Itoa(int(coll.Spec.Agent.EBPF.Metrics.Server.Port)), + }) + config = append(config, corev1.EnvVar{ + Name: envMetricPrefix, + Value: "netobserv_agent_", + }) + } + dedup := dedupeDefault dedupJustMark := DedupeJustMarkDefault dedupMerge := DedupeMergeDefault diff --git a/controllers/flowcollector_controller_ebpf_test.go b/controllers/flowcollector_controller_ebpf_test.go index 6b0fdab0b..3aaaf5ec3 100644 --- a/controllers/flowcollector_controller_ebpf_test.go +++ b/controllers/flowcollector_controller_ebpf_test.go @@ -45,6 +45,10 @@ func flowCollectorEBPFSpecs() { Name: constants.EBPFServiceAccount, Namespace: agentKey2.Namespace, } + promSvcKey := types.NamespacedName{ + Name: constants.EBPFAgentMetricsSvcName, + Namespace: operatorNamespace + "-privileged", + } nsKey := types.NamespacedName{Name: agentKey.Namespace} nsKey2 := types.NamespacedName{Name: agentKey2.Namespace} @@ -74,6 +78,9 @@ func flowCollectorEBPFSpecs() { Advanced: &flowslatest.AdvancedAgentConfig{ Env: map[string]string{"GOGC": "400", "BUFFERS_LENGTH": "100"}, }, + Metrics: flowslatest.EBPFMetrics{ + Enable: ptr.To(true), + }, }, }, }, @@ -142,6 +149,11 @@ func flowCollectorEBPFSpecs() { By("expecting to create the netobserv-ebpf-agent service account") Expect(k8sClient.Get(ctx, saKey, &v1.ServiceAccount{})).To(Succeed()) + + By("Expecting to create the netobserv-ebpf-agent prometheus service") + Eventually(func() interface{} { + return k8sClient.Get(ctx, promSvcKey, &v1.Service{}) + }).WithTimeout(timeout).WithPolling(interval).Should(Succeed()) }) It("Should update fields that have changed", func() { @@ -149,6 +161,7 @@ func flowCollectorEBPFSpecs() { Expect(*fc.Spec.Agent.EBPF.Sampling).To(Equal(int32(123))) *fc.Spec.Agent.EBPF.Sampling = 4 fc.Spec.Agent.EBPF.Privileged = true + fc.Spec.Agent.EBPF.Metrics.Enable = ptr.To(false) }) ds := appsv1.DaemonSet{} @@ -171,6 +184,11 @@ func flowCollectorEBPFSpecs() { Expect(container.SecurityContext.Privileged).To(Not(BeNil())) Expect(*container.SecurityContext.Privileged).To(BeTrue()) Expect(container.SecurityContext.Capabilities).To(BeNil()) + + By("Expecting to delete the netobserv-ebpf-agent prometheus service") + Eventually(func() interface{} { + return k8sClient.Get(ctx, promSvcKey, &v1.Service{}) + }).WithTimeout(timeout).WithPolling(interval).Should(MatchError(`services "ebpf-agent-svc-prom" not found`)) }) It("Should redeploy all when changing namespace", func() { diff --git a/controllers/flowcollector_controller_iso_test.go b/controllers/flowcollector_controller_iso_test.go index c847d29a6..05b71e8f9 100644 --- a/controllers/flowcollector_controller_iso_test.go +++ b/controllers/flowcollector_controller_iso_test.go @@ -119,6 +119,16 @@ func flowCollectorIsoSpecs() { Privileged: false, KafkaBatchSize: 0, Features: nil, + Metrics: flowslatest.EBPFMetrics{ + Enable: ptr.To(false), + Server: flowslatest.MetricsServerConfig{ + Port: 12347, + TLS: flowslatest.ServerTLS{ + Type: "Disabled", + Provided: nil, + }, + }, + }, }, }, ConsolePlugin: flowslatest.FlowCollectorConsolePlugin{ diff --git a/controllers/flp/flp_common_objects.go b/controllers/flp/flp_common_objects.go index 8cc080d6d..036c06bda 100644 --- a/controllers/flp/flp_common_objects.go +++ b/controllers/flp/flp_common_objects.go @@ -353,7 +353,7 @@ func (b *builder) promService() *corev1.Service { // Some Kubernetes versions might automatically set TargetPort to Port. We need to // explicitly set it here so the reconcile loop verifies that the owned service // is equal as the desired service - TargetPort: intstr.FromInt(int(b.desired.Processor.Metrics.Server.Port)), + TargetPort: intstr.FromInt32(b.desired.Processor.Metrics.Server.Port), }}, }, } diff --git a/docs/FlowCollector.md b/docs/FlowCollector.md index 74667b520..d05289d95 100644 --- a/docs/FlowCollector.md +++ b/docs/FlowCollector.md @@ -288,6 +288,13 @@ Agent configuration for flows extraction. Default: info
false + + metrics + object + + `metrics` defines the eBPF agent configuration regarding metrics
+ + false privileged boolean @@ -346,6 +353,243 @@ Agent configuration for flows extraction. +### FlowCollector.spec.agent.ebpf.metrics +[↩ Parent](#flowcollectorspecagentebpf) + + + +`metrics` defines the eBPF agent configuration regarding metrics + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
enableboolean + Set `enable` to `true` to enable eBPF agent metrics collection.
+
false
serverobject + Metrics server endpoint configuration for Prometheus scraper
+
false
+ + +### FlowCollector.spec.agent.ebpf.metrics.server +[↩ Parent](#flowcollectorspecagentebpfmetrics) + + + +Metrics server endpoint configuration for Prometheus scraper + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
portinteger + The prometheus HTTP port
+
+ Format: int32
+ Default: 9102
+ Minimum: 1
+ Maximum: 65535
+
false
tlsobject + TLS configuration.
+
false
+ + +### FlowCollector.spec.agent.ebpf.metrics.server.tls +[↩ Parent](#flowcollectorspecagentebpfmetricsserver) + + + +TLS configuration. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
insecureSkipVerifyboolean + `insecureSkipVerify` allows skipping client-side verification of the provided certificate. If set to `true`, the `providedCaFile` field is ignored.
+
+ Default: false
+
false
providedobject + TLS configuration when `type` is set to `PROVIDED`.
+
false
providedCaFileobject + Reference to the CA file when `type` is set to `PROVIDED`.
+
false
typeenum + Select the type of TLS configuration:
- `DISABLED` (default) to not configure TLS for the endpoint. - `PROVIDED` to manually provide cert file and a key file. - `AUTO` to use OpenShift auto generated certificate using annotations.
+
+ Enum: DISABLED, PROVIDED, AUTO
+ Default: DISABLED
+
false
+ + +### FlowCollector.spec.agent.ebpf.metrics.server.tls.provided +[↩ Parent](#flowcollectorspecagentebpfmetricsservertls) + + + +TLS configuration when `type` is set to `PROVIDED`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
certFilestring + `certFile` defines the path to the certificate file name within the config map or secret
+
false
certKeystring + `certKey` defines the path to the certificate private key file name within the config map or secret. Omit when the key is not necessary.
+
false
namestring + Name of the config map or secret containing certificates
+
false
namespacestring + Namespace of the config map or secret containing certificates. If omitted, the default is to use the same namespace as where NetObserv is deployed. If the namespace is different, the config map or the secret is copied so that it can be mounted as required.
+
+ Default:
+
false
typeenum + Type for the certificate reference: `configmap` or `secret`
+
+ Enum: configmap, secret
+
false
+ + +### FlowCollector.spec.agent.ebpf.metrics.server.tls.providedCaFile +[↩ Parent](#flowcollectorspecagentebpfmetricsservertls) + + + +Reference to the CA file when `type` is set to `PROVIDED`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
filestring + File name within the config map or secret
+
false
namestring + Name of the config map or secret containing the file
+
false
namespacestring + Namespace of the config map or secret containing the file. If omitted, the default is to use the same namespace as where NetObserv is deployed. If the namespace is different, the config map or the secret is copied so that it can be mounted as required.
+
+ Default:
+
false
typeenum + Type for the file reference: "configmap" or "secret"
+
+ Enum: configmap, secret
+
false
+ + ### FlowCollector.spec.agent.ebpf.resources [↩ Parent](#flowcollectorspecagentebpf) @@ -4948,6 +5192,13 @@ Agent configuration for flows extraction. Default: info
false + + metrics + object + + `metrics` defines the eBPF agent configuration regarding metrics
+ + false privileged boolean @@ -5006,6 +5257,243 @@ Agent configuration for flows extraction. +### FlowCollector.spec.agent.ebpf.metrics +[↩ Parent](#flowcollectorspecagentebpf-1) + + + +`metrics` defines the eBPF agent configuration regarding metrics + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
enableboolean + Set `enable` to `true` to enable eBPF agent metrics collection.
+
false
serverobject + Metrics server endpoint configuration for Prometheus scraper
+
false
+ + +### FlowCollector.spec.agent.ebpf.metrics.server +[↩ Parent](#flowcollectorspecagentebpfmetrics-1) + + + +Metrics server endpoint configuration for Prometheus scraper + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
portinteger + The prometheus HTTP port
+
+ Format: int32
+ Default: 9102
+ Minimum: 1
+ Maximum: 65535
+
false
tlsobject + TLS configuration.
+
false
+ + +### FlowCollector.spec.agent.ebpf.metrics.server.tls +[↩ Parent](#flowcollectorspecagentebpfmetricsserver-1) + + + +TLS configuration. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
insecureSkipVerifyboolean + `insecureSkipVerify` allows skipping client-side verification of the provided certificate. If set to `true`, the `providedCaFile` field is ignored.
+
+ Default: false
+
false
providedobject + TLS configuration when `type` is set to `Provided`.
+
false
providedCaFileobject + Reference to the CA file when `type` is set to `Provided`.
+
false
typeenum + Select the type of TLS configuration:
- `Disabled` (default) to not configure TLS for the endpoint. - `Provided` to manually provide cert file and a key file. - `Auto` to use OpenShift auto generated certificate using annotations.
+
+ Enum: Disabled, Provided, Auto
+ Default: Disabled
+
false
+ + +### FlowCollector.spec.agent.ebpf.metrics.server.tls.provided +[↩ Parent](#flowcollectorspecagentebpfmetricsservertls-1) + + + +TLS configuration when `type` is set to `Provided`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
certFilestring + `certFile` defines the path to the certificate file name within the config map or secret
+
false
certKeystring + `certKey` defines the path to the certificate private key file name within the config map or secret. Omit when the key is not necessary.
+
false
namestring + Name of the config map or secret containing certificates
+
false
namespacestring + Namespace of the config map or secret containing certificates. If omitted, the default is to use the same namespace as where NetObserv is deployed. If the namespace is different, the config map or the secret is copied so that it can be mounted as required.
+
+ Default:
+
false
typeenum + Type for the certificate reference: `configmap` or `secret`
+
+ Enum: configmap, secret
+
false
+ + +### FlowCollector.spec.agent.ebpf.metrics.server.tls.providedCaFile +[↩ Parent](#flowcollectorspecagentebpfmetricsservertls-1) + + + +Reference to the CA file when `type` is set to `Provided`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
filestring + File name within the config map or secret
+
false
namestring + Name of the config map or secret containing the file
+
false
namespacestring + Namespace of the config map or secret containing the file. If omitted, the default is to use the same namespace as where NetObserv is deployed. If the namespace is different, the config map or the secret is copied so that it can be mounted as required.
+
+ Default:
+
false
typeenum + Type for the file reference: "configmap" or "secret"
+
+ Enum: configmap, secret
+
false
+ + ### FlowCollector.spec.agent.ebpf.resources [↩ Parent](#flowcollectorspecagentebpf-1) diff --git a/pkg/helper/flowcollector.go b/pkg/helper/flowcollector.go index fc58199dd..eec4e2efe 100644 --- a/pkg/helper/flowcollector.go +++ b/pkg/helper/flowcollector.go @@ -122,6 +122,10 @@ func IsZoneEnabled(spec *flowslatest.FlowCollectorFLP) bool { return spec.AddZone != nil && *spec.AddZone } +func IsEBPFMetricsEnabled(spec *flowslatest.FlowCollectorEBPF) bool { + return spec.Metrics.Enable != nil && *spec.Metrics.Enable +} + func PtrBool(b *bool) bool { if b == nil { return false