Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions manifests/0000_70_dns-operator_00-cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ rules:
- rbac.authorization.k8s.io
resources:
- clusterroles
- roles

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allows the operator to update pkg/manifests/assets/dns/metrics/role.yaml on the cluster

verbs:
- update

Expand Down
8 changes: 8 additions & 0 deletions manifests/0000_90_dns-operator_00_prometheusrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,11 @@ rules:
- get
- list
- watch
- apiGroups:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to add these same permissions to the ClusterRole, otherwise the user running openshift-dns-operator won´t be able to give this permission.

See:

	ERROR	Reconciler error	{"controller": "dns_controller", "object": {"name":"default"}, "namespace": "", "name": "default", "reconcileID": "edd6c3b1-ee05-40eb-a566-6a83471fb643", "error": "failed to ensure dns default: failed to integrate metrics with openshift-monitoring for dns default: failed to ensure dns metrics role for default: failed to update dns metrics role openshift-dns/prometheus-k8s: roles.rbac.authorization.k8s.io \"prometheus-k8s\" is forbidden: user \"system:serviceaccount:openshift-dns-operator:dns-operator\" (groups=[\"system:serviceaccounts\" \"system:serviceaccounts:openshift-dns-operator\" \"system:authenticated\"]) is attempting to grant RBAC permissions not currently held:\n{APIGroups:[\"discovery.k8s.io\"], Resources:[\"endpointslices\"], Verbs:[\"get\"]}", "errorCauses": [{"error": "failed to ensure dns default: failed to integrate metrics with openshift-monitoring for dns default: failed to ensure dns metrics role for default: failed to update dns metrics role openshift-dns/prometheus-k8s: roles.rbac.authorization.k8s.io \"prometheus-k8s\" is forbidden: user \"system:serviceaccount:openshift-dns-operator:dns-operator\" (groups=[\"system:serviceaccounts\" \"system:serviceaccounts:openshift-dns-operator\" \"system:authenticated\"]) is attempting to grant RBAC permissions not currently held:\n{APIGroups:[\"discovery.k8s.io\"], Resources:[\"endpointslices\"], Verbs:[\"get\"]}"}]}

- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
1 change: 1 addition & 0 deletions manifests/0000_90_dns-operator_02_servicemonitor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ spec:
selector:
matchLabels:
name: dns-operator
serviceDiscoveryRole: EndpointSlice
8 changes: 8 additions & 0 deletions pkg/manifests/assets/dns/metrics/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@ rules:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- list
- watch
11 changes: 2 additions & 9 deletions pkg/operator/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,15 +464,8 @@ func (r *reconciler) ensureMetricsIntegration(dns *operatorv1.DNS, svc *corev1.S
logrus.Infof("created dns metrics cluster role binding %s", crb.Name)
}

