diff --git a/Makefile b/Makefile index ac4abd188..e85f9a211 100644 --- a/Makefile +++ b/Makefile @@ -255,7 +255,13 @@ endif ##@ Code / files generation manifests: YQ controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + $(CONTROLLER_GEN) \ + rbac:roleName=manager-role \ + crd:crdVersions=v1 \ + paths="./apis/..." \ + output:crd:artifacts:config=config/crd/bases \ + output:webhook:dir=./config/webhook \ + webhook $(YQ) -i 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.processor.properties.kafkaConsumerAutoscaler.properties.metrics.items | .. | select(has("description")) | .description)' config/crd/bases/flows.netobserv.io_flowcollectors.yaml $(YQ) -i 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.consolePlugin.properties.autoscaler.properties.metrics.items | .. | select(has("description")) | .description)' config/crd/bases/flows.netobserv.io_flowcollectors.yaml $(YQ) -i 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.agent.properties.ebpf.properties.advanced.properties.affinity.properties | .. | select(has("description")) | .description)' config/crd/bases/flows.netobserv.io_flowcollectors.yaml diff --git a/PROJECT b/PROJECT index 3de0f51e9..54f37f051 100644 --- a/PROJECT +++ b/PROJECT @@ -1,3 +1,7 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html domain: netobserv.io layout: - go.kubebuilder.io/v3 @@ -30,4 +34,7 @@ resources: kind: FlowMetric path: github.com/netobserv/network-observability-operator/apis/flowmetrics/v1alpha1 version: v1alpha1 + webhooks: + validation: true + webhookVersion: v1 version: "3" diff --git a/apis/flowmetrics/v1alpha1/flowmetric_types.go b/apis/flowmetrics/v1alpha1/flowmetric_types.go index 9206e89ad..321967cce 100644 --- a/apis/flowmetrics/v1alpha1/flowmetric_types.go +++ b/apis/flowmetrics/v1alpha1/flowmetric_types.go @@ -74,13 +74,13 @@ type FlowMetricSpec struct { // `valueField` is the flow field that must be used as a value for this metric. This field must hold numeric values. // Leave empty to count flows rather than a specific value per flow. - // Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/networking/network_observability/json-flows-format-reference.html. + // Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. // +optional ValueField string `json:"valueField,omitempty"` // `filters` is a list of fields and values used to restrict which flows are taken into account. Oftentimes, these filters must // be used to eliminate duplicates: `Duplicate != "true"` and `FlowDirection = "0"`. - // Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/networking/network_observability/json-flows-format-reference.html. + // Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. // +optional Filters []MetricFilter `json:"filters"` @@ -89,7 +89,7 @@ type FlowMetricSpec struct { // It must be done carefully as it impacts the metric cardinality (cf https://rhobs-handbook.netlify.app/products/openshiftmonitoring/telemetry.md/#what-is-the-cardinality-of-a-metric). // In general, avoid setting very high cardinality labels such as IP or MAC addresses. // "SrcK8S_OwnerName" or "DstK8S_OwnerName" should be preferred over "SrcK8S_Name" or "DstK8S_Name" as much as possible. - // Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/network_observability/json-flows-format-reference.html. + // Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. // +optional Labels []string `json:"labels"` diff --git a/apis/flowmetrics/v1alpha1/flowmetric_webhook.go b/apis/flowmetrics/v1alpha1/flowmetric_webhook.go new file mode 100644 index 000000000..5883d41d4 --- /dev/null +++ b/apis/flowmetrics/v1alpha1/flowmetric_webhook.go @@ -0,0 +1,99 @@ +package v1alpha1 + +import ( + "context" + "fmt" + + "github.com/netobserv/network-observability-operator/pkg/helper" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" + ctrl "sigs.k8s.io/controller-runtime" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// log is for logging in this package. +var flowmetriclog = logf.Log.WithName("flowmetric-resource") + +type FlowMetricWebhook struct { + FlowMetric +} + +// +kubebuilder:webhook:verbs=create;update,path=/validate-flows-netobserv-io-v1alpha1-flowmetric,mutating=false,failurePolicy=fail,sideEffects=None,groups=flows.netobserv.io,resources=flowmetrics,versions=v1alpha1,name=flowmetricvalidationwebhook.netobserv.io,admissionReviewVersions=v1 +var ( + _ webhook.CustomValidator = &FlowMetricWebhook{FlowMetric{}} +) + +func (r *FlowMetricWebhook) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(&FlowMetric{}). + WithValidator(&FlowMetricWebhook{}). + Complete() +} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (r *FlowMetricWebhook) ValidateCreate(ctx context.Context, newObj runtime.Object) (warnings admission.Warnings, err error) { + flowmetriclog.Info("validate create", "name", r.Name) + newFlowMetric, ok := newObj.(*FlowMetric) + if !ok { + return nil, apierrors.NewBadRequest(fmt.Sprintf("expected an FlowMetric but got a %T", newObj)) + } + return nil, validateFlowMetric(ctx, newFlowMetric) +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (r *FlowMetricWebhook) ValidateUpdate(ctx context.Context, _, newObj runtime.Object) (warnings admission.Warnings, err error) { + flowmetriclog.Info("validate update", "name", r.Name) + newFlowMetric, ok := newObj.(*FlowMetric) + if !ok { + return nil, apierrors.NewBadRequest(fmt.Sprintf("expected an FlowMetric but got a %T", newObj)) + } + return nil, validateFlowMetric(ctx, newFlowMetric) +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (r *FlowMetricWebhook) ValidateDelete(_ context.Context, _ runtime.Object) (warnings admission.Warnings, err error) { + flowmetriclog.Info("validate delete", "name", r.Name) + return nil, nil +} + +func validateFlowMetric(_ context.Context, fMetric *FlowMetric) error { + var str []string + var allErrs field.ErrorList + + for _, f := range fMetric.Spec.Filters { + str = append(str, f.Field) + } + + if len(str) != 0 { + if !helper.FindFilter(str, false) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "filters"), str, + fmt.Sprintf("invalid filter field: %s", str))) + } + } + + if len(fMetric.Spec.Labels) != 0 { + if !helper.FindFilter(fMetric.Spec.Labels, false) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "labels"), fMetric.Spec.Labels, + fmt.Sprintf("invalid label name: %s", fMetric.Spec.Labels))) + } + } + + if fMetric.Spec.ValueField != "" { + if !helper.FindFilter([]string{fMetric.Spec.ValueField}, true) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "valueField"), fMetric.Spec.ValueField, + fmt.Sprintf("invalid value field: %s", fMetric.Spec.ValueField))) + } + } + + if len(allErrs) != 0 { + return apierrors.NewInvalid( + schema.GroupKind{Group: GroupVersion.Group, Kind: FlowMetric{}.Kind}, + fMetric.Name, allErrs) + } + return nil +} diff --git a/apis/flowmetrics/v1alpha1/flowmetric_webhook_test.go b/apis/flowmetrics/v1alpha1/flowmetric_webhook_test.go new file mode 100644 index 000000000..f82201556 --- /dev/null +++ b/apis/flowmetrics/v1alpha1/flowmetric_webhook_test.go @@ -0,0 +1,125 @@ +package v1alpha1 + +import ( + "context" + "fmt" + "strings" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestFlowMetric(t *testing.T) { + tests := []struct { + desc string + m *FlowMetric + expectedError string + }{ + { + desc: "Invalid FlowMetric Filter", + m: &FlowMetric{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Namespace: "test-namespace", + }, + Spec: FlowMetricSpec{ + Filters: []MetricFilter{ + { + Field: "test", + }, + }, + }, + }, + expectedError: "invalid filter field", + }, + { + desc: "Valid FlowMetric Filter", + m: &FlowMetric{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Namespace: "test-namespace", + }, + Spec: FlowMetricSpec{ + Filters: []MetricFilter{ + { + Field: "DstK8S_Zone", + }, + }, + }, + }, + expectedError: "", + }, + { + desc: "Invalid FlowMetric Label", + m: &FlowMetric{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Namespace: "test-namespace", + }, + Spec: FlowMetricSpec{ + Labels: []string{ + "test", + }, + }, + }, + expectedError: "invalid label name", + }, + { + desc: "Valid FlowMetric Label", + m: &FlowMetric{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Namespace: "test-namespace", + }, + Spec: FlowMetricSpec{ + Labels: []string{ + "DstK8S_Zone", + }, + }, + }, + expectedError: "", + }, + { + desc: "Valid valueField", + m: &FlowMetric{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Namespace: "test-namespace", + }, + Spec: FlowMetricSpec{ + ValueField: "Bytes", + }, + }, + expectedError: "", + }, + { + desc: "Invalid valueField", + m: &FlowMetric{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Namespace: "test-namespace", + }, + Spec: FlowMetricSpec{ + ValueField: "DstAddr", + }, + }, + expectedError: "invalid value field", + }, + } + + for _, test := range tests { + err := validateFlowMetric(context.TODO(), test.m) + if err == nil { + if test.expectedError != "" { + t.Errorf("%s: ValidateFlowMetric failed, no error found while expected: \"%s\"", test.desc, test.expectedError) + } + } else { + if len(test.expectedError) == 0 { + t.Errorf("%s: ValidateFlowMetric failed, unexpected error: \"%s\"", test.desc, err) + } + if !strings.Contains(fmt.Sprint(err), test.expectedError) { + t.Errorf("%s: ValidateFlowMetric failed, expected error: \"%s\" to contain: \"%s\"", test.desc, err, test.expectedError) + } + } + } +} diff --git a/apis/flowmetrics/v1alpha1/zz_generated.deepcopy.go b/apis/flowmetrics/v1alpha1/zz_generated.deepcopy.go index 34b5e6c21..f84b2c412 100644 --- a/apis/flowmetrics/v1alpha1/zz_generated.deepcopy.go +++ b/apis/flowmetrics/v1alpha1/zz_generated.deepcopy.go @@ -21,7 +21,7 @@ limitations under the License. package v1alpha1 import ( - runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -128,6 +128,22 @@ func (in *FlowMetricStatus) DeepCopy() *FlowMetricStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlowMetricWebhook) DeepCopyInto(out *FlowMetricWebhook) { + *out = *in + in.FlowMetric.DeepCopyInto(&out.FlowMetric) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowMetricWebhook. +func (in *FlowMetricWebhook) DeepCopy() *FlowMetricWebhook { + if in == nil { + return nil + } + out := new(FlowMetricWebhook) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MetricFilter) DeepCopyInto(out *MetricFilter) { *out = *in diff --git a/bundle/manifests/flows.netobserv.io_flowmetrics.yaml b/bundle/manifests/flows.netobserv.io_flowmetrics.yaml index a36936c50..ce86a887e 100644 --- a/bundle/manifests/flows.netobserv.io_flowmetrics.yaml +++ b/bundle/manifests/flows.netobserv.io_flowmetrics.yaml @@ -6,6 +6,16 @@ metadata: creationTimestamp: null name: flowmetrics.flows.netobserv.io spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: netobserv-webhook-service + namespace: netobserv + path: /convert + conversionReviewVersions: + - v1 group: flows.netobserv.io names: kind: FlowMetric @@ -66,7 +76,7 @@ spec: description: |- `filters` is a list of fields and values used to restrict which flows are taken into account. Oftentimes, these filters must be used to eliminate duplicates: `Duplicate != "true"` and `FlowDirection = "0"`. - Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/networking/network_observability/json-flows-format-reference.html. + Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. items: properties: field: @@ -103,7 +113,7 @@ spec: It must be done carefully as it impacts the metric cardinality (cf https://rhobs-handbook.netlify.app/products/openshiftmonitoring/telemetry.md/#what-is-the-cardinality-of-a-metric). In general, avoid setting very high cardinality labels such as IP or MAC addresses. "SrcK8S_OwnerName" or "DstK8S_OwnerName" should be preferred over "SrcK8S_Name" or "DstK8S_Name" as much as possible. - Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/network_observability/json-flows-format-reference.html. + Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. items: type: string type: array @@ -124,7 +134,7 @@ spec: description: |- `valueField` is the flow field that must be used as a value for this metric. This field must hold numeric values. Leave empty to count flows rather than a specific value per flow. - Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/networking/network_observability/json-flows-format-reference.html. + Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. type: string required: - metricName diff --git a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml index 2d1f19823..2b9b0b2b0 100644 --- a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml +++ b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml @@ -1300,8 +1300,9 @@ spec: containerPort: 443 conversionCRDs: - flowcollectors.flows.netobserv.io + - flowmetrics.flows.netobserv.io deploymentName: netobserv-controller-manager - generateName: cflowcollectors.kb.io + generateName: cflowcollectorsflowmetrics.kb.io sideEffects: None targetPort: 9443 type: ConversionWebhook @@ -1326,3 +1327,23 @@ spec: targetPort: 9443 type: ValidatingAdmissionWebhook webhookPath: /validate-netobserv-io-v1beta2-flowcollector + - admissionReviewVersions: + - v1 + containerPort: 443 + deploymentName: netobserv-controller-manager + failurePolicy: Fail + generateName: flowmetricvalidationwebhook.netobserv.io + rules: + - apiGroups: + - flows.netobserv.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - flowmetrics + sideEffects: None + targetPort: 9443 + type: ValidatingAdmissionWebhook + webhookPath: /validate-flows-netobserv-io-v1alpha1-flowmetric diff --git a/config/crd/bases/flows.netobserv.io_flowmetrics.yaml b/config/crd/bases/flows.netobserv.io_flowmetrics.yaml index a869ae7ba..9d6cc03df 100644 --- a/config/crd/bases/flows.netobserv.io_flowmetrics.yaml +++ b/config/crd/bases/flows.netobserv.io_flowmetrics.yaml @@ -66,7 +66,7 @@ spec: description: |- `filters` is a list of fields and values used to restrict which flows are taken into account. Oftentimes, these filters must be used to eliminate duplicates: `Duplicate != "true"` and `FlowDirection = "0"`. - Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/networking/network_observability/json-flows-format-reference.html. + Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. items: properties: field: @@ -103,7 +103,7 @@ spec: It must be done carefully as it impacts the metric cardinality (cf https://rhobs-handbook.netlify.app/products/openshiftmonitoring/telemetry.md/#what-is-the-cardinality-of-a-metric). In general, avoid setting very high cardinality labels such as IP or MAC addresses. "SrcK8S_OwnerName" or "DstK8S_OwnerName" should be preferred over "SrcK8S_Name" or "DstK8S_Name" as much as possible. - Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/network_observability/json-flows-format-reference.html. + Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. items: type: string type: array @@ -124,7 +124,7 @@ spec: description: |- `valueField` is the flow field that must be used as a value for this metric. This field must hold numeric values. Leave empty to count flows rather than a specific value per flow. - Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/networking/network_observability/json-flows-format-reference.html. + Refer to the documentation for the list of available fields: https://docs.openshift.com/container-platform/latest/observability/network_observability/json-flows-format-reference.html. type: string required: - metricName diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index c243e0de3..c12ea1aa3 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -10,7 +10,7 @@ patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD - patches/webhook_in_flowcollectors.yaml -#- patches/webhook_in_flowmetrics.yaml +- patches/webhook_in_flowmetrics.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. diff --git a/config/openshift/patch.yaml b/config/openshift/patch.yaml index dce8ff984..62a77a5a0 100644 --- a/config/openshift/patch.yaml +++ b/config/openshift/patch.yaml @@ -22,3 +22,10 @@ metadata: annotations: service.beta.openshift.io/inject-cabundle: "true" name: flowcollectors.flows.netobserv.io +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + service.beta.openshift.io/inject-cabundle: "true" + name: flowmetrics.flows.netobserv.io \ No newline at end of file diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index 62763b647..cb7d2fa2f 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -26,3 +26,23 @@ webhooks: resources: - flowcollectors sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-flows-netobserv-io-v1alpha1-flowmetric + failurePolicy: Fail + name: flowmetricvalidationwebhook.netobserv.io + rules: + - apiGroups: + - flows.netobserv.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - flowmetrics + sideEffects: None diff --git a/controllers/consoleplugin/config/config.go b/controllers/consoleplugin/config/config.go index d15a06d96..a45a780c2 100644 --- a/controllers/consoleplugin/config/config.go +++ b/controllers/consoleplugin/config/config.go @@ -1,6 +1,8 @@ package config import ( + _ "embed" + "github.com/netobserv/flowlogs-pipeline/pkg/api" flowslatest "github.com/netobserv/network-observability-operator/apis/flowcollector/v1beta2" ) @@ -105,3 +107,10 @@ type PluginConfig struct { Loki LokiConfig `yaml:"loki" json:"loki"` Frontend FrontendConfig `yaml:"frontend" json:"frontend"` } + +//go:embed static-frontend-config.yaml +var staticFrontendConfig []byte + +func LoadStaticFrontendConfig() []byte { + return staticFrontendConfig +} diff --git a/controllers/consoleplugin/consoleplugin_objects.go b/controllers/consoleplugin/consoleplugin_objects.go index c4651bc8f..530367d59 100644 --- a/controllers/consoleplugin/consoleplugin_objects.go +++ b/controllers/consoleplugin/consoleplugin_objects.go @@ -1,7 +1,6 @@ package consoleplugin import ( - _ "embed" "fmt" "hash/fnv" "path/filepath" @@ -18,7 +17,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" flowslatest "github.com/netobserv/network-observability-operator/apis/flowcollector/v1beta2" - config "github.com/netobserv/network-observability-operator/controllers/consoleplugin/config" + cfg "github.com/netobserv/network-observability-operator/controllers/consoleplugin/config" "github.com/netobserv/network-observability-operator/controllers/constants" "github.com/netobserv/network-observability-operator/controllers/ebpf" "github.com/netobserv/network-observability-operator/pkg/helper" @@ -310,7 +309,7 @@ func (b *builder) metricsService() *corev1.Service { } } -func (b *builder) setLokiConfig(lconf *config.LokiConfig) { +func (b *builder) setLokiConfig(lconf *cfg.LokiConfig) { lconf.URL = b.loki.QuerierURL statusURL := b.loki.StatusURL if lconf.URL != statusURL { @@ -353,7 +352,7 @@ func (b *builder) setLokiConfig(lconf *config.LokiConfig) { } } -func (b *builder) setFrontendConfig(fconf *config.FrontendConfig) error { +func (b *builder) setFrontendConfig(fconf *cfg.FrontendConfig) error { var err error dedupJustMark, err := strconv.ParseBool(ebpf.DedupeJustMarkDefault) if err != nil { @@ -395,7 +394,7 @@ func (b *builder) setFrontendConfig(fconf *config.FrontendConfig) error { fconf.QuickFilters = b.desired.ConsolePlugin.QuickFilters fconf.AlertNamespaces = []string{b.namespace} fconf.Sampling = helper.GetSampling(b.desired) - fconf.Deduper = config.Deduper{ + fconf.Deduper = cfg.Deduper{ Mark: dedupJustMark, Merge: dedupMerge, } @@ -411,13 +410,10 @@ func (b *builder) setFrontendConfig(fconf *config.FrontendConfig) error { return nil } -//go:embed config/static-frontend-config.yaml -var staticFrontendConfig []byte - // returns a configmap with a digest of its configuration contents, which will be used to // detect any configuration change func (b *builder) configMap() (*corev1.ConfigMap, string, error) { - config := config.PluginConfig{} + config := cfg.PluginConfig{} // configure server config.Server.CertPath = "/var/serving-cert/tls.crt" config.Server.KeyPath = "/var/serving-cert/tls.key" @@ -427,7 +423,7 @@ func (b *builder) configMap() (*corev1.ConfigMap, string, error) { b.setLokiConfig(&config.Loki) // configure frontend from embedded static file - err := yaml.Unmarshal(staticFrontendConfig, &config.Frontend) + err := yaml.Unmarshal(cfg.LoadStaticFrontendConfig(), &config.Frontend) if err != nil { return nil, "", err } diff --git a/controllers/consoleplugin/consoleplugin_test.go b/controllers/consoleplugin/consoleplugin_test.go index 461a2e9d7..a98939635 100644 --- a/controllers/consoleplugin/consoleplugin_test.go +++ b/controllers/consoleplugin/consoleplugin_test.go @@ -506,7 +506,7 @@ func TestHTTPClientConfig(t *testing.T) { func TestNoMissingFields(t *testing.T) { var cfg config.FrontendConfig - err := yaml.Unmarshal(staticFrontendConfig, &cfg) + err := yaml.Unmarshal(config.LoadStaticFrontendConfig(), &cfg) assert.NoError(t, err) hasField := func(name string) bool { @@ -538,7 +538,7 @@ func TestNoMissingFields(t *testing.T) { func TestFieldsCardinalityWarns(t *testing.T) { var cfg config.FrontendConfig - err := yaml.Unmarshal(staticFrontendConfig, &cfg) + err := yaml.Unmarshal(config.LoadStaticFrontendConfig(), &cfg) assert.NoError(t, err) allowed := []config.CardinalityWarn{config.CardinalityWarnAvoid, config.CardinalityWarnCareful, config.CardinalityWarnFine} diff --git a/main.go b/main.go index ad8cd5ed9..5c65b9e9f 100644 --- a/main.go +++ b/main.go @@ -169,6 +169,10 @@ func main() { setupLog.Error(err, "unable to create v1beta2 webhook", "webhook", "FlowCollector") os.Exit(1) } + if err = (&metricsv1alpha1.FlowMetricWebhook{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "FlowMetric") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/pkg/helper/helpers.go b/pkg/helper/helpers.go index 96565520e..4a989d279 100644 --- a/pkg/helper/helpers.go +++ b/pkg/helper/helpers.go @@ -6,6 +6,9 @@ import ( "sort" "strings" + "github.com/netobserv/network-observability-operator/controllers/consoleplugin/config" + + "gopkg.in/yaml.v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -88,3 +91,36 @@ func UnstructuredDuration(in *metav1.Duration) string { } return in.ToUnstructured().(string) } + +func FindFilter(labels []string, isNumber bool) bool { + var cfg config.FrontendConfig + type filter struct { + exists bool + isNum bool + } + + err := yaml.Unmarshal(config.LoadStaticFrontendConfig(), &cfg) + if err != nil { + return false + } + + labelMap := make(map[string]filter) + + for _, f := range cfg.Fields { + labelMap[f.Name] = filter{true, false} + if f.Type == "number" { + labelMap[f.Name] = filter{true, true} + } + } + + for _, l := range labels { + if ok := labelMap[l].exists; !ok { + return false + } + if isNumber && !labelMap[l].isNum { + return false + } + } + + return true +} diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 322e1fa3a..627e7c8c7 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -24,7 +24,7 @@ import ( //+kubebuilder:rbac:groups=flows.netobserv.io,resources=flowcollectors,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=flows.netobserv.io,resources=flowcollectors/status,verbs=get;update;patch //+kubebuilder:rbac:groups=flows.netobserv.io,resources=flowcollectors/finalizers,verbs=update -//+kubebuilder:rbac:groups=flows.netobserv.io,resources=flowmetrics,verbs=get;list;watch +//+kubebuilder:rbac:groups=flows.netobserv.io,resources=flowmetrics,verbs=get;list;watchh;create;update;patch;delete //+kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,resourceNames=hostnetwork,verbs=use //+kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=list;create;update;watch //+kubebuilder:rbac:groups=apiregistration.k8s.io,resources=apiservices,verbs=list;get;watch