Skip to content

Commit

Permalink
Merge pull request #4388 from CecileRobertMichon/cherry-pick-annotations
Browse files Browse the repository at this point in the history
🌱  Annotate nodes with cluster and owner info
  • Loading branch information
k8s-ci-robot authored Mar 29, 2021
2 parents ee72431 + f9e3252 commit 258684a
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 0 deletions.
15 changes: 15 additions & 0 deletions api/v1alpha3/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ const (
// tool uses this label for implementing provider's lifecycle operations.
ProviderLabelName = "cluster.x-k8s.io/provider"

// ClusterNameAnnotation is the annotation set on nodes identifying the name of the cluster the node belongs to.
ClusterNameAnnotation = "cluster.x-k8s.io/cluster-name"

// ClusterNamespaceAnnotation is the annotation set on nodes identifying the namespace of the cluster the node belongs to.
ClusterNamespaceAnnotation = "cluster.x-k8s.io/cluster-namespace"

// MachineAnnotation is the annotation set on nodes identifying the machine the node belongs to.
MachineAnnotation = "cluster.x-k8s.io/machine"

// OwnerKindAnnotation is the annotation set on nodes identifying the owner kind.
OwnerKindAnnotation = "cluster.x-k8s.io/owner-kind"

// OwnerNameAnnotation is the annotation set on nodes identifying the owner name.
OwnerNameAnnotation = "cluster.x-k8s.io/owner-name"

// PausedAnnotation is an annotation that can be applied to any Cluster API
// object to prevent a controller from processing a resource.
//
Expand Down
24 changes: 24 additions & 0 deletions controllers/machine_controller_noderef.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ package controllers
import (
"context"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/cluster-api/util/annotations"
"sigs.k8s.io/cluster-api/util/patch"

"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -84,6 +87,27 @@ func (r *MachineReconciler) reconcileNode(ctx context.Context, cluster *clusterv
r.recorder.Event(machine, corev1.EventTypeNormal, "SuccessfulSetNodeRef", machine.Status.NodeRef.Name)
}

// Reconcile node annotations.
patchHelper, err := patch.NewHelper(node, remoteClient)
if err != nil {
return ctrl.Result{}, err
}
desired := map[string]string{
clusterv1.ClusterNameAnnotation: machine.Spec.ClusterName,
clusterv1.ClusterNamespaceAnnotation: machine.GetNamespace(),
clusterv1.MachineAnnotation: machine.Name,
}
if owner := metav1.GetControllerOfNoCopy(machine); owner != nil {
desired[clusterv1.OwnerKindAnnotation] = owner.Kind
desired[clusterv1.OwnerNameAnnotation] = owner.Name
}
if annotations.AddAnnotations(node, desired) {
if err := patchHelper.Patch(ctx, node); err != nil {
logger.V(2).Info("Failed patch node to set annotations", "err", err, "node name", node.Name)
return ctrl.Result{}, err
}
}

// Do the remaining node health checks, then set the node health to true if all checks pass.
status, message := summarizeNodeConditions(node)
if status == corev1.ConditionFalse {
Expand Down
27 changes: 27 additions & 0 deletions exp/controllers/machinepool_controller_noderef.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package controllers
import (
"context"
"fmt"
"sigs.k8s.io/cluster-api/util/annotations"
"sigs.k8s.io/cluster-api/util/patch"
"time"

ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -100,6 +102,31 @@ func (r *MachinePoolReconciler) reconcileNodeRefs(ctx context.Context, cluster *
logger.Info("Set MachinePools's NodeRefs", "noderefs", mp.Status.NodeRefs)
r.recorder.Event(mp, apicorev1.EventTypeNormal, "SuccessfulSetNodeRefs", fmt.Sprintf("%+v", mp.Status.NodeRefs))

// Reconcile node annotations.
for _, nodeRef := range nodeRefsResult.references {
node := &corev1.Node{}
if err := clusterClient.Get(ctx, client.ObjectKey{Name: nodeRef.Name}, node); err != nil {
logger.V(2).Info("Failed to get Node, skipping setting annotations", "err", err, "nodeRef.Name", nodeRef.Name)
continue
}
patchHelper, err := patch.NewHelper(node, clusterClient)
if err != nil {
return ctrl.Result{}, err
}
desired := map[string]string{
clusterv1.ClusterNameAnnotation: mp.Spec.ClusterName,
clusterv1.ClusterNamespaceAnnotation: mp.GetNamespace(),
clusterv1.OwnerKindAnnotation: mp.Kind,
clusterv1.OwnerNameAnnotation: mp.Name,
}
if annotations.AddAnnotations(node, desired) {
if err := patchHelper.Patch(ctx, node); err != nil {
logger.V(2).Info("Failed patch node to set annotations", "err", err, "node name", node.Name)
return ctrl.Result{}, err
}
}
}

if mp.Status.Replicas != mp.Status.ReadyReplicas || len(nodeRefsResult.references) != int(mp.Status.ReadyReplicas) {
r.Log.Info("NodeRefs != ReadyReplicas", "NodeRefs", len(nodeRefsResult.references), "ReadyReplicas", mp.Status.ReadyReplicas)
conditions.MarkFalse(mp, expv1.ReplicasReadyCondition, expv1.WaitingForReplicasReadyReason, clusterv1.ConditionSeverityInfo, "")
Expand Down
4 changes: 4 additions & 0 deletions util/annotations/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,13 @@ func HasWithPrefix(prefix string, annotations map[string]string) bool {

// AddAnnotations sets the desired annotations on the object and returns true if the annotations have changed.
func AddAnnotations(o metav1.Object, desired map[string]string) bool {
if len(desired) == 0 {
return false
}
annotations := o.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
o.SetAnnotations(annotations)
}
hasChanged := false
for k, v := range desired {
Expand Down
152 changes: 152 additions & 0 deletions util/annotations/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
Copyright 2020 The Kubernetes 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 annotations

import (
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
)

func TestAddAnnotations(t *testing.T) {
g := NewWithT(t)

var testcases = []struct {
name string
obj metav1.Object
input map[string]string
expected map[string]string
changed bool
}{
{
name: "should return false if no changes are made",
obj: &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"foo": "bar",
},
},
Spec: corev1.NodeSpec{},
Status: corev1.NodeStatus{},
},
input: map[string]string{
"foo": "bar",
},
expected: map[string]string{
"foo": "bar",
},
changed: false,
},
{
name: "should do nothing if no annotations are provided",
obj: &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"foo": "bar",
},
},
Spec: corev1.NodeSpec{},
Status: corev1.NodeStatus{},
},
input: map[string]string{},
expected: map[string]string{
"foo": "bar",
},
changed: false,
},
{
name: "should do nothing if no annotations are provided and have been nil before",
obj: &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Annotations: nil,
},
Spec: corev1.NodeSpec{},
Status: corev1.NodeStatus{},
},
input: map[string]string{},
expected: nil,
changed: false,
},
{
name: "should return true if annotations are added",
obj: &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"foo": "bar",
},
},
Spec: corev1.NodeSpec{},
Status: corev1.NodeStatus{},
},
input: map[string]string{
"thing1": "thing2",
"buzz": "blah",
},
expected: map[string]string{
"foo": "bar",
"thing1": "thing2",
"buzz": "blah",
},
changed: true,
},
{
name: "should return true if annotations are changed",
obj: &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"foo": "bar",
},
},
Spec: corev1.NodeSpec{},
Status: corev1.NodeStatus{},
},
input: map[string]string{
"foo": "buzz",
},
expected: map[string]string{
"foo": "buzz",
},
changed: true,
},
{
name: "should return true if annotations are changed and have been nil before",
obj: &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Annotations: nil,
},
Spec: corev1.NodeSpec{},
Status: corev1.NodeStatus{},
},
input: map[string]string{
"foo": "buzz",
},
expected: map[string]string{
"foo": "buzz",
},
changed: true,
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
res := AddAnnotations(tc.obj, tc.input)
g.Expect(res).To(Equal(tc.changed))
g.Expect(tc.obj.GetAnnotations()).To(Equal(tc.expected))
})
}
}

0 comments on commit 258684a

Please sign in to comment.