mr := manifests.MetricsRole()
if err := r.client.Get(context.TODO(), types.NamespacedName{Namespace: mr.Namespace, Name: mr.Name}, mr); err != nil {
if !errors.IsNotFound(err) {
return fmt.Errorf("failed to get dns metrics role %s/%s: %v", mr.Namespace, mr.Name, err)
}
if err := r.client.Create(context.TODO(), mr); err != nil {
return fmt.Errorf("failed to create dns metrics role %s/%s: %v", mr.Namespace, mr.Name, err)
}
logrus.Infof("created dns metrics role %s/%s", mr.Namespace, mr.Name)
if _, _, err := r.ensureDNSMetricsRole(); err != nil {
return fmt.Errorf("failed to ensure dns metrics role for %s: %v", dns.Name, err)
}

mrb := manifests.MetricsRoleBinding()
Expand Down
79 changes: 79 additions & 0 deletions pkg/operator/controller/controller_metrics_role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package controller

import (
"context"
"fmt"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/openshift/cluster-dns-operator/pkg/manifests"

"github.com/sirupsen/logrus"

rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
)

func (r *reconciler) ensureDNSMetricsRole() (bool, *rbacv1.Role, error) {
desired := manifests.MetricsRole()

have, current, err := r.currentDNSMetricsRole()
if err != nil {
return false, nil, err
}

switch {
case !have:
if err := r.client.Create(context.TODO(), desired); err != nil {
return false, nil, fmt.Errorf("failed to create dns metrics role %s/%s: %v", desired.GetNamespace(), desired.GetName(), err)
}
logrus.Infof("created dns metrics role %s/%s", desired.GetNamespace(), desired.GetName())
return r.currentDNSMetricsRole()
case have:
if updated, err := r.updateDNSMetricsRole(current, desired); err != nil {
return true, current, err
} else if updated {
return r.currentDNSMetricsRole()
}
}
return true, current, nil
}

func (r *reconciler) currentDNSMetricsRole() (bool, *rbacv1.Role, error) {
desired := manifests.MetricsRole()
current := &rbacv1.Role{}
if err := r.client.Get(context.TODO(), types.NamespacedName{Namespace: desired.GetNamespace(), Name: desired.GetName()}, current); err != nil {
if errors.IsNotFound(err) {
return false, nil, nil
}
return false, nil, err
}
return true, current, nil
}

func (r *reconciler) updateDNSMetricsRole(current, desired *rbacv1.Role) (bool, error) {
changed, updated := dnsMetricsRoleChanged(current, desired)
if !changed {
return false, nil
}

// Diff before updating because the client may mutate the object.
diff := cmp.Diff(current, updated, cmpopts.EquateEmpty())
if err := r.client.Update(context.TODO(), updated); err != nil {
return false, fmt.Errorf("failed to update dns metrics role %s/%s: %v", updated.GetNamespace(), updated.GetName(), err)
}
logrus.Infof("updated dns metrics role %s/%s: %v", updated.GetNamespace(), updated.GetName(), diff)
return true, nil
}

func dnsMetricsRoleChanged(current, desired *rbacv1.Role) (bool, *rbacv1.Role) {
if cmp.Equal(current.Rules, desired.Rules, cmpopts.EquateEmpty()) {
return false, nil
}

updated := current.DeepCopy()
updated.Rules = desired.Rules

return true, updated
}
26 changes: 26 additions & 0 deletions pkg/operator/controller/controller_metrics_role_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package controller

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


import (
"testing"

"github.com/openshift/cluster-dns-operator/pkg/manifests"
rbacv1 "k8s.io/api/rbac/v1"
)

func TestDNSggMetricsRoleChanged(t *testing.T) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: DNSgg?

role1 := manifests.MetricsRole()
role2 := manifests.MetricsRole()
if changed, _ := dnsMetricsRoleChanged(role1, role2); changed {
t.Fatal("expected changed to be false for two roles with identical rules")
}
role2.Rules = append(role2.Rules, rbacv1.PolicyRule{
APIGroups: []string{"example.io"},
Resources: []string{"foos"},
Verbs: []string{"get"},
})
if changed, updated := dnsMetricsRoleChanged(role1, role2); !changed {
t.Fatal("expected changed to be true after adding a rule")
} else if changedAgain, _ := dnsMetricsRoleChanged(role2, updated); changedAgain {
t.Fatal("dnsMetricsRoleChanged does not behave as a fixed-point function")
}
}
3 changes: 2 additions & 1 deletion pkg/operator/controller/controller_service_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ func desiredServiceMonitor(dns *operatorv1.DNS, svc *corev1.Service, daemonsetRe
"openshift-dns",
},
},
"selector": map[string]interface{}{},
"selector": map[string]interface{}{},
"serviceDiscoveryRole": "EndpointSlice",
"endpoints": []interface{}{
map[string]interface{}{
"bearerTokenFile": "/var/run/secrets/kubernetes.io/serviceaccount/token",
Expand Down
8 changes: 8 additions & 0 deletions pkg/operator/controller/controller_service_monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ func TestDNSServiceMonitorChanged(t *testing.T) {
},
expect: true,
},
{
description: "if serviceDiscoveryRole changes",
mutate: func(serviceMonitor *unstructured.Unstructured) {
spec := serviceMonitor.Object["spec"].(map[string]interface{})
spec["serviceDiscoveryRole"] = "EndpointSlice"
},
expect: true,
},
{
description: "if labels change",
mutate: func(serviceMonitor *unstructured.Unstructured) {
Expand Down