-
Notifications
You must be signed in to change notification settings - Fork 39.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] feat: add limited resource for critical pod in all namespaces - part1 #82575
Changes from all commits
fed5994
742e831
df0d36d
98e49db
2a3d0f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,8 @@ type Plugin struct { | |
*admission.Handler | ||
client kubernetes.Interface | ||
lister schedulingv1listers.PriorityClassLister | ||
// We are initializing them here because of performance impact of checking featuregates. | ||
resourceQuotaFeatureGateEnabled bool | ||
} | ||
|
||
var _ admission.MutationInterface = &Plugin{} | ||
|
@@ -66,7 +68,8 @@ var _ = genericadmissioninitializers.WantsExternalKubeClientSet(&Plugin{}) | |
// NewPlugin creates a new priority admission plugin. | ||
func NewPlugin() *Plugin { | ||
return &Plugin{ | ||
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), | ||
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), | ||
resourceQuotaFeatureGateEnabled: utilfeature.DefaultFeatureGate.Enabled(features.ResourceQuotaScopeSelectors), | ||
} | ||
} | ||
|
||
|
@@ -177,19 +180,27 @@ func (p *Plugin) admitPod(a admission.Attributes) error { | |
} | ||
|
||
if operation == admission.Create { | ||
var priority int32 | ||
var preemptionPolicy *apiv1.PreemptionPolicy | ||
var ( | ||
priority int32 | ||
preemptionPolicy *apiv1.PreemptionPolicy | ||
) | ||
if len(pod.Spec.PriorityClassName) == 0 { | ||
var err error | ||
var pcName string | ||
var ( | ||
err error | ||
pcName string | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ugly |
||
|
||
pcName, priority, preemptionPolicy, err = p.getDefaultPriority() | ||
if err != nil { | ||
return fmt.Errorf("failed to get default priority class: %v", err) | ||
} | ||
|
||
pod.Spec.PriorityClassName = pcName | ||
} else { | ||
pcName := pod.Spec.PriorityClassName | ||
if !priorityClassPermittedInNamespace(pcName, a.GetNamespace()) { | ||
// If ResourceQuotaScopeSelectors is enabled, we should let pods with critical priorityClass to be created | ||
// any namespace where administrator wants it to be created. | ||
if !p.resourceQuotaFeatureGateEnabled && !priorityClassPermittedInNamespace(pcName, a.GetNamespace()) { | ||
return admission.NewForbidden(a, fmt.Errorf("pods with %v priorityClass is not permitted in %v namespace", pcName, a.GetNamespace())) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -626,7 +626,7 @@ func TestPodAdmission(t *testing.T) { | |
[]*scheduling.PriorityClass{systemClusterCritical}, | ||
*pods[7], | ||
scheduling.SystemCriticalPriority, | ||
true, | ||
false, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why this? |
||
nil, | ||
}, | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,11 +21,11 @@ import ( | |
"io" | ||
"io/ioutil" | ||
|
||
v1 "k8s.io/api/core/v1" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. corev1 |
||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/runtime/serializer" | ||
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota" | ||
"k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install" | ||
resourcequotav1beta1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1beta1" | ||
) | ||
|
||
var ( | ||
|
@@ -37,19 +37,38 @@ func init() { | |
install.Install(scheme) | ||
} | ||
|
||
// AddCriticalPodLimitedResources limits the number of critical pods that can be created. We're creating a default | ||
// resource quota in `kube-system` namespace to allow unlimited number of critical pods to be created in that | ||
// namespace. Making this function public for easy testing | ||
func AddCriticalPodLimitedResources() []resourcequotaapi.LimitedResource { | ||
return []resourcequotaapi.LimitedResource{ | ||
{ | ||
Resource: "pods", | ||
MatchScopes: []v1.ScopedResourceSelectorRequirement{ | ||
{ | ||
ScopeName: v1.ResourceQuotaScopePriorityClass, | ||
Operator: v1.ScopeSelectorOpIn, | ||
Values: []string{"system-cluster-critical", "system-node-critical"}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// LoadConfiguration loads the provided configuration. | ||
func LoadConfiguration(config io.Reader) (*resourcequotaapi.Configuration, error) { | ||
// if no config is provided, return a default configuration | ||
// if no config is provided, return a default configuration with critical pods as limited resources | ||
if config == nil { | ||
externalConfig := &resourcequotav1beta1.Configuration{} | ||
scheme.Default(externalConfig) | ||
internalConfig := &resourcequotaapi.Configuration{} | ||
if err := scheme.Convert(externalConfig, internalConfig, nil); err != nil { | ||
return nil, err | ||
} | ||
return internalConfig, nil | ||
config := &resourcequotaapi.Configuration{} | ||
scheme.Default(config) | ||
// append pods as limited resources so that we can limit the number of critical pods to be created. We have | ||
// a matching default quota in `kube-system` namespace which allows unlimited pods to be created in that | ||
// namespace | ||
config.LimitedResources = append(config.LimitedResources, AddCriticalPodLimitedResources()...) | ||
return config, nil | ||
} | ||
// we have a config so parse it. | ||
|
||
// we have a config so parse it and limit the critical pods that can be created | ||
data, err := ioutil.ReadAll(config) | ||
if err != nil { | ||
return nil, err | ||
|
@@ -63,5 +82,8 @@ func LoadConfiguration(config io.Reader) (*resourcequotaapi.Configuration, error | |
if !ok { | ||
return nil, fmt.Errorf("unexpected type: %T", decodedObj) | ||
} | ||
// append pods as limited resources so that we can limit the number of critical pods to be created. We have | ||
// a matching default quota in `kube-system` namespace which allows unlimited pods to be created in that namespace | ||
resourceQuotaConfiguration.LimitedResources = append(resourceQuotaConfiguration.LimitedResources, AddCriticalPodLimitedResources()...) | ||
return resourceQuotaConfiguration, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,8 +92,9 @@ func TestGracefulShutdown(t *testing.T) { | |
} | ||
body.Close() | ||
respErr := <-respErrCh | ||
if err != nil { | ||
t.Fatal(err) | ||
t.Logf("respErr %v", respErr) | ||
if respErr.err != nil { | ||
t.Fatal(respErr.err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you move this into a separate PR? It was obviously wrong. |
||
} | ||
defer respErr.resp.Body.Close() | ||
bs, err := ioutil.ReadAll(respErr.resp.Body) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugly