Skip to content

Commit d366f40

Browse files
authored
Add scale from and to 0 support for autoscaler (#860)
1 parent 61bfad5 commit d366f40

12 files changed

+512
-14
lines changed

api/v1alpha4/ibmpowervs_conversion.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,8 @@ func Convert_v1beta1_IBMPowerVSMachineSpec_To_v1alpha4_IBMPowerVSMachineSpec(in
159159
func Convert_v1alpha4_IBMPowerVSMachineSpec_To_v1beta1_IBMPowerVSMachineSpec(in *IBMPowerVSMachineSpec, out *infrav1beta1.IBMPowerVSMachineSpec, s apiconversion.Scope) error {
160160
return autoConvert_v1alpha4_IBMPowerVSMachineSpec_To_v1beta1_IBMPowerVSMachineSpec(in, out, s)
161161
}
162+
163+
// Convert_v1beta1_IBMPowerVSMachineTemplateStatus_To_v1alpha4_IBMPowerVSMachineTemplateStatus is an autogenerated conversion function.
164+
func Convert_v1beta1_IBMPowerVSMachineTemplateStatus_To_v1alpha4_IBMPowerVSMachineTemplateStatus(in *infrav1beta1.IBMPowerVSMachineTemplateStatus, out *IBMPowerVSMachineTemplateStatus, s apiconversion.Scope) error {
165+
return autoConvert_v1beta1_IBMPowerVSMachineTemplateStatus_To_v1alpha4_IBMPowerVSMachineTemplateStatus(in, out, s)
166+
}

api/v1alpha4/zz_generated.conversion.go

Lines changed: 6 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1beta1/ibmpowervsmachinetemplate_types.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v1beta1
1818

1919
import (
20+
corev1 "k8s.io/api/core/v1"
2021
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122
)
2223

@@ -34,10 +35,14 @@ type IBMPowerVSMachineTemplateResource struct {
3435

3536
// IBMPowerVSMachineTemplateStatus defines the observed state of IBMPowerVSMachineTemplate.
3637
type IBMPowerVSMachineTemplateStatus struct {
37-
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
38-
// Important: Run "make" to regenerate code after modifying this file
38+
// Capacity defines the resource capacity for this machine.
39+
// This value is used for autoscaling from zero operations as defined in:
40+
// https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20210310-opt-in-autoscaling-from-zero.md
41+
// +optional
42+
Capacity corev1.ResourceList `json:"capacity,omitempty"`
3943
}
4044

45+
//+kubebuilder:subresource:status
4146
//+kubebuilder:object:root=true
4247
//+kubebuilder:storageversion
4348

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsmachinetemplates.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,21 @@ spec:
221221
status:
222222
description: IBMPowerVSMachineTemplateStatus defines the observed state
223223
of IBMPowerVSMachineTemplate.
224+
properties:
225+
capacity:
226+
additionalProperties:
227+
anyOf:
228+
- type: integer
229+
- type: string
230+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
231+
x-kubernetes-int-or-string: true
232+
description: 'Capacity defines the resource capacity for this machine.
233+
This value is used for autoscaling from zero operations as defined
234+
in: https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20210310-opt-in-autoscaling-from-zero.md'
235+
type: object
224236
type: object
225237
type: object
226238
served: true
227239
storage: true
240+
subresources:
241+
status: {}

config/rbac/role.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ rules:
102102
- get
103103
- patch
104104
- update
105+
- apiGroups:
106+
- infrastructure.cluster.x-k8s.io
107+
resources:
108+
- ibmpowervsmachinetemplates
109+
verbs:
110+
- get
111+
- list
112+
- watch
113+
- apiGroups:
114+
- infrastructure.cluster.x-k8s.io
115+
resources:
116+
- ibmpowervsmachinetemplates/status
117+
verbs:
118+
- get
119+
- patch
120+
- update
105121
- apiGroups:
106122
- infrastructure.cluster.x-k8s.io
107123
resources:
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package controllers
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"math"
23+
"reflect"
24+
"strconv"
25+
26+
"github.com/go-logr/logr"
27+
28+
corev1 "k8s.io/api/core/v1"
29+
apierrors "k8s.io/apimachinery/pkg/api/errors"
30+
"k8s.io/apimachinery/pkg/api/resource"
31+
"k8s.io/apimachinery/pkg/runtime"
32+
33+
ctrl "sigs.k8s.io/controller-runtime"
34+
"sigs.k8s.io/controller-runtime/pkg/client"
35+
36+
"sigs.k8s.io/cluster-api/util/patch"
37+
38+
infrav1beta1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta1"
39+
)
40+
41+
// defaultSMT is the default value of simultaneous multithreading.
42+
const defaultSMT = 8
43+
44+
// IBMPowerVSMachineTemplateReconciler reconciles a IBMPowerVSMachineTemplate object.
45+
type IBMPowerVSMachineTemplateReconciler struct {
46+
client.Client
47+
Log logr.Logger
48+
Scheme *runtime.Scheme
49+
}
50+
51+
func (r *IBMPowerVSMachineTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error {
52+
return ctrl.NewControllerManagedBy(mgr).
53+
For(&infrav1beta1.IBMPowerVSMachineTemplate{}).
54+
Complete(r)
55+
}
56+
57+
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=ibmpowervsmachinetemplates,verbs=get;list;watch
58+
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=ibmpowervsmachinetemplates/status,verbs=get;update;patch
59+
60+
func (r *IBMPowerVSMachineTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
61+
logger := r.Log.WithValues("ibmpowervsmachinetemplate", req.NamespacedName)
62+
63+
var machineTemplate infrav1beta1.IBMPowerVSMachineTemplate
64+
if err := r.Get(ctx, req.NamespacedName, &machineTemplate); err != nil {
65+
logger.Error(err, "unable to fetch ibmpowervsmachinetemplate")
66+
return ctrl.Result{}, client.IgnoreNotFound(err)
67+
}
68+
69+
helper, err := patch.NewHelper(&machineTemplate, r.Client)
70+
if err != nil {
71+
return ctrl.Result{}, fmt.Errorf("failed to init patch helper: %w", err)
72+
}
73+
74+
capacity, err := getIBMPowerVSMachineCapacity(machineTemplate)
75+
if err != nil {
76+
logger.Error(err, "failed to get capacity from the ibmpowervsmachine template")
77+
return ctrl.Result{}, fmt.Errorf("failed to get capcity for machine template: %w", err)
78+
}
79+
logger.V(3).Info("calculated capacity for machine template", "capacity", capacity)
80+
if !reflect.DeepEqual(machineTemplate.Status.Capacity, capacity) {
81+
machineTemplate.Status.Capacity = capacity
82+
if err := helper.Patch(ctx, &machineTemplate); err != nil {
83+
if !apierrors.IsNotFound(err) {
84+
logger.Error(err, "failed to patch machineTemplate")
85+
return ctrl.Result{}, err
86+
}
87+
}
88+
}
89+
logger.V(3).Info("machine template status", "status", machineTemplate.Status.Capacity)
90+
return ctrl.Result{}, nil
91+
}
92+
93+
func getIBMPowerVSMachineCapacity(machineTemplate infrav1beta1.IBMPowerVSMachineTemplate) (corev1.ResourceList, error) {
94+
capacity := make(corev1.ResourceList)
95+
capacity[corev1.ResourceMemory] = resource.MustParse(fmt.Sprintf("%sG", machineTemplate.Spec.Template.Spec.Memory))
96+
// There is a core-to-lCPU ratio of 1:1 for Dedicated processors. For shared processors, fractional cores round up to the nearest whole number. For example, 1.25 cores equals 2 lCPUs.
97+
// VM with 1 dedicated processor will see = 1 * SMT = 1 * 8 = 8 cpus in OS
98+
// VM with 1.5 shared processor will see = 2 * SMT = 2 * 8 = 16 cpus in OS
99+
// Here SMT: simultaneous multithreading which is default to 8
100+
// Here lCPU: number of online logical processors
101+
// example: on a Power VS machine with 0.5 cores
102+
// $ lparstat
103+
// System Configuration
104+
// type=Shared mode=Uncapped smt=8 lcpu=1 mem=33413760 kB cpus=20 ent=0.50
105+
cores, err := strconv.ParseFloat(machineTemplate.Spec.Template.Spec.Processors, 64)
106+
if err != nil {
107+
return nil, err
108+
}
109+
virtualProcessors := fmt.Sprintf("%v", math.Ceil(cores)*defaultSMT)
110+
capacity[corev1.ResourceCPU] = resource.MustParse(virtualProcessors)
111+
return capacity, nil
112+
}

0 commit comments

Comments
 (0)