diff --git a/docs/documents/apis.md b/docs/documents/apis.md
index 9b2668d1d..1ed350d9e 100644
--- a/docs/documents/apis.md
+++ b/docs/documents/apis.md
@@ -2435,6 +2435,22 @@ Kubernetes core/v1.ResourceList
+
instanceType
|
diff --git a/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml b/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml
index 4452c16c2..f0cd9d515 100644
--- a/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml
+++ b/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml
@@ -78,6 +78,16 @@ spec:
region:
description: Region of the expected node belonging to nodeGroup
type: string
+ virtualCapacity:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: VirtualCapacity represents the expected Node 'virtual'
+ capacity ie comprising virtual extended resources.
+ type: object
zone:
description: Zone of the expected node belonging to nodeGroup
type: string
diff --git a/pkg/apis/machine/types.go b/pkg/apis/machine/types.go
index 8ac47c2f0..0facf09ba 100644
--- a/pkg/apis/machine/types.go
+++ b/pkg/apis/machine/types.go
@@ -743,6 +743,10 @@ type NodeTemplate struct {
// Capacity contains subfields to track all node resources required to scale nodegroup from zero
Capacity corev1.ResourceList
+ // VirtualCapacity represents the expected Node 'virtual' capacity ie comprising virtual extended resources.
+ // +optional
+ VirtualCapacity corev1.ResourceList
+
// Instance type of the node belonging to nodeGroup
InstanceType string
diff --git a/pkg/apis/machine/v1alpha1/machineclass_types.go b/pkg/apis/machine/v1alpha1/machineclass_types.go
index 59ee9e1e0..2db540a3f 100644
--- a/pkg/apis/machine/v1alpha1/machineclass_types.go
+++ b/pkg/apis/machine/v1alpha1/machineclass_types.go
@@ -66,6 +66,10 @@ type NodeTemplate struct {
// Capacity contains subfields to track all node resources required to scale nodegroup from zero
Capacity corev1.ResourceList `json:"capacity"`
+ // VirtualCapacity represents the expected Node 'virtual' capacity ie comprising virtual extended resources.
+ // +optional
+ VirtualCapacity corev1.ResourceList `json:"virtualCapacity,omitempty"`
+
// Instance type of the node belonging to nodeGroup
InstanceType string `json:"instanceType"`
diff --git a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go
index 1ef0f3aeb..7d5d1b485 100644
--- a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go
+++ b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go
@@ -1052,6 +1052,7 @@ func Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(in *mac
func autoConvert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(in *NodeTemplate, out *machine.NodeTemplate, s conversion.Scope) error {
out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity))
+ out.VirtualCapacity = *(*v1.ResourceList)(unsafe.Pointer(&in.VirtualCapacity))
out.InstanceType = in.InstanceType
out.Region = in.Region
out.Zone = in.Zone
@@ -1066,6 +1067,7 @@ func Convert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(in *NodeTemplate, out
func autoConvert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(in *machine.NodeTemplate, out *NodeTemplate, s conversion.Scope) error {
out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity))
+ out.VirtualCapacity = *(*v1.ResourceList)(unsafe.Pointer(&in.VirtualCapacity))
out.InstanceType = in.InstanceType
out.Region = in.Region
out.Zone = in.Zone
diff --git a/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go
index a5f4b0571..2691557c9 100644
--- a/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go
@@ -686,6 +686,13 @@ func (in *NodeTemplate) DeepCopyInto(out *NodeTemplate) {
(*out)[key] = val.DeepCopy()
}
}
+ if in.VirtualCapacity != nil {
+ in, out := &in.VirtualCapacity, &out.VirtualCapacity
+ *out = make(v1.ResourceList, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val.DeepCopy()
+ }
+ }
if in.Architecture != nil {
in, out := &in.Architecture, &out.Architecture
*out = new(string)
diff --git a/pkg/apis/machine/zz_generated.deepcopy.go b/pkg/apis/machine/zz_generated.deepcopy.go
index dd0487331..05c40b651 100644
--- a/pkg/apis/machine/zz_generated.deepcopy.go
+++ b/pkg/apis/machine/zz_generated.deepcopy.go
@@ -779,6 +779,13 @@ func (in *NodeTemplate) DeepCopyInto(out *NodeTemplate) {
(*out)[key] = val.DeepCopy()
}
}
+ if in.VirtualCapacity != nil {
+ in, out := &in.VirtualCapacity, &out.VirtualCapacity
+ *out = make(v1.ResourceList, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val.DeepCopy()
+ }
+ }
if in.Architecture != nil {
in, out := &in.Architecture, &out.Architecture
*out = new(string)
diff --git a/pkg/openapi/openapi_generated.go b/pkg/openapi/openapi_generated.go
index f602824f5..c4ee08c09 100644
--- a/pkg/openapi/openapi_generated.go
+++ b/pkg/openapi/openapi_generated.go
@@ -1648,6 +1648,20 @@ func schema_pkg_apis_machine_v1alpha1_NodeTemplate(ref common.ReferenceCallback)
},
},
},
+ "virtualCapacity": {
+ SchemaProps: spec.SchemaProps{
+ Description: "VirtualCapacity represents the expected Node 'virtual' capacity ie comprising virtual extended resources.",
+ Type: []string{"object"},
+ AdditionalProperties: &spec.SchemaOrBool{
+ Allows: true,
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"),
+ },
+ },
+ },
+ },
+ },
"instanceType": {
SchemaProps: spec.SchemaProps{
Description: "Instance type of the node belonging to nodeGroup",
diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go
index a15710f10..53cca4460 100644
--- a/pkg/util/provider/machinecontroller/machine.go
+++ b/pkg/util/provider/machinecontroller/machine.go
@@ -220,7 +220,7 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp
return retry, err
}
- retry, err = c.syncMachineNodeTemplates(ctx, machine)
+ retry, err = c.syncNodeTemplates(ctx, machine, machineClass)
if err != nil {
return retry, err
}
diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go
index 7e7e41430..7f76293ac 100644
--- a/pkg/util/provider/machinecontroller/machine_util.go
+++ b/pkg/util/provider/machinecontroller/machine_util.go
@@ -486,14 +486,17 @@ func (c *controller) updateMachineStatusAndNodeCondition(ctx context.Context, ma
return machineutils.ShortRetry, err
}
-// syncMachineNodeTemplate syncs nodeTemplates between machine and corresponding node-object.
-// It ensures, that any nodeTemplate element available on Machine should be available on node-object.
+// syncNodeTemplates syncs nodeTemplates between machine, machineClass and corresponding node-object.
+// It ensures that any nodeTemplate element available on Machine should be available on node-object.
+// It ensures that MachineClass.NodeTemplate.VirtualCapacity is synced to the Node's Capacity.
// Although there could be more elements already available on node-object which will not be touched.
-func (c *controller) syncMachineNodeTemplates(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) {
+func (c *controller) syncNodeTemplates(ctx context.Context, machine *v1alpha1.Machine, machineClass *v1alpha1.MachineClass) (machineutils.RetryPeriod, error) {
var (
- initializedNodeAnnotation bool
- currentlyAppliedALTJSONByte []byte
- lastAppliedALT v1alpha1.NodeTemplateSpec
+ initializedNodeAnnotation bool
+ currentlyAppliedALTJSONByte []byte
+ lastAppliedALT v1alpha1.NodeTemplateSpec
+ currentlyAppliedVirtualCapacityJSONByte []byte
+ lastAppliedVirtualCapacity v1.ResourceList
)
node, err := c.nodeLister.Get(getNodeName(machine))
@@ -524,10 +527,30 @@ func (c *controller) syncMachineNodeTemplates(ctx context.Context, machine *v1al
}
}
+ lastAppliedVirtualCapacityJSONString, exists := node.Annotations[machineutils.LastAppliedVirtualCapacityAnnotation]
+ if exists {
+ err = json.Unmarshal([]byte(lastAppliedVirtualCapacityJSONString), &lastAppliedVirtualCapacity)
+ if err != nil {
+ klog.Errorf("Error occurred while syncing node virtual capacity: %s", err)
+ return machineutils.ShortRetry, err
+ }
+ }
+
annotationsChanged := SyncMachineAnnotations(machine, nodeCopy, lastAppliedALT.Annotations)
labelsChanged := SyncMachineLabels(machine, nodeCopy, lastAppliedALT.Labels)
taintsChanged := SyncMachineTaints(machine, nodeCopy, lastAppliedALT.Spec.Taints)
+ var virtualCapacityChanged bool
+ var desiredVirtualCapacity v1.ResourceList
+ if machineClass != nil && machineClass.NodeTemplate != nil {
+ desiredVirtualCapacity = machineClass.NodeTemplate.VirtualCapacity
+ virtualCapacityChanged = SyncVirtualCapacity(desiredVirtualCapacity, nodeCopy, lastAppliedVirtualCapacity)
+ }
+
+ if !initializedNodeAnnotation && !annotationsChanged && !labelsChanged && !taintsChanged && !virtualCapacityChanged {
+ return machineutils.LongRetry, nil
+ }
+
// Update node-object with latest nodeTemplate elements if elements have changed.
if initializedNodeAnnotation || labelsChanged || annotationsChanged || taintsChanged {
@@ -548,23 +571,44 @@ func (c *controller) syncMachineNodeTemplates(ctx context.Context, machine *v1al
return machineutils.ShortRetry, err
}
nodeCopy.Annotations[machineutils.LastAppliedALTAnnotation] = string(currentlyAppliedALTJSONByte)
+ }
- _, err := c.targetCoreClient.CoreV1().Nodes().Update(ctx, nodeCopy, metav1.UpdateOptions{})
+ if virtualCapacityChanged {
+ klog.V(3).Infof("virtualCapacity changed, attempting UpdateStatus for node.Status.Capacity of node %q to %v", nodeCopy.Name, nodeCopy.Status.Capacity)
+ // must patch the Node’s status subresource, because capacity lives under status
+ nodeUpdated, err := c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, nodeCopy, metav1.UpdateOptions{})
if err != nil {
- // Keep retrying until update goes through
- klog.Errorf("Updated failed for node object of machine %q. Retrying, error: %q", machine.Name, err)
+ klog.Errorf("UpdateStatus failed for node %q of machine %q. error: %q", node.Name, machine.Name, err)
+ return machineutils.ShortRetry, err
+ }
+ klog.V(3).Infof("node.Status.Capacity of node %q updated to: %v", node.Name, nodeUpdated.Status.Capacity)
+ currentlyAppliedVirtualCapacityJSONByte, err = json.Marshal(desiredVirtualCapacity)
+ if err != nil {
+ klog.Errorf("Error occurred while syncing node virtual capacity of node %q: %v", node.Name, err)
+ return machineutils.ShortRetry, err
+ }
+ nodeCopy = nodeUpdated.DeepCopy()
+ if len(desiredVirtualCapacity) == 0 {
+ delete(nodeCopy.Annotations, machineutils.LastAppliedVirtualCapacityAnnotation)
} else {
- // Return error to continue in next reconcile
- err = errSuccessfulALTsync
+ nodeCopy.Annotations[machineutils.LastAppliedVirtualCapacityAnnotation] = string(currentlyAppliedVirtualCapacityJSONByte)
}
+ }
- if apierrors.IsConflict(err) {
- return machineutils.ConflictRetry, err
- }
- return machineutils.ShortRetry, err
+ _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, nodeCopy, metav1.UpdateOptions{})
+ if err != nil {
+ // Keep retrying until update goes through
+ klog.Errorf("Updated failed for node object of machine %q. Retrying, error: %q", machine.Name, err)
+ } else {
+ // Return error to continue in next reconcile
+ err = errSuccessfulALTsync
}
- return machineutils.LongRetry, nil
+ if apierrors.IsConflict(err) {
+ return machineutils.ConflictRetry, err
+ }
+ return machineutils.ShortRetry, err
+
}
// SyncMachineAnnotations syncs the annotations of the machine with node-objects.
@@ -719,6 +763,37 @@ func SyncMachineTaints(
return toBeUpdated
}
+// SyncVirtualCapacity syncs the MachineClass.NodeTemplate.VirtualCapacity with the Node.Status.Capacity
+// It returns true if update is needed else false.
+func SyncVirtualCapacity(desiredVirtualCapacity v1.ResourceList, node *v1.Node, lastAppliedVirtualCapacity v1.ResourceList) bool {
+ toBeUpdated := false
+
+ if node.Status.Capacity == nil {
+ node.Status.Capacity = v1.ResourceList{}
+ }
+ if desiredVirtualCapacity == nil {
+ desiredVirtualCapacity = v1.ResourceList{}
+ }
+
+ // Delete any keys that existed in the past but has been deleted now
+ for prevKey := range lastAppliedVirtualCapacity {
+ if _, exists := desiredVirtualCapacity[prevKey]; !exists {
+ delete(node.Status.Capacity, prevKey)
+ toBeUpdated = true
+ }
+ }
+
+ // Add/Update any key that doesn't exist or whose value as changed
+ for targKey, targQuant := range desiredVirtualCapacity {
+ if nodeQuant, exists := node.Status.Capacity[targKey]; !exists || !nodeQuant.Equal(targQuant) {
+ node.Status.Capacity[targKey] = targQuant
+ toBeUpdated = true
+ }
+ }
+
+ return toBeUpdated
+}
+
// machineCreateErrorHandler updates the machine status based on
// CreateMachineResponse and the error during the machine creation
func (c *controller) machineCreateErrorHandler(ctx context.Context, machine *v1alpha1.Machine, createMachineResponse *driver.CreateMachineResponse, err error) (machineutils.RetryPeriod, error) {
diff --git a/pkg/util/provider/machinecontroller/machine_util_test.go b/pkg/util/provider/machinecontroller/machine_util_test.go
index 26d928a9b..53e92a6ba 100644
--- a/pkg/util/provider/machinecontroller/machine_util_test.go
+++ b/pkg/util/provider/machinecontroller/machine_util_test.go
@@ -9,6 +9,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "k8s.io/klog/v2"
"time"
machinev1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
@@ -22,7 +23,6 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
- "k8s.io/klog/v2"
"k8s.io/utils/ptr"
)
@@ -35,9 +35,10 @@ const (
)
var _ = Describe("machine_util", func() {
- Describe("#syncMachineNodeTemplates", func() {
+ Describe("#syncNodeTemplates", func() {
type setup struct {
- machine *machinev1.Machine
+ machine *machinev1.Machine
+ machineClass *machinev1.MachineClass
}
type action struct {
node *corev1.Node
@@ -61,6 +62,7 @@ var _ = Describe("machine_util", func() {
coreObjects := []runtime.Object{}
machineObject := data.setup.machine
+ machineClass := data.setup.machineClass
nodeObject := data.action.node
coreObjects = append(coreObjects, nodeObject)
@@ -70,7 +72,7 @@ var _ = Describe("machine_util", func() {
defer trackers.Stop()
waitForCacheSync(stop, c)
- _, err := c.syncMachineNodeTemplates(context.TODO(), machineObject)
+ _, err := c.syncNodeTemplates(context.TODO(), machineObject, machineClass)
waitForCacheSync(stop, c)
@@ -87,6 +89,7 @@ var _ = Describe("machine_util", func() {
if data.expect.node != nil {
Expect(updatedNodeObject.Spec.Taints).Should(ConsistOf(data.expect.node.Spec.Taints))
Expect(updatedNodeObject.Labels).Should(Equal(data.expect.node.Labels))
+ Expect(updatedNodeObject.Status.Capacity).Should(Equal(data.expect.node.Status.Capacity))
// ignore LastAppliedALTAnnotataion
delete(updatedNodeObject.Annotations, machineutils.LastAppliedALTAnnotation)
@@ -132,6 +135,17 @@ var _ = Describe("machine_util", func() {
},
&machinev1.MachineStatus{},
nil, nil, map[string]string{machinev1.NodeLabelKey: "test-node-0"}, true, metav1.Now()),
+ machineClass: &machinev1.MachineClass{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-machine-class",
+ },
+ NodeTemplate: &machinev1.NodeTemplate{
+ VirtualCapacity: corev1.ResourceList{
+ "virtual.com/dongle": resource.MustParse("2"),
+ },
+ },
+ },
},
action: action{
node: &corev1.Node{
@@ -170,6 +184,7 @@ var _ = Describe("machine_util", func() {
Namespace: testNamespace,
Annotations: map[string]string{
"anno1": "anno1",
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"virtual.com/dongle\":\"2\"}",
},
Labels: map[string]string{
"key1": "value1",
@@ -184,6 +199,11 @@ var _ = Describe("machine_util", func() {
},
},
},
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ "virtual.com/dongle": resource.MustParse("2"),
+ },
+ },
},
err: errSuccessfulALTsync,
},
@@ -1842,6 +1862,243 @@ var _ = Describe("machine_util", func() {
)
})
+ Describe("#SyncVirtualCapacity", func() {
+ type action struct {
+ node *corev1.Node
+ desiredVirtualCapacity corev1.ResourceList
+ }
+ type expect struct {
+ node *corev1.Node
+ virtualCapacityChanged bool
+ }
+ type data struct {
+ action action
+ expect expect
+ }
+
+ DescribeTable("##table",
+ func(data *data) error {
+ testNode := data.action.node.DeepCopy()
+ desiredVirtualCapacity := data.action.desiredVirtualCapacity
+ expectedNode := data.expect.node
+
+ var lastAppliedVirtualCapacity corev1.ResourceList
+ lastAppliedVirtualCapacityJSONString, exists := testNode.Annotations[machineutils.LastAppliedVirtualCapacityAnnotation]
+ if exists {
+ err := json.Unmarshal([]byte(lastAppliedVirtualCapacityJSONString), &lastAppliedVirtualCapacity)
+ if err != nil {
+ return fmt.Errorf("cannot unmarshall %q annotation: %w", machineutils.LastAppliedVirtualCapacityAnnotation, err)
+ }
+ }
+
+ virtualCapacityChanged := SyncVirtualCapacity(desiredVirtualCapacity, testNode, lastAppliedVirtualCapacity)
+
+ Expect(virtualCapacityChanged).To(Equal(data.expect.virtualCapacityChanged))
+ Expect(testNode.Status.Capacity).Should(Equal(expectedNode.Status.Capacity))
+
+ lastAppliedVirtualCapacityJSONString = expectedNode.Annotations[machineutils.LastAppliedVirtualCapacityAnnotation]
+ lastAppliedVirtualCapacity = corev1.ResourceList{}
+ err := json.Unmarshal([]byte(lastAppliedVirtualCapacityJSONString), &lastAppliedVirtualCapacity)
+ if err != nil {
+ return fmt.Errorf("cannot unmarshall %q annotation with value %q: %w", machineutils.LastAppliedVirtualCapacityAnnotation, lastAppliedVirtualCapacityJSONString, err)
+ }
+ Expect(lastAppliedVirtualCapacity).To(Equal(desiredVirtualCapacity))
+ return nil
+ },
+
+ Entry("when node.status.capacity has not been changed", &data{
+ action: action{
+ desiredVirtualCapacity: corev1.ResourceList{
+ "hc.hana.com/memory": resource.MustParse("1234567"),
+ },
+ node: &corev1.Node{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Node",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-node-0",
+ Annotations: map[string]string{
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"hc.hana.com/memory\":\"1234567\"}",
+ },
+ },
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("1234567"),
+ "hc.hana.com/memory": resource.MustParse("1234567"),
+ },
+ },
+ },
+ },
+ expect: expect{
+ node: &corev1.Node{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Node",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-node-0",
+ Annotations: map[string]string{
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"hc.hana.com/memory\":\"1234567\"}",
+ },
+ },
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("1234567"),
+ "hc.hana.com/memory": resource.MustParse("1234567"),
+ },
+ },
+ },
+ virtualCapacityChanged: false,
+ },
+ }),
+
+ Entry("when virtual resource value is changed in virtualCapacity", &data{
+ action: action{
+ desiredVirtualCapacity: corev1.ResourceList{
+ "hc.hana.com/memory": resource.MustParse("2234567"),
+ },
+ node: &corev1.Node{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Node",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-node-0",
+ Annotations: map[string]string{
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"hc.hana.com/memory\":\"1234567\"}",
+ },
+ },
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("1234567"),
+ "hc.hana.com/memory": resource.MustParse("1234567"),
+ },
+ },
+ },
+ },
+ expect: expect{
+ node: &corev1.Node{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Node",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-node-0",
+ Annotations: map[string]string{
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"hc.hana.com/memory\":\"2234567\"}",
+ },
+ },
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("1234567"),
+ "hc.hana.com/memory": resource.MustParse("2234567"),
+ },
+ },
+ },
+ virtualCapacityChanged: true,
+ },
+ }),
+
+ Entry("when virtual resources are added in virtualCapacity", &data{
+ action: action{
+ desiredVirtualCapacity: corev1.ResourceList{
+ "hc.hana.com/memory": resource.MustParse("1111111"),
+ "hc.hana.com/cpu": resource.MustParse("2"),
+ },
+ node: &corev1.Node{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Node",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-node-0",
+ Annotations: map[string]string{
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"hc.hana.com/memory\":\"1111111\"}",
+ },
+ },
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("1234567"),
+ "hc.hana.com/memory": resource.MustParse("1111111"),
+ },
+ },
+ },
+ },
+ expect: expect{
+ node: &corev1.Node{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Node",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-node-0",
+ Annotations: map[string]string{
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"hc.hana.com/cpu\":\"2\",\"hc.hana.com/memory\":\"1111111\"}",
+ },
+ },
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("1234567"),
+ "hc.hana.com/memory": resource.MustParse("1111111"),
+ "hc.hana.com/cpu": resource.MustParse("2"),
+ },
+ },
+ },
+ virtualCapacityChanged: true,
+ },
+ }),
+
+ Entry("when virtual resources are deleted in virtualCapacity", &data{
+ action: action{
+ desiredVirtualCapacity: corev1.ResourceList{
+ "hc.hana.com/cpu": resource.MustParse("2"),
+ },
+ node: &corev1.Node{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Node",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-node-0",
+ Annotations: map[string]string{
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"hc.hana.com/cpu\":\"2\",\"hc.hana.com/memory\":\"1111111\"}",
+ },
+ },
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("1234567"),
+ "hc.hana.com/cpu": resource.MustParse("2"),
+ "hc.hana.com/memory": resource.MustParse("1111111"),
+ },
+ },
+ },
+ },
+ expect: expect{
+ node: &corev1.Node{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "v1",
+ Kind: "Node",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-node-0",
+ Annotations: map[string]string{
+ machineutils.LastAppliedVirtualCapacityAnnotation: "{\"hc.hana.com/cpu\":\"2\"}",
+ },
+ },
+ Status: corev1.NodeStatus{
+ Capacity: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("1234567"),
+ "hc.hana.com/cpu": resource.MustParse("2"),
+ },
+ },
+ },
+ virtualCapacityChanged: true,
+ },
+ }),
+ )
+ })
+
Describe("#isMachineStatusSimilar", func() {
type setup struct {
m1, m2 machinev1.MachineStatus
diff --git a/pkg/util/provider/machinecontroller/machineclass.go b/pkg/util/provider/machinecontroller/machineclass.go
index d4a8b2392..975dfce20 100644
--- a/pkg/util/provider/machinecontroller/machineclass.go
+++ b/pkg/util/provider/machinecontroller/machineclass.go
@@ -115,6 +115,7 @@ func (c *controller) reconcileClusterMachineClass(ctx context.Context, class *v1
if class.DeletionTimestamp == nil && len(machines) > 0 {
// If deletionTimestamp is not set and at least one machine is referring this machineClass
+ var reason string
if finalizers := sets.NewString(class.Finalizers...); !finalizers.Has(MCMFinalizerName) {
// Add machineClassFinalizer as if doesn't exist
err = c.addMCMFinalizerToMachineClass(ctx, class)
@@ -124,11 +125,14 @@ func (c *controller) reconcileClusterMachineClass(ctx context.Context, class *v1
// Enqueue all machines once finalizer is added to machineClass
// This is to allow processing of such machines
- for _, machine := range machines {
- c.enqueueMachine(machine, "finalizer placed on machineClass")
- }
+ reason = "finalizer placed on machineClass"
+ } else {
+ reason = fmt.Sprintf("machine class %q was updated", class.Name)
}
+ for _, m := range machines {
+ c.enqueueMachine(m, reason)
+ }
return nil
}
diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go
index dd9dae817..5389aa96a 100644
--- a/pkg/util/provider/machineutils/utils.go
+++ b/pkg/util/provider/machineutils/utils.go
@@ -41,6 +41,9 @@ const (
// LastAppliedALTAnnotation contains the last configuration of annotations, labels & taints applied on the node object
LastAppliedALTAnnotation = "node.machine.sapcloud.io/last-applied-anno-labels-taints"
+ // LastAppliedVirtualCapacityAnnotation contains the last configuration of MachineClass.NodeTemplate.VirtualCapacity applied on the node object
+ LastAppliedVirtualCapacityAnnotation = "node.machine.sapcloud.io/last-applied-virtual-capacity"
+
// MachinePriority is the annotation used to specify priority
// associated with a machine while deleting it. The less its
// priority the more likely it is to be deleted first
|