Skip to content

Commit cb7d68f

Browse files
authored
Merge pull request kubernetes#2918 from bskiba/admission-refactor
Separate admission controller logic for pods and vpas
2 parents b0a2870 + 479d05e commit cb7d68f

File tree

13 files changed

+143
-128
lines changed

13 files changed

+143
-128
lines changed

vertical-pod-autoscaler/pkg/admission-controller/logic/server.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import (
2424

2525
"k8s.io/api/admission/v1beta1"
2626
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource"
28+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource/pod"
29+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource/vpa"
2730
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/limitrange"
2831
metrics_admission "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/metrics/admission"
2932
"k8s.io/klog"
@@ -32,23 +35,23 @@ import (
3235
// AdmissionServer is an admission webhook server that modifies pod resources request based on VPA recommendation
3336
type AdmissionServer struct {
3437
limitsChecker limitrange.LimitRangeCalculator
35-
resourceHandlers map[metav1.GroupResource]ResourceHandler
38+
resourceHandlers map[metav1.GroupResource]resource.Handler
3639
}
3740

3841
// NewAdmissionServer constructs new AdmissionServer
39-
func NewAdmissionServer(recommendationProvider RecommendationProvider,
40-
podPreProcessor PodPreProcessor,
41-
vpaPreProcessor VpaPreProcessor,
42+
func NewAdmissionServer(recommendationProvider pod.RecommendationProvider,
43+
podPreProcessor pod.PreProcessor,
44+
vpaPreProcessor vpa.PreProcessor,
4245
limitsChecker limitrange.LimitRangeCalculator,
43-
vpaMatcher VpaMatcher) *AdmissionServer {
44-
as := &AdmissionServer{limitsChecker, map[metav1.GroupResource]ResourceHandler{}}
45-
as.RegisterResourceHandler(newPodResourceHandler(podPreProcessor, recommendationProvider, vpaMatcher))
46-
as.RegisterResourceHandler(newVpaResourceHandler(vpaPreProcessor))
46+
vpaMatcher vpa.Matcher) *AdmissionServer {
47+
as := &AdmissionServer{limitsChecker, map[metav1.GroupResource]resource.Handler{}}
48+
as.RegisterResourceHandler(pod.NewResourceHandler(podPreProcessor, recommendationProvider, vpaMatcher))
49+
as.RegisterResourceHandler(vpa.NewResourceHandler(vpaPreProcessor))
4750
return as
4851
}
4952

5053
// RegisterResourceHandler allows to register a custom logic for handling given types of resources.
51-
func (s *AdmissionServer) RegisterResourceHandler(resourceHandler ResourceHandler) {
54+
func (s *AdmissionServer) RegisterResourceHandler(resourceHandler resource.Handler) {
5255
s.resourceHandlers[resourceHandler.GroupResource()] = resourceHandler
5356
}
5457

@@ -63,7 +66,7 @@ func (s *AdmissionServer) admit(data []byte) (*v1beta1.AdmissionResponse, metric
6366
return &response, metrics_admission.Error, metrics_admission.Unknown
6467
}
6568

66-
var patches []patchRecord
69+
var patches []resource.PatchRecord
6770
var err error
6871
resource := metrics_admission.Unknown
6972

vertical-pod-autoscaler/pkg/admission-controller/main.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626

2727
"k8s.io/autoscaler/vertical-pod-autoscaler/common"
2828
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/logic"
29+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource/pod"
30+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource/vpa"
2931
vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
3032
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/target"
3133
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/limitrange"
@@ -82,16 +84,16 @@ func main() {
8284
kubeClient := kube_client.NewForConfigOrDie(config)
8385
factory := informers.NewSharedInformerFactory(kubeClient, defaultResyncPeriod)
8486
targetSelectorFetcher := target.NewVpaTargetSelectorFetcher(config, kubeClient, factory)
85-
podPreprocessor := logic.NewDefaultPodPreProcessor()
86-
vpaPreprocessor := logic.NewDefaultVpaPreProcessor()
87+
podPreprocessor := pod.NewDefaultPreProcessor()
88+
vpaPreprocessor := vpa.NewDefaultPreProcessor()
8789
var limitRangeCalculator limitrange.LimitRangeCalculator
8890
limitRangeCalculator, err = limitrange.NewLimitsRangeCalculator(factory)
8991
if err != nil {
9092
klog.Errorf("Failed to create limitRangeCalculator, falling back to not checking limits. Error message: %s", err)
9193
limitRangeCalculator = limitrange.NewNoopLimitsCalculator()
9294
}
93-
recommendationProvider := logic.NewRecommendationProvider(limitRangeCalculator, vpa_api_util.NewCappingRecommendationProcessor(limitRangeCalculator))
94-
vpaMatcher := logic.NewVpaMatcher(vpaLister, targetSelectorFetcher)
95+
recommendationProvider := pod.NewRecommendationProvider(limitRangeCalculator, vpa_api_util.NewCappingRecommendationProcessor(limitRangeCalculator))
96+
vpaMatcher := vpa.NewMatcher(vpaLister, targetSelectorFetcher)
9597

9698
hostname, err := os.Hostname()
9799
if err != nil {

vertical-pod-autoscaler/pkg/admission-controller/logic/resource_handler.go renamed to vertical-pod-autoscaler/pkg/admission-controller/resource/handler.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,29 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package logic
17+
package resource
1818

1919
import (
2020
"k8s.io/api/admission/v1beta1"
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/metrics/admission"
2323
)
2424

25-
// ResourceHandler represents a handler for a resource in Admission Server
26-
type ResourceHandler interface {
25+
// PatchRecord represents a single patch for modifying a resource.
26+
type PatchRecord struct {
27+
Op string `json:"op,inline"`
28+
Path string `json:"path,inline"`
29+
Value interface{} `json:"value"`
30+
}
31+
32+
// Handler represents a handler for a resource in Admission Server
33+
type Handler interface {
2734
// GroupResource returns Group and Resource type this handler accepts.
2835
GroupResource() metav1.GroupResource
2936
// AdmissionResource returns resource type this handler accepts.
3037
AdmissionResource() admission.AdmissionResource
3138
// DisallowIncorrectObjects returns whether incorrect objects (eg. unparsable, not passing validations) should be disallowed by Admission Server.
3239
DisallowIncorrectObjects() bool
3340
// GetPatches returns patches for given AdmissionRequest
34-
GetPatches(*v1beta1.AdmissionRequest) ([]patchRecord, error)
41+
GetPatches(*v1beta1.AdmissionRequest) ([]PatchRecord, error)
3542
}

vertical-pod-autoscaler/pkg/admission-controller/logic/pod_resource_handler.go renamed to vertical-pod-autoscaler/pkg/admission-controller/resource/pod/handler.go

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package logic
17+
package pod
1818

1919
import (
2020
"encoding/json"
@@ -25,6 +25,8 @@ import (
2525
v1 "k8s.io/api/core/v1"
2626
"k8s.io/apimachinery/pkg/api/resource"
2727
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
resource_admission "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource"
29+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/resource/vpa"
2830
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/annotations"
2931
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/metrics/admission"
3032
vpa_api_util "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/vpa"
@@ -35,46 +37,40 @@ const (
3537
vpaAnnotationLabel = "vpaUpdates"
3638
)
3739

38-
type patchRecord struct {
39-
Op string `json:"op,inline"`
40-
Path string `json:"path,inline"`
41-
Value interface{} `json:"value"`
42-
}
43-
44-
// podResourceHandler builds patches for Pods.
45-
type podResourceHandler struct {
46-
podPreProcessor PodPreProcessor
40+
// resourceHandler builds patches for Pods.
41+
type resourceHandler struct {
42+
preProcessor PreProcessor
4743
recommendationProvider RecommendationProvider
48-
vpaMatcher VpaMatcher
44+
vpaMatcher vpa.Matcher
4945
}
5046

51-
// newPodResourceHandler creates new instance of podResourceHandler.
52-
func newPodResourceHandler(podPreProcessor PodPreProcessor, recommendationProvider RecommendationProvider, vpaMatcher VpaMatcher) ResourceHandler {
53-
return &podResourceHandler{
54-
podPreProcessor: podPreProcessor,
47+
// NewResourceHandler creates new instance of resourceHandler.
48+
func NewResourceHandler(preProcessor PreProcessor, recommendationProvider RecommendationProvider, vpaMatcher vpa.Matcher) resource_admission.Handler {
49+
return &resourceHandler{
50+
preProcessor: preProcessor,
5551
recommendationProvider: recommendationProvider,
5652
vpaMatcher: vpaMatcher,
5753
}
5854
}
5955

6056
// AdmissionResource returns resource type this handler accepts.
61-
func (h *podResourceHandler) AdmissionResource() admission.AdmissionResource {
57+
func (h *resourceHandler) AdmissionResource() admission.AdmissionResource {
6258
return admission.Pod
6359
}
6460

6561
// GroupResource returns Group and Resource type this handler accepts.
66-
func (h *podResourceHandler) GroupResource() metav1.GroupResource {
62+
func (h *resourceHandler) GroupResource() metav1.GroupResource {
6763
return metav1.GroupResource{Group: "", Resource: "pods"}
6864
}
6965

7066
// DisallowIncorrectObjects decides whether incorrect objects (eg. unparsable, not passing validations) should be disallowed by Admission Server.
71-
func (h *podResourceHandler) DisallowIncorrectObjects() bool {
67+
func (h *resourceHandler) DisallowIncorrectObjects() bool {
7268
// Incorrect Pods are validated by API Server.
7369
return false
7470
}
7571

7672
// GetPatches builds patches for Pod in given admission request.
77-
func (h *podResourceHandler) GetPatches(ar *v1beta1.AdmissionRequest) ([]patchRecord, error) {
73+
func (h *resourceHandler) GetPatches(ar *v1beta1.AdmissionRequest) ([]resource_admission.PatchRecord, error) {
7874
if ar.Resource.Version != "v1" {
7975
return nil, fmt.Errorf("only v1 Pods are supported")
8076
}
@@ -91,21 +87,21 @@ func (h *podResourceHandler) GetPatches(ar *v1beta1.AdmissionRequest) ([]patchRe
9187
controllingVpa := h.vpaMatcher.GetMatchingVPA(&pod)
9288
if controllingVpa == nil {
9389
klog.V(4).Infof("No matching VPA found for pod %s/%s", pod.Namespace, pod.Name)
94-
return []patchRecord{}, nil
90+
return []resource_admission.PatchRecord{}, nil
9591
}
9692
containersResources, annotationsPerContainer, err := h.recommendationProvider.GetContainersResourcesForPod(&pod, controllingVpa)
9793
if err != nil {
9894
return nil, err
9995
}
100-
pod, err = h.podPreProcessor.Process(pod)
96+
pod, err = h.preProcessor.Process(pod)
10197
if err != nil {
10298
return nil, err
10399
}
104100
if annotationsPerContainer == nil {
105101
annotationsPerContainer = vpa_api_util.ContainerToAnnotationsMap{}
106102
}
107103

108-
patches := []patchRecord{}
104+
patches := []resource_admission.PatchRecord{}
109105
updatesAnnotation := []string{}
110106
for i, containerResources := range containersResources {
111107
newPatches, newUpdatesAnnotation := getContainerPatch(pod, i, annotationsPerContainer, containerResources)
@@ -126,8 +122,8 @@ func (h *podResourceHandler) GetPatches(ar *v1beta1.AdmissionRequest) ([]patchRe
126122
return patches, nil
127123
}
128124

129-
func getContainerPatch(pod v1.Pod, i int, annotationsPerContainer vpa_api_util.ContainerToAnnotationsMap, containerResources vpa_api_util.ContainerResources) ([]patchRecord, string) {
130-
var patches []patchRecord
125+
func getContainerPatch(pod v1.Pod, i int, annotationsPerContainer vpa_api_util.ContainerToAnnotationsMap, containerResources vpa_api_util.ContainerResources) ([]resource_admission.PatchRecord, string) {
126+
var patches []resource_admission.PatchRecord
131127
// Add empty resources object if missing.
132128
if pod.Spec.Containers[i].Resources.Limits == nil &&
133129
pod.Spec.Containers[i].Resources.Requests == nil {
@@ -146,46 +142,46 @@ func getContainerPatch(pod v1.Pod, i int, annotationsPerContainer vpa_api_util.C
146142
return patches, updatesAnnotation
147143
}
148144

149-
func getAddEmptyAnnotationsPatch() patchRecord {
150-
return patchRecord{
145+
func getAddEmptyAnnotationsPatch() resource_admission.PatchRecord {
146+
return resource_admission.PatchRecord{
151147
Op: "add",
152148
Path: "/metadata/annotations",
153149
Value: map[string]string{},
154150
}
155151
}
156152

157-
func getAddAnnotationPatch(annotationName, annotationValue string) patchRecord {
158-
return patchRecord{
153+
func getAddAnnotationPatch(annotationName, annotationValue string) resource_admission.PatchRecord {
154+
return resource_admission.PatchRecord{
159155
Op: "add",
160156
Path: fmt.Sprintf("/metadata/annotations/%s", annotationName),
161157
Value: annotationValue,
162158
}
163159
}
164160

165-
func getPatchInitializingEmptyResources(i int) patchRecord {
166-
return patchRecord{
161+
func getPatchInitializingEmptyResources(i int) resource_admission.PatchRecord {
162+
return resource_admission.PatchRecord{
167163
Op: "add",
168164
Path: fmt.Sprintf("/spec/containers/%d/resources", i),
169165
Value: v1.ResourceRequirements{},
170166
}
171167
}
172168

173-
func getPatchInitializingEmptyResourcesSubfield(i int, kind string) patchRecord {
174-
return patchRecord{
169+
func getPatchInitializingEmptyResourcesSubfield(i int, kind string) resource_admission.PatchRecord {
170+
return resource_admission.PatchRecord{
175171
Op: "add",
176172
Path: fmt.Sprintf("/spec/containers/%d/resources/%s", i, kind),
177173
Value: v1.ResourceList{},
178174
}
179175
}
180176

181-
func getAddResourceRequirementValuePatch(i int, kind string, resource v1.ResourceName, quantity resource.Quantity) patchRecord {
182-
return patchRecord{
177+
func getAddResourceRequirementValuePatch(i int, kind string, resource v1.ResourceName, quantity resource.Quantity) resource_admission.PatchRecord {
178+
return resource_admission.PatchRecord{
183179
Op: "add",
184180
Path: fmt.Sprintf("/spec/containers/%d/resources/%s/%s", i, kind, resource),
185181
Value: quantity.String()}
186182
}
187183

188-
func appendPatchesAndAnnotations(patches []patchRecord, annotations []string, current v1.ResourceList, containerIndex int, resources v1.ResourceList, fieldName, resourceName string) ([]patchRecord, []string) {
184+
func appendPatchesAndAnnotations(patches []resource_admission.PatchRecord, annotations []string, current v1.ResourceList, containerIndex int, resources v1.ResourceList, fieldName, resourceName string) ([]resource_admission.PatchRecord, []string) {
189185
// Add empty object if it's missing and we're about to fill it.
190186
if current == nil && len(resources) > 0 {
191187
patches = append(patches, getPatchInitializingEmptyResourcesSubfield(containerIndex, fieldName))

0 commit comments

Comments
 (0)