Commit df22dd70 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #31033 from mml/evict

Automatic merge from submit-queue Implementation of the /eviction subresource.
parents 95be706b d82a5914
...@@ -8553,6 +8553,67 @@ ...@@ -8553,6 +8553,67 @@
] ]
}, },
{ {
"path": "/api/v1/namespaces/{namespace}/pods/{name}/eviction",
"description": "API at /api/v1",
"operations": [
{
"type": "v1alpha1.Eviction",
"method": "POST",
"summary": "create eviction of a Eviction",
"nickname": "createNamespacedEvictionEviction",
"parameters": [
{
"type": "string",
"paramType": "query",
"name": "pretty",
"description": "If 'true', then the output is pretty printed.",
"required": false,
"allowMultiple": false
},
{
"type": "v1alpha1.Eviction",
"paramType": "body",
"name": "body",
"description": "",
"required": true,
"allowMultiple": false
},
{
"type": "string",
"paramType": "path",
"name": "namespace",
"description": "object name and auth scope, such as for teams and projects",
"required": true,
"allowMultiple": false
},
{
"type": "string",
"paramType": "path",
"name": "name",
"description": "name of the Eviction",
"required": true,
"allowMultiple": false
}
],
"responseMessages": [
{
"code": 200,
"message": "OK",
"responseModel": "v1alpha1.Eviction"
}
],
"produces": [
"application/json",
"application/yaml",
"application/vnd.kubernetes.protobuf"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/api/v1/namespaces/{namespace}/pods/{name}/exec", "path": "/api/v1/namespaces/{namespace}/pods/{name}/exec",
"description": "API at /api/v1", "description": "API at /api/v1",
"operations": [ "operations": [
...@@ -18821,6 +18882,28 @@ ...@@ -18821,6 +18882,28 @@
} }
} }
}, },
"v1alpha1.Eviction": {
"id": "v1alpha1.Eviction",
"description": "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.",
"properties": {
"kind": {
"type": "string",
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds"
},
"apiVersion": {
"type": "string",
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources"
},
"metadata": {
"$ref": "v1.ObjectMeta",
"description": "ObjectMeta describes the pod that is being evicted."
},
"deleteOptions": {
"$ref": "v1.DeleteOptions",
"description": "DeleteOptions may be provided"
}
}
},
"v1.PodTemplateList": { "v1.PodTemplateList": {
"id": "v1.PodTemplateList", "id": "v1.PodTemplateList",
"description": "PodTemplateList is a list of PodTemplates.", "description": "PodTemplateList is a list of PodTemplates.",
......
...@@ -6660,6 +6660,61 @@ The resulting set of endpoints can be viewed as:<br> ...@@ -6660,6 +6660,61 @@ The resulting set of endpoints can be viewed as:<br>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_v1alpha1_eviction">v1alpha1.Eviction</h3>
<div class="paragraph">
<p>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 &#8230;/pods/foo/evictions.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">kind</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">apiVersion</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">ObjectMeta describes the pod that is being evicted.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_objectmeta">v1.ObjectMeta</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">deleteOptions</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">DeleteOptions may be provided</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_deleteoptions">v1.DeleteOptions</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_awselasticblockstorevolumesource">v1.AWSElasticBlockStoreVolumeSource</h3> <h3 id="_v1_awselasticblockstorevolumesource">v1.AWSElasticBlockStoreVolumeSource</h3>
<div class="paragraph"> <div class="paragraph">
<p>Represents a Persistent Disk resource in AWS.</p> <p>Represents a Persistent Disk resource in AWS.</p>
...@@ -8292,7 +8347,7 @@ The resulting set of endpoints can be viewed as:<br> ...@@ -8292,7 +8347,7 @@ The resulting set of endpoints can be viewed as:<br>
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2016-08-21 13:01:40 UTC Last updated 2016-08-22 23:33:31 UTC
</div> </div>
</div> </div>
</body> </body>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -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"`
}
...@@ -27,6 +27,16 @@ package v1alpha1 ...@@ -27,6 +27,16 @@ package v1alpha1
// Those methods can be generated by using hack/update-generated-swagger-docs.sh // Those methods can be generated by using hack/update-generated-swagger-docs.sh
// AUTO-GENERATED FUNCTIONS START HERE // AUTO-GENERATED FUNCTIONS START HERE
var map_Eviction = map[string]string{
"": "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.",
"metadata": "ObjectMeta describes the pod that is being evicted.",
"deleteOptions": "DeleteOptions may be provided",
}
func (Eviction) SwaggerDoc() map[string]string {
return map_Eviction
}
var map_PodDisruptionBudget = map[string]string{ var map_PodDisruptionBudget = map[string]string{
"": "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",
"spec": "Specification of the desired behavior of the PodDisruptionBudget.", "spec": "Specification of the desired behavior of the PodDisruptionBudget.",
......
...@@ -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