diff --git a/apis/v1alpha1/targetallocator_webhook.go b/apis/v1alpha1/targetallocator_webhook.go new file mode 100644 index 0000000000..bed76f29a4 --- /dev/null +++ b/apis/v1alpha1/targetallocator_webhook.go @@ -0,0 +1,143 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + "github.com/open-telemetry/opentelemetry-operator/internal/config" + "github.com/open-telemetry/opentelemetry-operator/internal/rbac" +) + +var ( + _ admission.CustomValidator = &TargetAllocatorWebhook{} + _ admission.CustomDefaulter = &TargetAllocatorWebhook{} +) + +// TODO: Uncomment this webhook after enabling the TargetAllocator controller +// //+kubebuilder:webhook:path=/mutate-opentelemetry-io-v1beta1-targetallocator,mutating=true,failurePolicy=fail,groups=opentelemetry.io,resources=targetallocators,verbs=create;update,versions=v1beta1,name=mtargetallocatorbeta.kb.io,sideEffects=none,admissionReviewVersions=v1 +// //+kubebuilder:webhook:verbs=create;update,path=/validate-opentelemetry-io-v1beta1-targetallocator,mutating=false,failurePolicy=fail,groups=opentelemetry.io,resources=targetallocators,versions=v1beta1,name=vtargetallocatorcreateupdatebeta.kb.io,sideEffects=none,admissionReviewVersions=v1 +// //+kubebuilder:webhook:verbs=delete,path=/validate-opentelemetry-io-v1beta1-targetallocator,mutating=false,failurePolicy=ignore,groups=opentelemetry.io,resources=targetallocators,versions=v1beta1,name=vtargetallocatordeletebeta.kb.io,sideEffects=none,admissionReviewVersions=v1 +// +kubebuilder:object:generate=false + +type TargetAllocatorWebhook struct { + logger logr.Logger + cfg config.Config + scheme *runtime.Scheme + reviewer *rbac.Reviewer +} + +func (w TargetAllocatorWebhook) Default(_ context.Context, obj runtime.Object) error { + targetallocator, ok := obj.(*TargetAllocator) + if !ok { + return fmt.Errorf("expected an TargetAllocator, received %T", obj) + } + return w.defaulter(targetallocator) +} + +func (w TargetAllocatorWebhook) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + otelcol, ok := obj.(*TargetAllocator) + if !ok { + return nil, fmt.Errorf("expected an TargetAllocator, received %T", obj) + } + return w.validate(ctx, otelcol) +} + +func (w TargetAllocatorWebhook) ValidateUpdate(ctx context.Context, _, newObj runtime.Object) (admission.Warnings, error) { + otelcol, ok := newObj.(*TargetAllocator) + if !ok { + return nil, fmt.Errorf("expected an TargetAllocator, received %T", newObj) + } + return w.validate(ctx, otelcol) +} + +func (w TargetAllocatorWebhook) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + otelcol, ok := obj.(*TargetAllocator) + if !ok || otelcol == nil { + return nil, fmt.Errorf("expected an TargetAllocator, received %T", obj) + } + return w.validate(ctx, otelcol) +} + +func (w TargetAllocatorWebhook) defaulter(ta *TargetAllocator) error { + if ta.Labels == nil { + ta.Labels = map[string]string{} + } + + one := int32(1) + + if ta.Spec.Replicas == nil { + ta.Spec.Replicas = &one + } + // if pdb isn't provided for target allocator and it's enabled + // using a valid strategy (consistent-hashing), + // we set MaxUnavailable 1, which will work even if there is + // just one replica, not blocking node drains but preventing + // out-of-the-box from disruption generated by them with replicas > 1 + if ta.Spec.AllocationStrategy == v1beta1.TargetAllocatorAllocationStrategyConsistentHashing && + ta.Spec.PodDisruptionBudget == nil { + ta.Spec.PodDisruptionBudget = &v1beta1.PodDisruptionBudgetSpec{ + MaxUnavailable: &intstr.IntOrString{ + Type: intstr.Int, + IntVal: 1, + }, + } + } + + return nil +} + +func (w TargetAllocatorWebhook) validate(ctx context.Context, ta *TargetAllocator) (admission.Warnings, error) { + // TODO: Further validate scrape configs + + warnings := admission.Warnings{} + + // validate port config + if err := v1beta1.ValidatePorts(ta.Spec.Ports); err != nil { + return warnings, err + } + + // if the prometheusCR is enabled, it needs a suite of permissions to function + if ta.Spec.PrometheusCR.Enabled { + warnings, err := v1beta1.CheckTargetAllocatorPrometheusCRPolicyRules(ctx, w.reviewer, ta.Spec.ServiceAccount, ta.GetNamespace()) + if err != nil || len(warnings) > 0 { + return warnings, err + } + } + + return warnings, nil +} + +func SetupTargetAllocatorWebhook(mgr ctrl.Manager, cfg config.Config, reviewer *rbac.Reviewer) error { + cvw := &TargetAllocatorWebhook{ + reviewer: reviewer, + logger: mgr.GetLogger().WithValues("handler", "TargetAllocatorWebhook", "version", "v1beta1"), + scheme: mgr.GetScheme(), + cfg: cfg, + } + return ctrl.NewWebhookManagedBy(mgr). + For(&TargetAllocator{}). + WithValidator(cvw). + WithDefaulter(cvw). + Complete() +} diff --git a/apis/v1alpha1/targetallocator_webhook_test.go b/apis/v1alpha1/targetallocator_webhook_test.go new file mode 100644 index 0000000000..aedbb62c82 --- /dev/null +++ b/apis/v1alpha1/targetallocator_webhook_test.go @@ -0,0 +1,356 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/go-logr/logr" + "github.com/stretchr/testify/assert" + authv1 "k8s.io/api/authorization/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/kubernetes/fake" + kubeTesting "k8s.io/client-go/testing" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + "github.com/open-telemetry/opentelemetry-operator/internal/config" + "github.com/open-telemetry/opentelemetry-operator/internal/rbac" +) + +func TestTargetAllocatorDefaultingWebhook(t *testing.T) { + one := int32(1) + five := int32(5) + + if err := AddToScheme(testScheme); err != nil { + fmt.Printf("failed to register scheme: %v", err) + os.Exit(1) + } + + tests := []struct { + name string + targetallocator TargetAllocator + expected TargetAllocator + }{ + { + name: "all fields default", + targetallocator: TargetAllocator{}, + expected: TargetAllocator{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{}, + }, + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &one, + }, + }, + }, + }, + { + name: "consistent hashing strategy", + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + AllocationStrategy: v1beta1.TargetAllocatorAllocationStrategyConsistentHashing, + }, + }, + expected: TargetAllocator{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{}, + }, + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &one, + PodDisruptionBudget: &v1beta1.PodDisruptionBudgetSpec{ + MaxUnavailable: &intstr.IntOrString{ + Type: intstr.Int, + IntVal: 1, + }, + }, + }, + AllocationStrategy: v1beta1.TargetAllocatorAllocationStrategyConsistentHashing, + }, + }, + }, + { + name: "provided values in spec", + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &five, + }, + }, + }, + expected: TargetAllocator{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{}, + }, + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &five, + }, + }, + }, + }, + { + name: "doesn't override unmanaged", + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &five, + ManagementState: v1beta1.ManagementStateUnmanaged, + }, + }, + }, + expected: TargetAllocator{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{}, + }, + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &five, + ManagementState: v1beta1.ManagementStateUnmanaged, + }, + }, + }, + }, + { + name: "Defined PDB", + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + PodDisruptionBudget: &v1beta1.PodDisruptionBudgetSpec{ + MinAvailable: &intstr.IntOrString{ + Type: intstr.String, + StrVal: "10%", + }, + }, + }, + }, + }, + expected: TargetAllocator{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{}, + }, + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &one, + PodDisruptionBudget: &v1beta1.PodDisruptionBudgetSpec{ + MinAvailable: &intstr.IntOrString{ + Type: intstr.String, + StrVal: "10%", + }, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + webhook := &TargetAllocatorWebhook{ + logger: logr.Discard(), + scheme: testScheme, + cfg: config.New( + config.WithTargetAllocatorImage("ta:v0.0.0"), + ), + } + ctx := context.Background() + err := webhook.Default(ctx, &test.targetallocator) + assert.NoError(t, err) + assert.Equal(t, test.expected, test.targetallocator) + }) + } +} + +func TestTargetAllocatorValidatingWebhook(t *testing.T) { + three := int32(3) + + tests := []struct { //nolint:govet + name string + targetallocator TargetAllocator + expectedErr string + expectedWarnings []string + shouldFailSar bool + }{ + { + name: "valid empty spec", + targetallocator: TargetAllocator{}, + }, + { + name: "valid full spec", + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &three, + Ports: []v1beta1.PortsSpec{ + { + ServicePort: v1.ServicePort{ + Name: "port1", + Port: 5555, + }, + }, + { + ServicePort: v1.ServicePort{ + Name: "port2", + Port: 5554, + Protocol: v1.ProtocolUDP, + }, + }, + }, + }, + }, + }, + }, + { + name: "prom CR admissions warning", + shouldFailSar: true, // force failure + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + PrometheusCR: v1beta1.TargetAllocatorPrometheusCR{ + Enabled: true, + }, + }, + }, + expectedWarnings: []string{ + "missing the following rules for monitoring.coreos.com/servicemonitors: [*]", + "missing the following rules for monitoring.coreos.com/podmonitors: [*]", + "missing the following rules for nodes/metrics: [get,list,watch]", + "missing the following rules for services: [get,list,watch]", + "missing the following rules for endpoints: [get,list,watch]", + "missing the following rules for namespaces: [get,list,watch]", + "missing the following rules for networking.k8s.io/ingresses: [get,list,watch]", + "missing the following rules for nodes: [get,list,watch]", + "missing the following rules for pods: [get,list,watch]", + "missing the following rules for configmaps: [get]", + "missing the following rules for discovery.k8s.io/endpointslices: [get,list,watch]", + "missing the following rules for nonResourceURL: /metrics: [get]", + }, + }, + { + name: "prom CR no admissions warning", + shouldFailSar: false, // force SAR okay + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{}, + }, + }, + { + name: "invalid port name", + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Ports: []v1beta1.PortsSpec{ + { + ServicePort: v1.ServicePort{ + // this port name contains a non alphanumeric character, which is invalid. + Name: "-testšŸ¦„port", + Port: 12345, + Protocol: v1.ProtocolTCP, + }, + }, + }, + }, + }, + }, + expectedErr: "the OpenTelemetry Spec Ports configuration is incorrect", + }, + { + name: "invalid port name, too long", + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Ports: []v1beta1.PortsSpec{ + { + ServicePort: v1.ServicePort{ + Name: "aaaabbbbccccdddd", // len: 16, too long + Port: 5555, + }, + }, + }, + }, + }, + }, + expectedErr: "the OpenTelemetry Spec Ports configuration is incorrect", + }, + { + name: "invalid port num", + targetallocator: TargetAllocator{ + Spec: TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Ports: []v1beta1.PortsSpec{ + { + ServicePort: v1.ServicePort{ + Name: "aaaabbbbccccddd", // len: 15 + // no port set means it's 0, which is invalid + }, + }, + }, + }, + }, + }, + expectedErr: "the OpenTelemetry Spec Ports configuration is incorrect", + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + cvw := &TargetAllocatorWebhook{ + logger: logr.Discard(), + scheme: testScheme, + cfg: config.New( + config.WithCollectorImage("targetallocator:v0.0.0"), + config.WithTargetAllocatorImage("ta:v0.0.0"), + ), + reviewer: getReviewer(test.shouldFailSar), + } + ctx := context.Background() + warnings, err := cvw.ValidateCreate(ctx, &test.targetallocator) + if test.expectedErr == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, test.expectedErr) + } + assert.Equal(t, len(test.expectedWarnings), len(warnings)) + assert.ElementsMatch(t, warnings, test.expectedWarnings) + }) + } +} + +func getReviewer(shouldFailSAR bool) *rbac.Reviewer { + c := fake.NewSimpleClientset() + c.PrependReactor("create", "subjectaccessreviews", func(action kubeTesting.Action) (handled bool, ret runtime.Object, err error) { + // check our expectation here + if !action.Matches("create", "subjectaccessreviews") { + return false, nil, fmt.Errorf("must be a create for a SAR") + } + sar, ok := action.(kubeTesting.CreateAction).GetObject().DeepCopyObject().(*authv1.SubjectAccessReview) + if !ok || sar == nil { + return false, nil, fmt.Errorf("bad object") + } + sar.Status = authv1.SubjectAccessReviewStatus{ + Allowed: !shouldFailSAR, + Denied: shouldFailSAR, + } + return true, sar, nil + }) + return rbac.NewReviewer(c) +} diff --git a/apis/v1beta1/collector_webhook.go b/apis/v1beta1/collector_webhook.go index 47d8528144..bedba31fb7 100644 --- a/apis/v1beta1/collector_webhook.go +++ b/apis/v1beta1/collector_webhook.go @@ -21,7 +21,6 @@ import ( "github.com/go-logr/logr" autoscalingv2 "k8s.io/api/autoscaling/v2" - rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/validation" @@ -36,34 +35,6 @@ import ( var ( _ admission.CustomValidator = &CollectorWebhook{} _ admission.CustomDefaulter = &CollectorWebhook{} - // targetAllocatorCRPolicyRules are the policy rules required for the CR functionality. - - targetAllocatorCRPolicyRules = []*rbacv1.PolicyRule{ - { - APIGroups: []string{"monitoring.coreos.com"}, - Resources: []string{"servicemonitors", "podmonitors"}, - Verbs: []string{"*"}, - }, { - APIGroups: []string{""}, - Resources: []string{"nodes", "nodes/metrics", "services", "endpoints", "pods", "namespaces"}, - Verbs: []string{"get", "list", "watch"}, - }, { - APIGroups: []string{""}, - Resources: []string{"configmaps"}, - Verbs: []string{"get"}, - }, { - APIGroups: []string{"discovery.k8s.io"}, - Resources: []string{"endpointslices"}, - Verbs: []string{"get", "list", "watch"}, - }, { - APIGroups: []string{"networking.k8s.io"}, - Resources: []string{"ingresses"}, - Verbs: []string{"get", "list", "watch"}, - }, { - NonResourceURLs: []string{"/metrics"}, - Verbs: []string{"get"}, - }, - } ) // +kubebuilder:webhook:path=/mutate-opentelemetry-io-v1beta1-opentelemetrycollector,mutating=true,failurePolicy=fail,groups=opentelemetry.io,resources=opentelemetrycollectors,verbs=create;update,versions=v1beta1,name=mopentelemetrycollectorbeta.kb.io,sideEffects=none,admissionReviewVersions=v1 @@ -266,14 +237,9 @@ func (c CollectorWebhook) validate(ctx context.Context, r *OpenTelemetryCollecto } } - // validator port config - for _, p := range r.Spec.Ports { - nameErrs := validation.IsValidPortName(p.Name) - numErrs := validation.IsValidPortNum(int(p.Port)) - if len(nameErrs) > 0 || len(numErrs) > 0 { - return warnings, fmt.Errorf("the OpenTelemetry Spec Ports configuration is incorrect, port name '%s' errors: %s, num '%d' errors: %s", - p.Name, nameErrs, p.Port, numErrs) - } + // validate port config + if err := ValidatePorts(r.Spec.Ports); err != nil { + return warnings, err } var maxReplicas *int32 @@ -328,11 +294,11 @@ func (c CollectorWebhook) validate(ctx context.Context, r *OpenTelemetryCollecto } // validate probes Liveness/Readiness - err := validateProbe("LivenessProbe", r.Spec.LivenessProbe) + err := ValidateProbe("LivenessProbe", r.Spec.LivenessProbe) if err != nil { return warnings, err } - err = validateProbe("ReadinessProbe", r.Spec.ReadinessProbe) + err = ValidateProbe("ReadinessProbe", r.Spec.ReadinessProbe) if err != nil { return warnings, err } @@ -382,17 +348,17 @@ func (c CollectorWebhook) validateTargetAllocatorConfig(ctx context.Context, r * } // if the prometheusCR is enabled, it needs a suite of permissions to function if r.Spec.TargetAllocator.PrometheusCR.Enabled { - if subjectAccessReviews, err := c.reviewer.CheckPolicyRules(ctx, r.Spec.TargetAllocator.ServiceAccount, r.GetNamespace(), targetAllocatorCRPolicyRules...); err != nil { - return nil, fmt.Errorf("unable to check rbac rules %w", err) - } else if allowed, deniedReviews := rbac.AllSubjectAccessReviewsAllowed(subjectAccessReviews); !allowed { - return rbac.WarningsGroupedByResource(deniedReviews), nil + warnings, err := CheckTargetAllocatorPrometheusCRPolicyRules( + ctx, c.reviewer, r.Spec.TargetAllocator.ServiceAccount, r.GetNamespace()) + if err != nil || len(warnings) > 0 { + return warnings, err } } return nil, nil } -func validateProbe(probeName string, probe *Probe) error { +func ValidateProbe(probeName string, probe *Probe) error { if probe != nil { if probe.InitialDelaySeconds != nil && *probe.InitialDelaySeconds < 0 { return fmt.Errorf("the OpenTelemetry Spec %s InitialDelaySeconds configuration is incorrect. InitialDelaySeconds should be greater than or equal to 0", probeName) @@ -416,6 +382,18 @@ func validateProbe(probeName string, probe *Probe) error { return nil } +func ValidatePorts(ports []PortsSpec) error { + for _, p := range ports { + nameErrs := validation.IsValidPortName(p.Name) + numErrs := validation.IsValidPortNum(int(p.Port)) + if len(nameErrs) > 0 || len(numErrs) > 0 { + return fmt.Errorf("the OpenTelemetry Spec Ports configuration is incorrect, port name '%s' errors: %s, num '%d' errors: %s", + p.Name, nameErrs, p.Port, numErrs) + } + } + return nil +} + func checkAutoscalerSpec(autoscaler *AutoscalerSpec) error { if autoscaler.Behavior != nil { if autoscaler.Behavior.ScaleDown != nil && autoscaler.Behavior.ScaleDown.StabilizationWindowSeconds != nil && diff --git a/apis/v1beta1/targetallocator_rbac.go b/apis/v1beta1/targetallocator_rbac.go new file mode 100644 index 0000000000..4fb48832e6 --- /dev/null +++ b/apis/v1beta1/targetallocator_rbac.go @@ -0,0 +1,75 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1beta1 + +import ( + "context" + "fmt" + + rbacv1 "k8s.io/api/rbac/v1" + + "github.com/open-telemetry/opentelemetry-operator/internal/rbac" +) + +var ( + + // targetAllocatorCRPolicyRules are the policy rules required for the CR functionality. + targetAllocatorCRPolicyRules = []*rbacv1.PolicyRule{ + { + APIGroups: []string{"monitoring.coreos.com"}, + Resources: []string{"servicemonitors", "podmonitors"}, + Verbs: []string{"*"}, + }, { + APIGroups: []string{""}, + Resources: []string{"nodes", "nodes/metrics", "services", "endpoints", "pods", "namespaces"}, + Verbs: []string{"get", "list", "watch"}, + }, { + APIGroups: []string{""}, + Resources: []string{"configmaps"}, + Verbs: []string{"get"}, + }, { + APIGroups: []string{"discovery.k8s.io"}, + Resources: []string{"endpointslices"}, + Verbs: []string{"get", "list", "watch"}, + }, { + APIGroups: []string{"networking.k8s.io"}, + Resources: []string{"ingresses"}, + Verbs: []string{"get", "list", "watch"}, + }, { + NonResourceURLs: []string{"/metrics"}, + Verbs: []string{"get"}, + }, + } +) + +func CheckTargetAllocatorPrometheusCRPolicyRules( + ctx context.Context, + reviewer *rbac.Reviewer, + namespace string, + serviceAccountName string) (warnings []string, err error) { + subjectAccessReviews, err := reviewer.CheckPolicyRules( + ctx, + namespace, + serviceAccountName, + targetAllocatorCRPolicyRules..., + ) + if err != nil { + return []string{}, fmt.Errorf("unable to check rbac rules %w", err) + } + if allowed, deniedReviews := rbac.AllSubjectAccessReviewsAllowed(subjectAccessReviews); !allowed { + return rbac.WarningsGroupedByResource(deniedReviews), nil + } + return []string{}, nil +} diff --git a/bundle/manifests/opentelemetry-operator.clusterserviceversion.yaml b/bundle/manifests/opentelemetry-operator.clusterserviceversion.yaml index cbb2a798d3..33f7a4b88a 100644 --- a/bundle/manifests/opentelemetry-operator.clusterserviceversion.yaml +++ b/bundle/manifests/opentelemetry-operator.clusterserviceversion.yaml @@ -99,7 +99,7 @@ metadata: categories: Logging & Tracing,Monitoring certified: "false" containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator - createdAt: "2024-06-25T12:03:57Z" + createdAt: "2024-07-03T13:39:45Z" description: Provides the OpenTelemetry components, including the Collector operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3