Commit c86b84cc authored by Matt Liggett's avatar Matt Liggett

Add /eviction subresource.

This is for #12611.
parent a6d37f7e
...@@ -50,6 +50,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { ...@@ -50,6 +50,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&PodDisruptionBudget{}, &PodDisruptionBudget{},
&PodDisruptionBudgetList{}, &PodDisruptionBudgetList{},
&api.ListOptions{}, &api.ListOptions{},
&Eviction{},
) )
return nil return nil
} }
...@@ -69,3 +69,16 @@ type PodDisruptionBudgetList struct { ...@@ -69,3 +69,16 @@ type PodDisruptionBudgetList struct {
unversioned.ListMeta `json:"metadata,omitempty"` unversioned.ListMeta `json:"metadata,omitempty"`
Items []PodDisruptionBudget `json:"items"` Items []PodDisruptionBudget `json:"items"`
} }
// Eviction evicts a pod from its node subject to certain policies and safety constraints.
// This is a subresource of Pod. A request to cause such an eviction is
// created by POSTing to .../pods/foo/evictions.
type Eviction struct {
unversioned.TypeMeta `json:",inline"`
// ObjectMeta describes the pod that is being evicted.
api.ObjectMeta `json:"metadata,omitempty"`
// DeleteOptions may be provided
DeleteOptions *api.DeleteOptions `json:"deleteOptions,omitempty"`
}
...@@ -30,6 +30,17 @@ import "k8s.io/kubernetes/pkg/util/intstr/generated.proto"; ...@@ -30,6 +30,17 @@ import "k8s.io/kubernetes/pkg/util/intstr/generated.proto";
// Package-wide variables from generator "generated". // Package-wide variables from generator "generated".
option go_package = "v1alpha1"; option go_package = "v1alpha1";
// Eviction evicts a pod from its node subject to certain policies and safety constraints.
// This is a subresource of Pod. A request to cause such an eviction is
// created by POSTing to .../pods/foo/evictions.
message Eviction {
// ObjectMeta describes the pod that is being evicted.
optional k8s.io.kubernetes.pkg.api.v1.ObjectMeta metadata = 1;
// DeleteOptions may be provided
optional k8s.io.kubernetes.pkg.api.v1.DeleteOptions deleteOptions = 2;
}
// PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods // PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods
message PodDisruptionBudget { message PodDisruptionBudget {
optional k8s.io.kubernetes.pkg.api.v1.ObjectMeta metadata = 1; optional k8s.io.kubernetes.pkg.api.v1.ObjectMeta metadata = 1;
......
...@@ -39,6 +39,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { ...@@ -39,6 +39,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion, scheme.AddKnownTypes(SchemeGroupVersion,
&PodDisruptionBudget{}, &PodDisruptionBudget{},
&PodDisruptionBudgetList{}, &PodDisruptionBudgetList{},
&Eviction{},
&v1.ListOptions{}, &v1.ListOptions{},
&v1.DeleteOptions{}, &v1.DeleteOptions{},
) )
......
...@@ -18,7 +18,6 @@ package v1alpha1 ...@@ -18,7 +18,6 @@ package v1alpha1
import ( import (
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
) )
...@@ -70,3 +69,16 @@ type PodDisruptionBudgetList struct { ...@@ -70,3 +69,16 @@ type PodDisruptionBudgetList struct {
unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []PodDisruptionBudget `json:"items" protobuf:"bytes,2,rep,name=items"` Items []PodDisruptionBudget `json:"items" protobuf:"bytes,2,rep,name=items"`
} }
// Eviction evicts a pod from its node subject to certain policies and safety constraints.
// This is a subresource of Pod. A request to cause such an eviction is
// created by POSTing to .../pods/foo/evictions.
type Eviction struct {
unversioned.TypeMeta `json:",inline"`
// ObjectMeta describes the pod that is being evicted.
v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// DeleteOptions may be provided
DeleteOptions *v1.DeleteOptions `json:"deleteOptions,omitempty" protobuf:"bytes,2,opt,name=deleteOptions"`
}
...@@ -22,6 +22,7 @@ package v1alpha1 ...@@ -22,6 +22,7 @@ package v1alpha1
import ( import (
api "k8s.io/kubernetes/pkg/api" api "k8s.io/kubernetes/pkg/api"
v1 "k8s.io/kubernetes/pkg/api/v1"
policy "k8s.io/kubernetes/pkg/apis/policy" policy "k8s.io/kubernetes/pkg/apis/policy"
conversion "k8s.io/kubernetes/pkg/conversion" conversion "k8s.io/kubernetes/pkg/conversion"
runtime "k8s.io/kubernetes/pkg/runtime" runtime "k8s.io/kubernetes/pkg/runtime"
...@@ -35,6 +36,8 @@ func init() { ...@@ -35,6 +36,8 @@ func init() {
// Public to allow building arbitrary schemes. // Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error { func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs( return scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_Eviction_To_policy_Eviction,
Convert_policy_Eviction_To_v1alpha1_Eviction,
Convert_v1alpha1_PodDisruptionBudget_To_policy_PodDisruptionBudget, Convert_v1alpha1_PodDisruptionBudget_To_policy_PodDisruptionBudget,
Convert_policy_PodDisruptionBudget_To_v1alpha1_PodDisruptionBudget, Convert_policy_PodDisruptionBudget_To_v1alpha1_PodDisruptionBudget,
Convert_v1alpha1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList, Convert_v1alpha1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList,
...@@ -46,6 +49,56 @@ func RegisterConversions(scheme *runtime.Scheme) error { ...@@ -46,6 +49,56 @@ func RegisterConversions(scheme *runtime.Scheme) error {
) )
} }
func autoConvert_v1alpha1_Eviction_To_policy_Eviction(in *Eviction, out *policy.Eviction, s conversion.Scope) error {
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if in.DeleteOptions != nil {
in, out := &in.DeleteOptions, &out.DeleteOptions
*out = new(api.DeleteOptions)
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(*in, *out, 0); err != nil {
return err
}
} else {
out.DeleteOptions = nil
}
return nil
}
func Convert_v1alpha1_Eviction_To_policy_Eviction(in *Eviction, out *policy.Eviction, s conversion.Scope) error {
return autoConvert_v1alpha1_Eviction_To_policy_Eviction(in, out, s)
}
func autoConvert_policy_Eviction_To_v1alpha1_Eviction(in *policy.Eviction, out *Eviction, s conversion.Scope) error {
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if in.DeleteOptions != nil {
in, out := &in.DeleteOptions, &out.DeleteOptions
*out = new(v1.DeleteOptions)
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(*in, *out, 0); err != nil {
return err
}
} else {
out.DeleteOptions = nil
}
return nil
}
func Convert_policy_Eviction_To_v1alpha1_Eviction(in *policy.Eviction, out *Eviction, s conversion.Scope) error {
return autoConvert_policy_Eviction_To_v1alpha1_Eviction(in, out, s)
}
func autoConvert_v1alpha1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in *PodDisruptionBudget, out *policy.PodDisruptionBudget, s conversion.Scope) error { func autoConvert_v1alpha1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in *PodDisruptionBudget, out *policy.PodDisruptionBudget, s conversion.Scope) error {
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil { if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err return err
......
...@@ -36,6 +36,7 @@ func init() { ...@@ -36,6 +36,7 @@ func init() {
// to allow building arbitrary schemes. // to allow building arbitrary schemes.
func RegisterDeepCopies(scheme *runtime.Scheme) error { func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs( return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_Eviction, InType: reflect.TypeOf(&Eviction{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_PodDisruptionBudget, InType: reflect.TypeOf(&PodDisruptionBudget{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_PodDisruptionBudget, InType: reflect.TypeOf(&PodDisruptionBudget{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_PodDisruptionBudgetList, InType: reflect.TypeOf(&PodDisruptionBudgetList{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_PodDisruptionBudgetList, InType: reflect.TypeOf(&PodDisruptionBudgetList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_PodDisruptionBudgetSpec, InType: reflect.TypeOf(&PodDisruptionBudgetSpec{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_PodDisruptionBudgetSpec, InType: reflect.TypeOf(&PodDisruptionBudgetSpec{})},
...@@ -43,6 +44,27 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error { ...@@ -43,6 +44,27 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
) )
} }
func DeepCopy_v1alpha1_Eviction(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*Eviction)
out := out.(*Eviction)
out.TypeMeta = in.TypeMeta
if err := v1.DeepCopy_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
if in.DeleteOptions != nil {
in, out := &in.DeleteOptions, &out.DeleteOptions
*out = new(v1.DeleteOptions)
if err := v1.DeepCopy_v1_DeleteOptions(*in, *out, c); err != nil {
return err
}
} else {
out.DeleteOptions = nil
}
return nil
}
}
func DeepCopy_v1alpha1_PodDisruptionBudget(in interface{}, out interface{}, c *conversion.Cloner) error { func DeepCopy_v1alpha1_PodDisruptionBudget(in interface{}, out interface{}, c *conversion.Cloner) error {
{ {
in := in.(*PodDisruptionBudget) in := in.(*PodDisruptionBudget)
......
...@@ -36,6 +36,7 @@ func init() { ...@@ -36,6 +36,7 @@ func init() {
// to allow building arbitrary schemes. // to allow building arbitrary schemes.
func RegisterDeepCopies(scheme *runtime.Scheme) error { func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs( return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_policy_Eviction, InType: reflect.TypeOf(&Eviction{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_policy_PodDisruptionBudget, InType: reflect.TypeOf(&PodDisruptionBudget{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_policy_PodDisruptionBudget, InType: reflect.TypeOf(&PodDisruptionBudget{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_policy_PodDisruptionBudgetList, InType: reflect.TypeOf(&PodDisruptionBudgetList{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_policy_PodDisruptionBudgetList, InType: reflect.TypeOf(&PodDisruptionBudgetList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_policy_PodDisruptionBudgetSpec, InType: reflect.TypeOf(&PodDisruptionBudgetSpec{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_policy_PodDisruptionBudgetSpec, InType: reflect.TypeOf(&PodDisruptionBudgetSpec{})},
...@@ -43,6 +44,27 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error { ...@@ -43,6 +44,27 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
) )
} }
func DeepCopy_policy_Eviction(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*Eviction)
out := out.(*Eviction)
out.TypeMeta = in.TypeMeta
if err := api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
if in.DeleteOptions != nil {
in, out := &in.DeleteOptions, &out.DeleteOptions
*out = new(api.DeleteOptions)
if err := api.DeepCopy_api_DeleteOptions(*in, *out, c); err != nil {
return err
}
} else {
out.DeleteOptions = nil
}
return nil
}
}
func DeepCopy_policy_PodDisruptionBudget(in interface{}, out interface{}, c *conversion.Cloner) error { func DeepCopy_policy_PodDisruptionBudget(in interface{}, out interface{}, c *conversion.Cloner) error {
{ {
in := in.(*PodDisruptionBudget) in := in.(*PodDisruptionBudget)
......
...@@ -242,15 +242,17 @@ func (m *Master) InstallAPIs(c *Config) { ...@@ -242,15 +242,17 @@ func (m *Master) InstallAPIs(c *Config) {
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
"v1": m.v1ResourcesStorage, "v1": m.v1ResourcesStorage,
}, },
IsLegacyGroup: true, IsLegacyGroup: true,
Scheme: api.Scheme, Scheme: api.Scheme,
ParameterCodec: api.ParameterCodec, ParameterCodec: api.ParameterCodec,
NegotiatedSerializer: api.Codecs, NegotiatedSerializer: api.Codecs,
SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{},
} }
if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) {
apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{ apiGroupInfo.SubresourceGroupVersionKind["replicationcontrollers/scale"] = autoscalingGroupVersion.WithKind("Scale")
"replicationcontrollers/scale": autoscalingGroupVersion.WithKind("Scale"), }
} if policyGroupVersion := (unversioned.GroupVersion{Group: "policy", Version: "v1alpha1"}); registered.IsEnabledVersion(policyGroupVersion) {
apiGroupInfo.SubresourceGroupVersionKind["pods/eviction"] = policyGroupVersion.WithKind("Eviction")
} }
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
} }
...@@ -300,6 +302,19 @@ func (m *Master) InstallAPIs(c *Config) { ...@@ -300,6 +302,19 @@ func (m *Master) InstallAPIs(c *Config) {
continue continue
} }
// This is here so that, if the policy group is present, the eviction
// subresource handler wil be able to find poddisruptionbudgets
// TODO(lavalamp) find a better way for groups to discover and interact
// with each other
if group == "policy" {
storage := apiGroupsInfo[0].VersionedResourcesStorageMap["v1"]["pods/eviction"]
evictionStorage := storage.(*podetcd.EvictionREST)
storage = apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"]["poddisruptionbudgets"]
evictionStorage.PodDisruptionBudgetLister = storage.(rest.Lister)
evictionStorage.PodDisruptionBudgetUpdater = storage.(rest.Updater)
}
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
} }
...@@ -426,6 +441,9 @@ func (m *Master) initV1ResourcesStorage(c *Config) { ...@@ -426,6 +441,9 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) { if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) {
m.v1ResourcesStorage["replicationControllers/scale"] = controllerStorage.Scale m.v1ResourcesStorage["replicationControllers/scale"] = controllerStorage.Scale
} }
if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "policy", Version: "v1alpha1"}) {
m.v1ResourcesStorage["pods/eviction"] = podStorage.Eviction
}
} }
// NewBootstrapController returns a controller for watching the core capabilities of the master. If // NewBootstrapController returns a controller for watching the core capabilities of the master. If
......
...@@ -27,7 +27,9 @@ import ( ...@@ -27,7 +27,9 @@ import (
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/kubelet/client" "k8s.io/kubernetes/pkg/kubelet/client"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/cachesize" "k8s.io/kubernetes/pkg/registry/cachesize"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/registry/generic/registry" "k8s.io/kubernetes/pkg/registry/generic/registry"
...@@ -41,6 +43,7 @@ import ( ...@@ -41,6 +43,7 @@ import (
type PodStorage struct { type PodStorage struct {
Pod *REST Pod *REST
Binding *BindingREST Binding *BindingREST
Eviction *EvictionREST
Status *StatusREST Status *StatusREST
Log *podrest.LogREST Log *podrest.LogREST
Proxy *podrest.ProxyREST Proxy *podrest.ProxyREST
...@@ -100,6 +103,7 @@ func NewStorage(opts generic.RESTOptions, k client.ConnectionInfoGetter, proxyTr ...@@ -100,6 +103,7 @@ func NewStorage(opts generic.RESTOptions, k client.ConnectionInfoGetter, proxyTr
return PodStorage{ return PodStorage{
Pod: &REST{store, proxyTransport}, Pod: &REST{store, proxyTransport},
Binding: &BindingREST{store: store}, Binding: &BindingREST{store: store},
Eviction: &EvictionREST{store: store},
Status: &StatusREST{store: &statusStore}, Status: &StatusREST{store: &statusStore},
Log: &podrest.LogREST{Store: store, KubeletConn: k}, Log: &podrest.LogREST{Store: store, KubeletConn: k},
Proxy: &podrest.ProxyREST{Store: store, ProxyTransport: proxyTransport}, Proxy: &podrest.ProxyREST{Store: store, ProxyTransport: proxyTransport},
...@@ -117,6 +121,155 @@ func (r *REST) ResourceLocation(ctx api.Context, name string) (*url.URL, http.Ro ...@@ -117,6 +121,155 @@ func (r *REST) ResourceLocation(ctx api.Context, name string) (*url.URL, http.Ro
return pod.ResourceLocation(r, r.proxyTransport, ctx, name) return pod.ResourceLocation(r, r.proxyTransport, ctx, name)
} }
// EvictionREST implements the REST endpoint for evicting pods from nodes when etcd is in use.
type EvictionREST struct {
store *registry.Store
PodDisruptionBudgetLister rest.Lister
PodDisruptionBudgetUpdater rest.Updater
}
var _ = rest.Creater(&EvictionREST{})
// New creates a new eviction resource
func (r *EvictionREST) New() runtime.Object {
return &policy.Eviction{}
}
// Create attempts to create a new eviction. That is, it tries to evict a pod.
func (r *EvictionREST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
eviction := obj.(*policy.Eviction)
obj, err := r.store.Get(ctx, eviction.Name)
if err != nil {
return nil, err
}
pod := obj.(*api.Pod)
pdbs, err := r.getPodDisruptionBudgets(ctx, pod)
if err != nil {
return nil, err
}
if len(pdbs) > 1 {
return &unversioned.Status{
Status: unversioned.StatusFailure,
Message: "This pod has more than one PodDisruptionBudget, which the eviction subresource does not support.",
Code: 500,
}, nil
} else if len(pdbs) == 1 {
pdb := pdbs[0]
// Try to verify-and-decrement
// If it was false already, or if it becomes false during the course of our retries,
// raise an error marked as a ... 429 maybe?
ok, err := r.checkAndDecrement(ctx, pdb)
if err != nil {
return nil, err
}
if !ok {
return &unversioned.Status{
Status: unversioned.StatusFailure,
// TODO(mml): Include some more details about why the eviction is disallowed.
// Ideally any such text is generated by the DisruptionController (offline).
Message: "Cannot evict pod as it would violate the pod's disruption budget.",
Code: 429,
// TODO(mml): Add a Retry-After header. Once there are time-based
// budgets, we can sometimes compute a sensible suggested value. But
// even without that, we can give a suggestion (10 minutes?) that
// prevents well-behaved clients from hammering us.
}, nil
}
}
// At this point there was either no PDB or we succeded in decrementing
// Try the delete
_, err = r.store.Delete(ctx, eviction.Name, eviction.DeleteOptions)
if err != nil {
return nil, err
}
// Success!
return &unversioned.Status{Status: unversioned.StatusSuccess}, nil
}
// UpdatedObjectInfo is a simple interface for attempting updates to
// runtime.Objects. EvictionREST implements it directly.
var _ = rest.UpdatedObjectInfo(&EvictionREST{})
// Preconditions returns any preconditions required prior to updating the
// PDB. None currently.
func (r *EvictionREST) Preconditions() *api.Preconditions {
return nil
}
// UpdatedObject returns the updated PDB if it is able to update
// PodDisruptionAllowed from true->false.
func (r *EvictionREST) UpdatedObject(ctx api.Context, oldObj runtime.Object) (newObj runtime.Object, err error) {
copy, err := api.Scheme.DeepCopy(oldObj)
if err != nil {
return
}
newObj = copy.(runtime.Object)
pdb := oldObj.(*policy.PodDisruptionBudget)
if !pdb.Status.PodDisruptionAllowed {
return nil, fmt.Errorf("PodDisruptionAllowed is already false")
}
pdb.Status.PodDisruptionAllowed = false
return
}
func (r *EvictionREST) checkAndDecrement(ctx api.Context, pdb policy.PodDisruptionBudget) (ok bool, err error) {
if !pdb.Status.PodDisruptionAllowed {
return false, nil
}
newObj, _, err := r.PodDisruptionBudgetUpdater.Update(ctx, pdb.Name, r)
if err != nil {
return false, err
}
newPdb := newObj.(*policy.PodDisruptionBudget)
if newPdb.Status.PodDisruptionAllowed {
return false, fmt.Errorf("update did not succeed")
}
return true, nil
}
// Returns any PDBs that match the pod.
// err is set if there's an error.
func (r *EvictionREST) getPodDisruptionBudgets(ctx api.Context, pod *api.Pod) (pdbs []policy.PodDisruptionBudget, err error) {
if len(pod.Labels) == 0 {
return
}
l, err := r.PodDisruptionBudgetLister.List(ctx, nil)
if err != nil {
return
}
pdbList := l.(*policy.PodDisruptionBudgetList)
for _, pdb := range pdbList.Items {
if pdb.Namespace != pod.Namespace {
continue
}
selector, err := unversioned.LabelSelectorAsSelector(pdb.Spec.Selector)
if err != nil {
continue
}
// If a PDB with a nil or empty selector creeps in, it should match nothing, not everything.
if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) {
continue
}
pdbs = append(pdbs, pdb)
}
return pdbs, nil
}
// BindingREST implements the REST endpoint for binding pods to nodes when etcd is in use. // BindingREST implements the REST endpoint for binding pods to nodes when etcd is in use.
type BindingREST struct { type BindingREST struct {
store *registry.Store store *registry.Store
......
...@@ -49,7 +49,7 @@ func NewSecurityContextDeny(client clientset.Interface) admission.Interface { ...@@ -49,7 +49,7 @@ func NewSecurityContextDeny(client clientset.Interface) admission.Interface {
// Admit will deny any pod that defines SELinuxOptions or RunAsUser. // Admit will deny any pod that defines SELinuxOptions or RunAsUser.
func (p *plugin) Admit(a admission.Attributes) (err error) { func (p *plugin) Admit(a admission.Attributes) (err error) {
if a.GetResource().GroupResource() != api.Resource("pods") { if a.GetSubresource() != "" || a.GetResource().GroupResource() != api.Resource("pods") {
return nil return nil
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment