Skip to content

Commit 7b9cb8c

Browse files
authored
Merge pull request #8508 from abdelrahman882/capacitybuffer
Add capacity buffer CRD
2 parents b7115db + 509aa6b commit 7b9cb8c

File tree

33 files changed

+2760
-0
lines changed

33 files changed

+2760
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
Copyright 2025 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+
// +k8s:deepcopy-gen=package
18+
// +groupName=autoscaling.x-k8s.io
19+
// +k8s:openapi-gen=true
20+
// +k8s:protobuf-gen=package
21+
// +k8s:prerelease-lifecycle-gen=true
22+
// +kubebuilder:object:generate=true
23+
24+
package v1
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
Copyright 2025 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 v1
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/apimachinery/pkg/runtime"
22+
"k8s.io/apimachinery/pkg/runtime/schema"
23+
)
24+
25+
// SchemeGroupVersion is group version used to register these objects
26+
var SchemeGroupVersion = schema.GroupVersion{Group: "autoscaling.x-k8s.io", Version: "v1"}
27+
28+
// Resource takes an unqualified resource and returns a Group qualified GroupResource
29+
func Resource(resource string) schema.GroupResource {
30+
return SchemeGroupVersion.WithResource(resource).GroupResource()
31+
}
32+
33+
var (
34+
// SchemeBuilder points to a list of functions added to Scheme.
35+
SchemeBuilder runtime.SchemeBuilder
36+
localSchemeBuilder = &SchemeBuilder
37+
// AddToScheme applies all the stored functions to the scheme.
38+
AddToScheme = localSchemeBuilder.AddToScheme
39+
)
40+
41+
func init() {
42+
// We only register manually written functions here. The registration of the
43+
// generated functions takes place in the generated files. The separation
44+
// makes the code compile even when the generated files are missing.
45+
localSchemeBuilder.Register(addKnownTypes)
46+
}
47+
48+
// Adds the list of known types to api.Scheme.
49+
func addKnownTypes(scheme *runtime.Scheme) error {
50+
scheme.AddKnownTypes(SchemeGroupVersion,
51+
&CapacityBuffer{},
52+
&CapacityBufferList{},
53+
)
54+
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
55+
return nil
56+
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
Copyright 2025 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+
// +k8s:deepcopy-gen=package
18+
// +groupName=autoscaling.x-k8s.io
19+
// +k8s:protobuf-gen=package
20+
21+
// Package v1 contains the v1 API for the autoscaling.x-k8s.io group.
22+
// This API group defines custom resources used by the Cluster Autoscaler
23+
// for managing buffer capacity.
24+
package v1
25+
26+
import (
27+
"k8s.io/apimachinery/pkg/api/resource"
28+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+
30+
// Dependencies for the generation of the code:
31+
_ "github.com/onsi/ginkgo/v2"
32+
_ "github.com/onsi/gomega"
33+
_ "k8s.io/code-generator"
34+
)
35+
36+
// +genclient
37+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
38+
// +kubebuilder:object:root=true
39+
// +kubebuilder:subresource:status
40+
// +kubebuilder:resource:path=capacitybuffers,scope=Cluster,shortName=cb
41+
// +kubebuilder:printcolumn:name="Strategy",type="string",JSONPath=".spec.provisioningStrategy",description="The strategy used for provisioning buffer capacity."
42+
// +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".spec.replicas",description="The desired number of buffer chunks, if specified."
43+
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].reason",description="The readiness status of the CapacityBuffer."
44+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the CapacityBuffer."
45+
// +k8s:openapi-gen=true
46+
47+
// CapacityBuffer is the configuration that an autoscaler can use to provision buffer capacity within a cluster.
48+
// This buffer is represented by placeholder pods that trigger the Cluster Autoscaler to scale up nodes in advance,
49+
// ensuring that there is always spare capacity available to handle sudden workload spikes or to speed up scaling events.
50+
type CapacityBuffer struct {
51+
// Standard Kubernetes object metadata.
52+
metav1.TypeMeta `json:",inline"`
53+
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
54+
55+
// Spec defines the desired characteristics of the buffer.
56+
// +kubebuilder:validation:Required
57+
Spec CapacityBufferSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
58+
59+
// Status represents the current state of the buffer and its readiness for autoprovisioning.
60+
// +optional
61+
Status CapacityBufferStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
62+
}
63+
64+
// LocalObjectRef contains the name of the object being referred to.
65+
type LocalObjectRef struct {
66+
// Name of the object.
67+
// +kubebuilder:validation:Required
68+
// +kubebuilder:validation:MinLength=1
69+
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
70+
}
71+
72+
// ResourceName is the name identifying a resource mirroring k8s.io/api/core/v1.ResourceName.
73+
// +k8s:openapi-gen=true
74+
type ResourceName string
75+
76+
// ScalableRef contains name, kind and API group of an object that can be scaled.
77+
type ScalableRef struct {
78+
// APIGroup of the scalable object.
79+
// Empty string for the core API group
80+
// +optional
81+
APIGroup string `json:"apiGroup,omitempty" protobuf:"bytes,1,opt,name=apiGroup"`
82+
// Kind of the scalable object (e.g., "Deployment", "StatefulSet").
83+
// +kubebuilder:validation:Required
84+
// +kubebuilder:validation:MinLength=1
85+
Kind string `json:"kind" protobuf:"bytes,2,opt,name=kind"`
86+
// Name of the scalable object.
87+
// +kubebuilder:validation:Required
88+
// +kubebuilder:validation:MinLength=1
89+
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
90+
}
91+
92+
// ResourceList is a set of (resource name, quantity) pairs.
93+
// This is mirroring k8s.io/api/core/v1.ResourceList to avoid direct dependency.
94+
// +k8s:openapi-gen=true
95+
type ResourceList map[ResourceName]resource.Quantity
96+
97+
// CapacityBufferSpec defines the desired state of CapacityBuffer.
98+
type CapacityBufferSpec struct {
99+
// ProvisioningStrategy defines how the buffer is utilized.
100+
// "active-capacity" is the default strategy, where the buffer actively scales up the cluster by creating placeholder pods.
101+
// +kubebuilder:validation:Enum=active-capacity
102+
// +kubebuilder:default="active-capacity"
103+
// +optional
104+
ProvisioningStrategy *string `json:"provisioningStrategy,omitempty" protobuf:"bytes,1,opt,name=provisioningStrategy"`
105+
106+
// PodTemplateRef is a reference to a PodTemplate resource in the same namespace
107+
// that declares the shape of a single chunk of the buffer. The pods created
108+
// from this template will be used as placeholder pods for the buffer capacity.
109+
// Exactly one of `podTemplateRef`, `scalableRef` should be specified.
110+
// +optional
111+
// +kubebuilder:validation:Xor=podTemplateRef,scalableRef
112+
PodTemplateRef *LocalObjectRef `json:"podTemplateRef,omitempty" protobuf:"bytes,2,opt,name=podTemplateRef"`
113+
114+
// ScalableRef is a reference to an object of a kind that has a scale subresource
115+
// and specifies its label selector field. This allows the CapacityBuffer to
116+
// manage the buffer by scaling an existing scalable resource.
117+
// Exactly one of `podTemplateRef`, `scalableRef` should be specified.
118+
// +optional
119+
// +kubebuilder:validation:Xor=podTemplateRef,scalableRef
120+
ScalableRef *ScalableRef `json:"scalableRef,omitempty" protobuf:"bytes,3,opt,name=scalableRef"`
121+
122+
// Replicas defines the desired number of buffer chunks to provision.
123+
// If neither `replicas` nor `percentage` is set, as many chunks as fit within
124+
// defined resource limits (if any) will be created. If both are set, the maximum
125+
// of the two will be used.
126+
// This field is mutually exclusive with `percentage` when `scalableRef` is set.
127+
// +optional
128+
// +kubebuilder:validation:Minimum=0
129+
// +kubebuilder:validation:ExclusiveMinimum=false
130+
// +kubebuilder:validation:Xor=replicas,percentage
131+
Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,4,opt,name=replicas"`
132+
133+
// Percentage defines the desired buffer capacity as a percentage of the
134+
// `scalableRef`'s current replicas. This is only applicable if `scalableRef` is set.
135+
// The absolute number of replicas is calculated from the percentage by rounding up to a minimum of 1.
136+
// For example, if `scalableRef` has 10 replicas and `percentage` is 20, 2 buffer chunks will be created.
137+
// This field is mutually exclusive with `replicas`.
138+
// +optional
139+
// +kubebuilder:validation:Minimum=0
140+
// +kubebuilder:validation:Maximum=100
141+
// +kubebuilder:validation:ExclusiveMaximum=false
142+
// +kubebuilder:validation:ExclusiveMinimum=false
143+
// +kubebuilder:validation:Xor=replicas,percentage
144+
Percentage *int32 `json:"percentage,omitempty" protobuf:"varint,5,opt,name=percentage"`
145+
146+
// Limits, if specified, will limit the number of chunks created for this buffer
147+
// based on total resource requests (e.g., CPU, memory). If there are no other
148+
// limitations for the number of chunks (i.e., `replicas` or `percentage` are not set),
149+
// this will be used to create as many chunks as fit into these limits.
150+
// +optional
151+
Limits *ResourceList `json:"limits,omitempty" protobuf:"bytes,6,opt,name=limits"`
152+
}
153+
154+
// CapacityBufferStatus defines the observed state of CapacityBuffer.
155+
type CapacityBufferStatus struct {
156+
// PodTemplateRef is the observed reference to the PodTemplate that was used
157+
// to provision the buffer. If this field is not set, and the `conditions`
158+
// indicate an error, it provides details about the error state.
159+
// +optional
160+
PodTemplateRef *LocalObjectRef `json:"podTemplateRef,omitempty" protobuf:"bytes,1,opt,name=podTemplateRef"`
161+
162+
// Replicas is the actual number of buffer chunks currently provisioned.
163+
// +optional
164+
Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,2,opt,name=replicas"`
165+
166+
// PodTemplateGeneration is the observed generation of the PodTemplate, used
167+
// to determine if the status is up-to-date with the desired `spec.podTemplateRef`.
168+
// +optional
169+
PodTemplateGeneration *int64 `json:"podTemplateGeneration,omitempty" protobuf:"varint,3,opt,name=podTemplateGeneration"`
170+
171+
// Conditions provide a standard mechanism for reporting the buffer's state.
172+
// The "Ready" condition indicates if the buffer is successfully provisioned
173+
// and active. Other conditions may report on various aspects of the buffer's
174+
// health and provisioning process.
175+
// +optional
176+
// +patchMergeKey=type
177+
// +patchStrategy=merge
178+
// +listType=map
179+
// +listMapKey=type
180+
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,4,rep,name=conditions"`
181+
}
182+
183+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
184+
185+
// CapacityBufferList contains a list of CapacityBuffer objects.
186+
type CapacityBufferList struct {
187+
metav1.TypeMeta `json:",inline"`
188+
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
189+
Items []CapacityBuffer `json:"items" protobuf:"bytes,2,rep,name=items"`
190+
}

0 commit comments

Comments
 (0)