From 6d42941984f43cc8a10612d624f0c6332e27fe0f Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Mon, 26 Feb 2024 15:48:17 -0500 Subject: [PATCH 1/3] NETOBSERV-557: add eBPF agent metrics for troubleshooting Signed-off-by: Mohamed Mahmoud --- .../v1beta1/flowcollector_types.go | 13 + .../v1beta1/zz_generated.conversion.go | 42 ++ .../v1beta1/zz_generated.deepcopy.go | 22 + .../v1beta2/flowcollector_types.go | 13 + .../v1beta2/zz_generated.deepcopy.go | 22 + .../flows.netobserv.io_flowcollectors.yaml | 220 ++++++++ ...observ-operator.clusterserviceversion.yaml | 14 + .../flows.netobserv.io_flowcollectors.yaml | 220 ++++++++ .../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 | 90 ++++ controllers/ebpf/agent_controller.go | 42 +- .../flowcollector_controller_iso_test.go | 10 + controllers/flp/flp_common_objects.go | 2 +- docs/FlowCollector.md | 492 ++++++++++++++++++ go.sum | 3 - pkg/helper/flowcollector.go | 4 + 19 files changed, 1261 insertions(+), 13 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..0a8c92520 100644 --- a/apis/flowcollector/v1beta1/flowcollector_types.go +++ b/apis/flowcollector/v1beta1/flowcollector_types.go @@ -158,6 +158,16 @@ const ( FlowRTT AgentFeature = "FlowRTT" ) +// `EBPFMetrics` define the desired EBPF agent configuration regarding metrics +type EBPFMetrics struct { + // Metrics server endpoint configuration for Prometheus scraper + // +optional + Server MetricsServerConfig `json:"server,omitempty"` + //+kubebuilder:default:=false + // 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,9 @@ 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` define 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..655343811 100644 --- a/apis/flowcollector/v1beta2/flowcollector_types.go +++ b/apis/flowcollector/v1beta2/flowcollector_types.go @@ -165,6 +165,16 @@ const ( FlowRTT AgentFeature = "FlowRTT" ) +// `EBPFMetrics` define the desired EBPF agent configuration regarding metrics +type EBPFMetrics struct { + // Metrics server endpoint configuration for Prometheus scraper + // +optional + Server MetricsServerConfig `json:"server,omitempty"` + //+kubebuilder:default:=false + // 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,9 @@ 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` define 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..34153740d 100644 --- a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml +++ b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml @@ -187,6 +187,116 @@ spec: - fatal - panic type: string + metrics: + description: '`Metrics` define the EBPF agent configuration + regarding metrics' + properties: + enable: + default: false + 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 +2992,116 @@ spec: - fatal - panic type: string + metrics: + description: '`Metrics` define the EBPF agent configuration + regarding metrics' + properties: + enable: + default: false + 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 3f24a6d0c..d21331d1f 100644 --- a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml +++ b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml @@ -241,6 +241,12 @@ metadata: "interfaces": [], "kafkaBatchSize": 1048576, "logLevel": "info", + "metrics": { + "enable": false, + "server": { + "port": 9090 + } + }, "privileged": false, "resources": { "limits": { @@ -690,6 +696,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..7f224bec3 100644 --- a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml +++ b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml @@ -174,6 +174,116 @@ spec: - fatal - panic type: string + metrics: + description: '`Metrics` define the EBPF agent configuration + regarding metrics' + properties: + enable: + default: false + 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 +2979,116 @@ spec: - fatal - panic type: string + metrics: + description: '`Metrics` define the EBPF agent configuration + regarding metrics' + properties: + enable: + default: false + 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..d50037702 --- /dev/null +++ b/controllers/ebpf/agent-metrics.go @@ -0,0 +1,90 @@ +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" + "k8s.io/apimachinery/pkg/api/errors" + 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 err := c.ReconcileService(ctx, c.promSvc, c.promService(target), &report); err != nil && !errors.IsAlreadyExists(err) { + 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 && !errors.IsAlreadyExists(err) { + 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..bd8a828b1 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,22 @@ 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{ + 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 { @@ -135,6 +146,12 @@ func (c *AgentController) Reconcile(ctx context.Context, target *flowslatest.Flo return err } + if helper.IsEBPFMetricsEnabled(&target.Spec.Agent.EBPF) { + err = c.reconcilePrometheusService(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") @@ -465,6 +482,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 @@ -500,3 +532,7 @@ func (c *AgentController) setEnvConfig(coll *flowslatest.FlowCollector) []corev1 return config } + +func (c *AgentController) reconcilePrometheusService(ctx context.Context, target *flowslatest.FlowCollectorEBPF) error { + return c.ReconcileMetricsService(ctx, target) +} 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..d515d09f7 100644 --- a/docs/FlowCollector.md +++ b/docs/FlowCollector.md @@ -288,6 +288,13 @@ Agent configuration for flows extraction. Default: info
false + + metrics + object + + `Metrics` define the EBPF agent configuration regarding metrics
+ + false privileged boolean @@ -346,6 +353,245 @@ Agent configuration for flows extraction. +### FlowCollector.spec.agent.ebpf.metrics +[↩ Parent](#flowcollectorspecagentebpf) + + + +`Metrics` define the EBPF agent configuration regarding metrics + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
enableboolean + Set `enable` to `true` to enable EBPF agent metrics collection.
+
+ Default: false
+
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 +5194,13 @@ Agent configuration for flows extraction. Default: info
false + + metrics + object + + `Metrics` define the EBPF agent configuration regarding metrics
+ + false privileged boolean @@ -5006,6 +5259,245 @@ Agent configuration for flows extraction. +### FlowCollector.spec.agent.ebpf.metrics +[↩ Parent](#flowcollectorspecagentebpf-1) + + + +`Metrics` define the EBPF agent configuration regarding metrics + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
enableboolean + Set `enable` to `true` to enable EBPF agent metrics collection.
+
+ Default: false
+
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/go.sum b/go.sum index 0f601e06e..4b6ea290d 100644 --- a/go.sum +++ b/go.sum @@ -125,7 +125,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -186,7 +185,6 @@ github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -213,7 +211,6 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= 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 From 86783ed021be0c11a6e821774241772df5aad867 Mon Sep 17 00:00:00 2001 From: Joel Takvorian Date: Wed, 28 Feb 2024 17:17:37 +0100 Subject: [PATCH 2/3] Fix managed objects use with agent controller --- controllers/ebpf/agent-metrics.go | 15 ++++++--- controllers/ebpf/agent_controller.go | 32 ++++++++++--------- .../flowcollector_controller_ebpf_test.go | 18 +++++++++++ 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/controllers/ebpf/agent-metrics.go b/controllers/ebpf/agent-metrics.go index d50037702..2c9504044 100644 --- a/controllers/ebpf/agent-metrics.go +++ b/controllers/ebpf/agent-metrics.go @@ -10,22 +10,29 @@ import ( monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" 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 { +func (c *AgentController) reconcileMetricsService(ctx context.Context, target *flowslatest.FlowCollectorEBPF) error { report := helper.NewChangeReport("EBPF Agent prometheus service") defer report.LogIfNeeded(ctx) - if err := c.ReconcileService(ctx, c.promSvc, c.promService(target), &report); err != nil && !errors.IsAlreadyExists(err) { + 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 && !errors.IsAlreadyExists(err) { + serviceMonitor, &report, helper.ServiceMonitorChanged); err != nil { return err } } diff --git a/controllers/ebpf/agent_controller.go b/controllers/ebpf/agent_controller.go index bd8a828b1..6de3b1c60 100644 --- a/controllers/ebpf/agent_controller.go +++ b/controllers/ebpf/agent_controller.go @@ -100,6 +100,7 @@ type AgentController struct { } func NewAgentController(common *reconcilers.Instance) *AgentController { + common.Managed.Namespace = common.PrivilegedNamespace() agent := AgentController{ Instance: common, permissions: permissions.NewReconciler(common), @@ -118,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 @@ -146,12 +154,11 @@ func (c *AgentController) Reconcile(ctx context.Context, target *flowslatest.Flo return err } - if helper.IsEBPFMetricsEnabled(&target.Spec.Agent.EBPF) { - err = c.reconcilePrometheusService(ctx, &target.Spec.Agent.EBPF) - if err != nil { - return fmt.Errorf("reconciling prometheus service: %w", 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") @@ -176,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 } @@ -532,7 +538,3 @@ func (c *AgentController) setEnvConfig(coll *flowslatest.FlowCollector) []corev1 return config } - -func (c *AgentController) reconcilePrometheusService(ctx context.Context, target *flowslatest.FlowCollectorEBPF) error { - return c.ReconcileMetricsService(ctx, target) -} 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() { From e0db29159739de59f557588ce3bf15e362aa6a79 Mon Sep 17 00:00:00 2001 From: Joel Takvorian Date: Wed, 28 Feb 2024 17:29:58 +0100 Subject: [PATCH 3/3] some doc fixes --- .../flowcollector/v1beta1/flowcollector_types.go | 9 +++++---- .../flowcollector/v1beta2/flowcollector_types.go | 9 +++++---- .../flows.netobserv.io_flowcollectors.yaml | 10 ++++------ .../bases/flows.netobserv.io_flowcollectors.yaml | 10 ++++------ docs/FlowCollector.md | 16 ++++++---------- 5 files changed, 24 insertions(+), 30 deletions(-) diff --git a/apis/flowcollector/v1beta1/flowcollector_types.go b/apis/flowcollector/v1beta1/flowcollector_types.go index 0a8c92520..d442f6fa8 100644 --- a/apis/flowcollector/v1beta1/flowcollector_types.go +++ b/apis/flowcollector/v1beta1/flowcollector_types.go @@ -158,13 +158,13 @@ const ( FlowRTT AgentFeature = "FlowRTT" ) -// `EBPFMetrics` define the desired EBPF agent configuration regarding metrics +// `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"` - //+kubebuilder:default:=false - // Set `enable` to `true` to enable EBPF agent metrics collection. + + // Set `enable` to `true` to enable eBPF agent metrics collection. Enable *bool `json:"enable,omitempty"` } @@ -249,7 +249,8 @@ 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` define the EBPF agent configuration regarding metrics + + // `metrics` defines the eBPF agent configuration regarding metrics // +optional Metrics EBPFMetrics `json:"metrics,omitempty"` } diff --git a/apis/flowcollector/v1beta2/flowcollector_types.go b/apis/flowcollector/v1beta2/flowcollector_types.go index 655343811..b94163fca 100644 --- a/apis/flowcollector/v1beta2/flowcollector_types.go +++ b/apis/flowcollector/v1beta2/flowcollector_types.go @@ -165,13 +165,13 @@ const ( FlowRTT AgentFeature = "FlowRTT" ) -// `EBPFMetrics` define the desired EBPF agent configuration regarding metrics +// `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"` - //+kubebuilder:default:=false - // Set `enable` to `true` to enable EBPF agent metrics collection. + + // Set `enable` to `true` to enable eBPF agent metrics collection. Enable *bool `json:"enable,omitempty"` } @@ -256,7 +256,8 @@ 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` define the EBPF agent configuration regarding metrics + + // `metrics` defines the eBPF agent configuration regarding metrics // +optional Metrics EBPFMetrics `json:"metrics,omitempty"` } diff --git a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml index 34153740d..ba829a68b 100644 --- a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml +++ b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml @@ -188,12 +188,11 @@ spec: - panic type: string metrics: - description: '`Metrics` define the EBPF agent configuration + description: '`metrics` defines the eBPF agent configuration regarding metrics' properties: enable: - default: false - description: Set `enable` to `true` to enable EBPF agent + description: Set `enable` to `true` to enable eBPF agent metrics collection. type: boolean server: @@ -2993,12 +2992,11 @@ spec: - panic type: string metrics: - description: '`Metrics` define the EBPF agent configuration + description: '`metrics` defines the eBPF agent configuration regarding metrics' properties: enable: - default: false - description: Set `enable` to `true` to enable EBPF agent + description: Set `enable` to `true` to enable eBPF agent metrics collection. type: boolean server: diff --git a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml index 7f224bec3..86fd1be99 100644 --- a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml +++ b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml @@ -175,12 +175,11 @@ spec: - panic type: string metrics: - description: '`Metrics` define the EBPF agent configuration + description: '`metrics` defines the eBPF agent configuration regarding metrics' properties: enable: - default: false - description: Set `enable` to `true` to enable EBPF agent + description: Set `enable` to `true` to enable eBPF agent metrics collection. type: boolean server: @@ -2980,12 +2979,11 @@ spec: - panic type: string metrics: - description: '`Metrics` define the EBPF agent configuration + description: '`metrics` defines the eBPF agent configuration regarding metrics' properties: enable: - default: false - description: Set `enable` to `true` to enable EBPF agent + description: Set `enable` to `true` to enable eBPF agent metrics collection. type: boolean server: diff --git a/docs/FlowCollector.md b/docs/FlowCollector.md index d515d09f7..d05289d95 100644 --- a/docs/FlowCollector.md +++ b/docs/FlowCollector.md @@ -292,7 +292,7 @@ Agent configuration for flows extraction. metrics object - `Metrics` define the EBPF agent configuration regarding metrics
+ `metrics` defines the eBPF agent configuration regarding metrics
false @@ -358,7 +358,7 @@ Agent configuration for flows extraction. -`Metrics` define the EBPF agent configuration regarding metrics +`metrics` defines the eBPF agent configuration regarding metrics @@ -373,9 +373,7 @@ Agent configuration for flows extraction. @@ -5198,7 +5196,7 @@ Agent configuration for flows extraction. @@ -5264,7 +5262,7 @@ Agent configuration for flows extraction. -`Metrics` define the EBPF agent configuration regarding metrics +`metrics` defines the eBPF agent configuration regarding metrics
enable boolean - Set `enable` to `true` to enable EBPF agent metrics collection.
-
- Default: false
+ Set `enable` to `true` to enable eBPF agent metrics collection.
false
metrics object - `Metrics` define the EBPF agent configuration regarding metrics
+ `metrics` defines the eBPF agent configuration regarding metrics
false
@@ -5279,9 +5277,7 @@ Agent configuration for flows extraction.
enable boolean - Set `enable` to `true` to enable EBPF agent metrics collection.
-
- Default: false
+ Set `enable` to `true` to enable eBPF agent metrics collection.
false