mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 18:00:08 +00:00
Improve error message when name is omitted but generateName is available
This commit is contained in:
parent
4d3b66c09f
commit
81dcd8c836
@ -21,14 +21,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type attributesRecord struct {
|
type attributesRecord struct {
|
||||||
|
kind string
|
||||||
namespace string
|
namespace string
|
||||||
resource string
|
resource string
|
||||||
operation string
|
operation string
|
||||||
object runtime.Object
|
object runtime.Object
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAttributesRecord(object runtime.Object, namespace, resource, operation string) Attributes {
|
func NewAttributesRecord(object runtime.Object, kind, namespace, resource, operation string) Attributes {
|
||||||
return &attributesRecord{
|
return &attributesRecord{
|
||||||
|
kind: kind,
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
resource: resource,
|
resource: resource,
|
||||||
operation: operation,
|
operation: operation,
|
||||||
@ -36,6 +38,10 @@ func NewAttributesRecord(object runtime.Object, namespace, resource, operation s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (record *attributesRecord) GetKind() string {
|
||||||
|
return record.kind
|
||||||
|
}
|
||||||
|
|
||||||
func (record *attributesRecord) GetNamespace() string {
|
func (record *attributesRecord) GetNamespace() string {
|
||||||
return record.namespace
|
return record.namespace
|
||||||
}
|
}
|
||||||
|
48
pkg/admission/errors.go
Normal file
48
pkg/admission/errors.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package admission
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewForbidden is a utility function to return a well-formatted admission control error response
|
||||||
|
func NewForbidden(a Attributes, internalError error) error {
|
||||||
|
// do not double wrap an error of same type
|
||||||
|
if apierrors.IsForbidden(internalError) {
|
||||||
|
return internalError
|
||||||
|
}
|
||||||
|
|
||||||
|
name := "Unknown"
|
||||||
|
kind := a.GetKind()
|
||||||
|
obj := a.GetObject()
|
||||||
|
if obj != nil {
|
||||||
|
objectMeta, err := api.ObjectMetaFor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return apierrors.NewForbidden(kind, name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is necessary because name object name generation has not occurred yet
|
||||||
|
if len(objectMeta.Name) > 0 {
|
||||||
|
name = objectMeta.Name
|
||||||
|
} else if len(objectMeta.GenerateName) > 0 {
|
||||||
|
name = objectMeta.GenerateName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apierrors.NewForbidden(kind, name, internalError)
|
||||||
|
}
|
@ -27,6 +27,7 @@ type Attributes interface {
|
|||||||
GetResource() string
|
GetResource() string
|
||||||
GetOperation() string
|
GetOperation() string
|
||||||
GetObject() runtime.Object
|
GetObject() runtime.Object
|
||||||
|
GetKind() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface is an abstract, pluggable interface for Admission Control decisions.
|
// Interface is an abstract, pluggable interface for Admission Control decisions.
|
||||||
|
@ -40,6 +40,8 @@ type Interface interface {
|
|||||||
SetNamespace(namespace string)
|
SetNamespace(namespace string)
|
||||||
Name() string
|
Name() string
|
||||||
SetName(name string)
|
SetName(name string)
|
||||||
|
GenerateName() string
|
||||||
|
SetGenerateName(name string)
|
||||||
UID() types.UID
|
UID() types.UID
|
||||||
SetUID(uid types.UID)
|
SetUID(uid types.UID)
|
||||||
ResourceVersion() string
|
ResourceVersion() string
|
||||||
@ -79,6 +81,9 @@ type MetadataAccessor interface {
|
|||||||
Name(obj runtime.Object) (string, error)
|
Name(obj runtime.Object) (string, error)
|
||||||
SetName(obj runtime.Object, name string) error
|
SetName(obj runtime.Object, name string) error
|
||||||
|
|
||||||
|
GenerateName(obj runtime.Object) (string, error)
|
||||||
|
SetGenerateName(obj runtime.Object, name string) error
|
||||||
|
|
||||||
UID(obj runtime.Object) (types.UID, error)
|
UID(obj runtime.Object) (types.UID, error)
|
||||||
SetUID(obj runtime.Object, uid types.UID) error
|
SetUID(obj runtime.Object, uid types.UID) error
|
||||||
|
|
||||||
|
@ -178,6 +178,23 @@ func (resourceAccessor) SetName(obj runtime.Object, name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (resourceAccessor) GenerateName(obj runtime.Object) (string, error) {
|
||||||
|
accessor, err := Accessor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return accessor.GenerateName(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (resourceAccessor) SetGenerateName(obj runtime.Object, name string) error {
|
||||||
|
accessor, err := Accessor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
accessor.SetGenerateName(name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) {
|
func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) {
|
||||||
accessor, err := Accessor(obj)
|
accessor, err := Accessor(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -268,6 +285,7 @@ func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) e
|
|||||||
type genericAccessor struct {
|
type genericAccessor struct {
|
||||||
namespace *string
|
namespace *string
|
||||||
name *string
|
name *string
|
||||||
|
generateName *string
|
||||||
uid *types.UID
|
uid *types.UID
|
||||||
apiVersion *string
|
apiVersion *string
|
||||||
kind *string
|
kind *string
|
||||||
@ -305,6 +323,20 @@ func (a genericAccessor) SetName(name string) {
|
|||||||
*a.name = name
|
*a.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a genericAccessor) GenerateName() string {
|
||||||
|
if a.generateName == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *a.generateName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a genericAccessor) SetGenerateName(generateName string) {
|
||||||
|
if a.generateName == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*a.generateName = generateName
|
||||||
|
}
|
||||||
|
|
||||||
func (a genericAccessor) UID() types.UID {
|
func (a genericAccessor) UID() types.UID {
|
||||||
if a.uid == nil {
|
if a.uid == nil {
|
||||||
return ""
|
return ""
|
||||||
@ -392,6 +424,9 @@ func extractFromObjectMeta(v reflect.Value, a *genericAccessor) error {
|
|||||||
if err := runtime.FieldPtr(v, "Name", &a.name); err != nil {
|
if err := runtime.FieldPtr(v, "Name", &a.name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := runtime.FieldPtr(v, "GenerateName", &a.generateName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := runtime.FieldPtr(v, "UID", &a.uid); err != nil {
|
if err := runtime.FieldPtr(v, "UID", &a.uid); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ func TestGenericTypeMeta(t *testing.T) {
|
|||||||
Kind string `json:"kind,omitempty"`
|
Kind string `json:"kind,omitempty"`
|
||||||
Namespace string `json:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
GenerateName string `json:"generateName,omitempty"`
|
||||||
UID string `json:"uid,omitempty"`
|
UID string `json:"uid,omitempty"`
|
||||||
CreationTimestamp util.Time `json:"creationTimestamp,omitempty"`
|
CreationTimestamp util.Time `json:"creationTimestamp,omitempty"`
|
||||||
SelfLink string `json:"selfLink,omitempty"`
|
SelfLink string `json:"selfLink,omitempty"`
|
||||||
@ -44,6 +45,7 @@ func TestGenericTypeMeta(t *testing.T) {
|
|||||||
TypeMeta{
|
TypeMeta{
|
||||||
Namespace: "bar",
|
Namespace: "bar",
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
|
GenerateName: "prefix",
|
||||||
UID: "uid",
|
UID: "uid",
|
||||||
APIVersion: "a",
|
APIVersion: "a",
|
||||||
Kind: "b",
|
Kind: "b",
|
||||||
@ -63,6 +65,9 @@ func TestGenericTypeMeta(t *testing.T) {
|
|||||||
if e, a := "foo", accessor.Name(); e != a {
|
if e, a := "foo", accessor.Name(); e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
|
if e, a := "prefix", accessor.GenerateName(); e != a {
|
||||||
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
|
}
|
||||||
if e, a := "uid", string(accessor.UID()); e != a {
|
if e, a := "uid", string(accessor.UID()); e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
@ -92,6 +97,7 @@ func TestGenericTypeMeta(t *testing.T) {
|
|||||||
|
|
||||||
accessor.SetNamespace("baz")
|
accessor.SetNamespace("baz")
|
||||||
accessor.SetName("bar")
|
accessor.SetName("bar")
|
||||||
|
accessor.SetGenerateName("generate")
|
||||||
accessor.SetUID("other")
|
accessor.SetUID("other")
|
||||||
accessor.SetAPIVersion("c")
|
accessor.SetAPIVersion("c")
|
||||||
accessor.SetKind("d")
|
accessor.SetKind("d")
|
||||||
@ -105,6 +111,9 @@ func TestGenericTypeMeta(t *testing.T) {
|
|||||||
if e, a := "bar", j.Name; e != a {
|
if e, a := "bar", j.Name; e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
|
if e, a := "generate", j.GenerateName; e != a {
|
||||||
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
|
}
|
||||||
if e, a := "other", j.UID; e != a {
|
if e, a := "other", j.UID; e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
@ -135,6 +144,7 @@ type InternalTypeMeta struct {
|
|||||||
Kind string `json:"kind,omitempty"`
|
Kind string `json:"kind,omitempty"`
|
||||||
Namespace string `json:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
GenerateName string `json:"generateName,omitempty"`
|
||||||
UID string `json:"uid,omitempty"`
|
UID string `json:"uid,omitempty"`
|
||||||
CreationTimestamp util.Time `json:"creationTimestamp,omitempty"`
|
CreationTimestamp util.Time `json:"creationTimestamp,omitempty"`
|
||||||
SelfLink string `json:"selfLink,omitempty"`
|
SelfLink string `json:"selfLink,omitempty"`
|
||||||
@ -154,6 +164,7 @@ func TestGenericTypeMetaAccessor(t *testing.T) {
|
|||||||
InternalTypeMeta{
|
InternalTypeMeta{
|
||||||
Namespace: "bar",
|
Namespace: "bar",
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
|
GenerateName: "prefix",
|
||||||
UID: "uid",
|
UID: "uid",
|
||||||
APIVersion: "a",
|
APIVersion: "a",
|
||||||
Kind: "b",
|
Kind: "b",
|
||||||
@ -178,6 +189,13 @@ func TestGenericTypeMetaAccessor(t *testing.T) {
|
|||||||
if e, a := "foo", name; e != a {
|
if e, a := "foo", name; e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
|
generateName, err := accessor.GenerateName(j)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if e, a := "prefix", generateName; e != a {
|
||||||
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
|
}
|
||||||
uid, err := accessor.UID(j)
|
uid, err := accessor.UID(j)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@ -234,6 +252,9 @@ func TestGenericTypeMetaAccessor(t *testing.T) {
|
|||||||
if err := accessor.SetName(j, "bar"); err != nil {
|
if err := accessor.SetName(j, "bar"); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
if err := accessor.SetGenerateName(j, "generate"); err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
if err := accessor.SetUID(j, "other"); err != nil {
|
if err := accessor.SetUID(j, "other"); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -264,6 +285,9 @@ func TestGenericTypeMetaAccessor(t *testing.T) {
|
|||||||
if e, a := "bar", j.TypeMeta.Name; e != a {
|
if e, a := "bar", j.TypeMeta.Name; e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
|
if e, a := "generate", j.TypeMeta.GenerateName; e != a {
|
||||||
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
|
}
|
||||||
if e, a := "other", j.TypeMeta.UID; e != a {
|
if e, a := "other", j.TypeMeta.UID; e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
@ -295,6 +319,7 @@ func TestGenericObjectMeta(t *testing.T) {
|
|||||||
type ObjectMeta struct {
|
type ObjectMeta struct {
|
||||||
Namespace string `json:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
GenerateName string `json:"generateName,omitempty"`
|
||||||
UID string `json:"uid,omitempty"`
|
UID string `json:"uid,omitempty"`
|
||||||
CreationTimestamp util.Time `json:"creationTimestamp,omitempty"`
|
CreationTimestamp util.Time `json:"creationTimestamp,omitempty"`
|
||||||
SelfLink string `json:"selfLink,omitempty"`
|
SelfLink string `json:"selfLink,omitempty"`
|
||||||
@ -314,6 +339,7 @@ func TestGenericObjectMeta(t *testing.T) {
|
|||||||
ObjectMeta{
|
ObjectMeta{
|
||||||
Namespace: "bar",
|
Namespace: "bar",
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
|
GenerateName: "prefix",
|
||||||
UID: "uid",
|
UID: "uid",
|
||||||
ResourceVersion: "1",
|
ResourceVersion: "1",
|
||||||
SelfLink: "some/place/only/we/know",
|
SelfLink: "some/place/only/we/know",
|
||||||
@ -331,6 +357,9 @@ func TestGenericObjectMeta(t *testing.T) {
|
|||||||
if e, a := "foo", accessor.Name(); e != a {
|
if e, a := "foo", accessor.Name(); e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
|
if e, a := "prefix", accessor.GenerateName(); e != a {
|
||||||
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
|
}
|
||||||
if e, a := "uid", string(accessor.UID()); e != a {
|
if e, a := "uid", string(accessor.UID()); e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
@ -355,6 +384,7 @@ func TestGenericObjectMeta(t *testing.T) {
|
|||||||
|
|
||||||
accessor.SetNamespace("baz")
|
accessor.SetNamespace("baz")
|
||||||
accessor.SetName("bar")
|
accessor.SetName("bar")
|
||||||
|
accessor.SetGenerateName("generate")
|
||||||
accessor.SetUID("other")
|
accessor.SetUID("other")
|
||||||
accessor.SetAPIVersion("c")
|
accessor.SetAPIVersion("c")
|
||||||
accessor.SetKind("d")
|
accessor.SetKind("d")
|
||||||
@ -370,6 +400,9 @@ func TestGenericObjectMeta(t *testing.T) {
|
|||||||
if e, a := "bar", j.Name; e != a {
|
if e, a := "bar", j.Name; e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
|
if e, a := "generate", j.GenerateName; e != a {
|
||||||
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
|
}
|
||||||
if e, a := "other", j.UID; e != a {
|
if e, a := "other", j.UID; e != a {
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
t.Errorf("expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectType
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(obj, namespace, scope.Resource, "CREATE"))
|
err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, scope.Resource, "CREATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorJSON(err, scope.Codec, w)
|
errorJSON(err, scope.Codec, w)
|
||||||
return
|
return
|
||||||
@ -262,7 +262,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, typer runtime.ObjectTyper
|
|||||||
|
|
||||||
obj := r.New()
|
obj := r.New()
|
||||||
// PATCH requires same permission as UPDATE
|
// PATCH requires same permission as UPDATE
|
||||||
err = admit.Admit(admission.NewAttributesRecord(obj, namespace, scope.Resource, "UPDATE"))
|
err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, scope.Resource, "UPDATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorJSON(err, scope.Codec, w)
|
errorJSON(err, scope.Codec, w)
|
||||||
return
|
return
|
||||||
@ -362,7 +362,7 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(obj, namespace, scope.Resource, "UPDATE"))
|
err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, scope.Resource, "UPDATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorJSON(err, scope.Codec, w)
|
errorJSON(err, scope.Codec, w)
|
||||||
return
|
return
|
||||||
@ -423,7 +423,7 @@ func DeleteResource(r rest.GracefulDeleter, checkBody bool, scope RequestScope,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(nil, namespace, scope.Resource, "DELETE"))
|
err = admit.Admit(admission.NewAttributesRecord(nil, scope.Kind, namespace, scope.Resource, "DELETE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorJSON(err, scope.Codec, w)
|
errorJSON(err, scope.Codec, w)
|
||||||
return
|
return
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
||||||
apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,7 +35,7 @@ func init() {
|
|||||||
type alwaysDeny struct{}
|
type alwaysDeny struct{}
|
||||||
|
|
||||||
func (alwaysDeny) Admit(a admission.Attributes) (err error) {
|
func (alwaysDeny) Admit(a admission.Attributes) (err error) {
|
||||||
return apierrors.NewForbidden(a.GetResource(), "", errors.New("Admission control is denying all modifications"))
|
return admission.NewForbidden(a, errors.New("Admission control is denying all modifications"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAlwaysDeny() admission.Interface {
|
func NewAlwaysDeny() admission.Interface {
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
func TestAdmission(t *testing.T) {
|
func TestAdmission(t *testing.T) {
|
||||||
handler := NewAlwaysDeny()
|
handler := NewAlwaysDeny()
|
||||||
err := handler.Admit(admission.NewAttributesRecord(nil, "foo", "Pod", "ignored"))
|
err := handler.Admit(admission.NewAttributesRecord(nil, "Pod", "foo", "Pod", "ignored"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error returned from admission handler")
|
t.Errorf("Expected error returned from admission handler")
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
@ -58,6 +57,9 @@ func (l *limitRanger) Admit(a admission.Attributes) (err error) {
|
|||||||
name := "Unknown"
|
name := "Unknown"
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
name, _ = meta.NewAccessor().Name(obj)
|
name, _ = meta.NewAccessor().Name(obj)
|
||||||
|
if len(name) == 0 {
|
||||||
|
name, _ = meta.NewAccessor().GenerateName(obj)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
key := &api.LimitRange{
|
key := &api.LimitRange{
|
||||||
@ -68,7 +70,7 @@ func (l *limitRanger) Admit(a admission.Attributes) (err error) {
|
|||||||
}
|
}
|
||||||
items, err := l.indexer.Index("namespace", key)
|
items, err := l.indexer.Index("namespace", key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing limit ranges", a.GetOperation(), resource))
|
return admission.NewForbidden(a, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing limit ranges", a.GetOperation(), resource))
|
||||||
}
|
}
|
||||||
if len(items) == 0 {
|
if len(items) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -79,7 +81,7 @@ func (l *limitRanger) Admit(a admission.Attributes) (err error) {
|
|||||||
limitRange := items[i].(*api.LimitRange)
|
limitRange := items[i].(*api.LimitRange)
|
||||||
err = l.limitFunc(limitRange, a.GetResource(), a.GetObject())
|
err = l.limitFunc(limitRange, a.GetResource(), a.GetObject())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -250,11 +252,11 @@ func PodLimitFunc(limitRange *api.LimitRange, pod *api.Pod) error {
|
|||||||
switch minOrMax {
|
switch minOrMax {
|
||||||
case "Min":
|
case "Min":
|
||||||
if observed < enforced {
|
if observed < enforced {
|
||||||
return apierrors.NewForbidden("pods", pod.Name, err)
|
return err
|
||||||
}
|
}
|
||||||
case "Max":
|
case "Max":
|
||||||
if observed > enforced {
|
if observed > enforced {
|
||||||
return apierrors.NewForbidden("pods", pod.Name, err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,11 @@ func (p *provision) Admit(a admission.Attributes) (err error) {
|
|||||||
}
|
}
|
||||||
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource())
|
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion)
|
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
|
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
|
||||||
return nil
|
return nil
|
||||||
@ -71,14 +71,14 @@ func (p *provision) Admit(a admission.Attributes) (err error) {
|
|||||||
}
|
}
|
||||||
_, exists, err := p.store.Get(namespace)
|
_, exists, err := p.store.Get(namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err = p.client.Namespaces().Create(namespace)
|
_, err = p.client.Namespaces().Create(namespace)
|
||||||
if err != nil && !errors.IsAlreadyExists(err) {
|
if err != nil && !errors.IsAlreadyExists(err) {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, namespace, "pods", "CREATE"))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", namespace, "pods", "CREATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ func TestAdmissionNamespaceExists(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, namespace, "pods", "CREATE"))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", namespace, "pods", "CREATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ func TestIgnoreAdmission(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, namespace, "pods", "UPDATE"))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", namespace, "pods", "UPDATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ func TestAdmissionNamespaceExistsUnknownToHandler(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, namespace, "pods", "CREATE"))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", namespace, "pods", "CREATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
@ -50,11 +49,11 @@ type exists struct {
|
|||||||
func (e *exists) Admit(a admission.Attributes) (err error) {
|
func (e *exists) Admit(a admission.Attributes) (err error) {
|
||||||
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource())
|
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion)
|
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
|
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
|
||||||
return nil
|
return nil
|
||||||
@ -68,17 +67,12 @@ func (e *exists) Admit(a admission.Attributes) (err error) {
|
|||||||
}
|
}
|
||||||
_, exists, err := e.store.Get(namespace)
|
_, exists, err := e.store.Get(namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
obj := a.GetObject()
|
return admission.NewForbidden(a, fmt.Errorf("Namespace %s does not exist", a.GetNamespace()))
|
||||||
name := "Unknown"
|
|
||||||
if obj != nil {
|
|
||||||
name, _ = meta.NewAccessor().Name(obj)
|
|
||||||
}
|
|
||||||
return apierrors.NewForbidden(kind, name, fmt.Errorf("Namespace %s does not exist", a.GetNamespace()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExists(c client.Interface) admission.Interface {
|
func NewExists(c client.Interface) admission.Interface {
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
@ -52,11 +51,11 @@ func (l *lifecycle) Admit(a admission.Attributes) (err error) {
|
|||||||
}
|
}
|
||||||
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource())
|
defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion)
|
mapping, err := latest.RESTMapper.RESTMapping(kind, defaultVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
|
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
|
||||||
return nil
|
return nil
|
||||||
@ -68,7 +67,7 @@ func (l *lifecycle) Admit(a admission.Attributes) (err error) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil
|
return nil
|
||||||
@ -78,12 +77,7 @@ func (l *lifecycle) Admit(a admission.Attributes) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
name := "Unknown"
|
return admission.NewForbidden(a, fmt.Errorf("Namespace %s is terminating", a.GetNamespace()))
|
||||||
obj := a.GetObject()
|
|
||||||
if obj != nil {
|
|
||||||
name, _ = meta.NewAccessor().Name(obj)
|
|
||||||
}
|
|
||||||
return apierrors.NewForbidden(kind, name, fmt.Errorf("Namespace %s is terminating", a.GetNamespace()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLifecycle(c client.Interface) admission.Interface {
|
func NewLifecycle(c client.Interface) admission.Interface {
|
||||||
|
@ -50,7 +50,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, namespaceObj.Namespace, "pods", "CREATE"))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", namespaceObj.Namespace, "pods", "CREATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
}
|
}
|
||||||
@ -60,19 +60,19 @@ func TestAdmission(t *testing.T) {
|
|||||||
store.Add(namespaceObj)
|
store.Add(namespaceObj)
|
||||||
|
|
||||||
// verify create operations in the namespace cause an error
|
// verify create operations in the namespace cause an error
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&pod, namespaceObj.Namespace, "pods", "CREATE"))
|
err = handler.Admit(admission.NewAttributesRecord(&pod, "Pod", namespaceObj.Namespace, "pods", "CREATE"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error rejecting creates in a namespace when it is terminating")
|
t.Errorf("Expected error rejecting creates in a namespace when it is terminating")
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify update operations in the namespace can proceed
|
// verify update operations in the namespace can proceed
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&pod, namespaceObj.Namespace, "pods", "UPDATE"))
|
err = handler.Admit(admission.NewAttributesRecord(&pod, "Pod", namespaceObj.Namespace, "pods", "UPDATE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify delete operations in the namespace can proceed
|
// verify delete operations in the namespace can proceed
|
||||||
err = handler.Admit(admission.NewAttributesRecord(nil, namespaceObj.Namespace, "pods", "DELETE"))
|
err = handler.Admit(admission.NewAttributesRecord(nil, "Pod", namespaceObj.Namespace, "pods", "DELETE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
|
||||||
@ -71,13 +69,6 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
obj := a.GetObject()
|
|
||||||
resource := a.GetResource()
|
|
||||||
name := "Unknown"
|
|
||||||
if obj != nil {
|
|
||||||
name, _ = meta.NewAccessor().Name(obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
key := &api.ResourceQuota{
|
key := &api.ResourceQuota{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Namespace: a.GetNamespace(),
|
Namespace: a.GetNamespace(),
|
||||||
@ -86,7 +77,7 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
|
|||||||
}
|
}
|
||||||
items, err := q.indexer.Index("namespace", key)
|
items, err := q.indexer.Index("namespace", key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing quota", a.GetOperation(), resource))
|
return admission.NewForbidden(a, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing quota", a.GetOperation(), a.GetResource()))
|
||||||
}
|
}
|
||||||
if len(items) == 0 {
|
if len(items) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -109,7 +100,7 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
|
|||||||
|
|
||||||
dirty, err := IncrementUsage(a, status, q.client)
|
dirty, err := IncrementUsage(a, status, q.client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dirty {
|
if dirty {
|
||||||
@ -125,7 +116,7 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
|
|||||||
usage.Status = *status
|
usage.Status = *status
|
||||||
_, err = q.client.ResourceQuotas(usage.Namespace).UpdateStatus(&usage)
|
_, err = q.client.ResourceQuotas(usage.Namespace).UpdateStatus(&usage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing quota", a.GetOperation(), a.GetResource()))
|
return admission.NewForbidden(a, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing quota", a.GetOperation(), a.GetResource()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,17 +127,12 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
|
|||||||
// Return true if the usage must be recorded prior to admitting the new resource
|
// Return true if the usage must be recorded prior to admitting the new resource
|
||||||
// Return an error if the operation should not pass admission control
|
// Return an error if the operation should not pass admission control
|
||||||
func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, client client.Interface) (bool, error) {
|
func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, client client.Interface) (bool, error) {
|
||||||
obj := a.GetObject()
|
|
||||||
resourceName := a.GetResource()
|
|
||||||
name := "Unknown"
|
|
||||||
if obj != nil {
|
|
||||||
name, _ = meta.NewAccessor().Name(obj)
|
|
||||||
}
|
|
||||||
dirty := false
|
dirty := false
|
||||||
set := map[api.ResourceName]bool{}
|
set := map[api.ResourceName]bool{}
|
||||||
for k := range status.Hard {
|
for k := range status.Hard {
|
||||||
set[k] = true
|
set[k] = true
|
||||||
}
|
}
|
||||||
|
obj := a.GetObject()
|
||||||
// handle max counts for each kind of resource (pods, services, replicationControllers, etc.)
|
// handle max counts for each kind of resource (pods, services, replicationControllers, etc.)
|
||||||
if a.GetOperation() == "CREATE" {
|
if a.GetOperation() == "CREATE" {
|
||||||
resourceName := resourceToResourceName[a.GetResource()]
|
resourceName := resourceToResourceName[a.GetResource()]
|
||||||
@ -154,10 +140,10 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
|
|||||||
if hardFound {
|
if hardFound {
|
||||||
used, usedFound := status.Used[resourceName]
|
used, usedFound := status.Used[resourceName]
|
||||||
if !usedFound {
|
if !usedFound {
|
||||||
return false, apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed."))
|
return false, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed.")
|
||||||
}
|
}
|
||||||
if used.Value() >= hard.Value() {
|
if used.Value() >= hard.Value() {
|
||||||
return false, apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Limited to %s %s", hard.String(), a.GetResource()))
|
return false, fmt.Errorf("Limited to %s %s", hard.String(), resourceName)
|
||||||
} else {
|
} else {
|
||||||
status.Used[resourceName] = *resource.NewQuantity(used.Value()+int64(1), resource.DecimalSI)
|
status.Used[resourceName] = *resource.NewQuantity(used.Value()+int64(1), resource.DecimalSI)
|
||||||
dirty = true
|
dirty = true
|
||||||
@ -173,7 +159,7 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
|
|||||||
if a.GetOperation() == "UPDATE" {
|
if a.GetOperation() == "UPDATE" {
|
||||||
oldPod, err := client.Pods(a.GetNamespace()).Get(pod.Name)
|
oldPod, err := client.Pods(a.GetNamespace()).Get(pod.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, apierrors.NewForbidden(resourceName, name, err)
|
return false, err
|
||||||
}
|
}
|
||||||
oldCPU := resourcequota.PodCPU(oldPod)
|
oldCPU := resourcequota.PodCPU(oldPod)
|
||||||
oldMemory := resourcequota.PodMemory(oldPod)
|
oldMemory := resourcequota.PodMemory(oldPod)
|
||||||
@ -185,10 +171,10 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
|
|||||||
if hardMemFound {
|
if hardMemFound {
|
||||||
used, usedFound := status.Used[api.ResourceMemory]
|
used, usedFound := status.Used[api.ResourceMemory]
|
||||||
if !usedFound {
|
if !usedFound {
|
||||||
return false, apierrors.NewForbidden(resourceName, name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed."))
|
return false, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed.")
|
||||||
}
|
}
|
||||||
if used.Value()+deltaMemory.Value() > hardMem.Value() {
|
if used.Value()+deltaMemory.Value() > hardMem.Value() {
|
||||||
return false, apierrors.NewForbidden(resourceName, name, fmt.Errorf("Limited to %s memory", hardMem.String()))
|
return false, fmt.Errorf("Limited to %s memory", hardMem.String())
|
||||||
} else {
|
} else {
|
||||||
status.Used[api.ResourceMemory] = *resource.NewQuantity(used.Value()+deltaMemory.Value(), resource.DecimalSI)
|
status.Used[api.ResourceMemory] = *resource.NewQuantity(used.Value()+deltaMemory.Value(), resource.DecimalSI)
|
||||||
dirty = true
|
dirty = true
|
||||||
@ -198,10 +184,10 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
|
|||||||
if hardCPUFound {
|
if hardCPUFound {
|
||||||
used, usedFound := status.Used[api.ResourceCPU]
|
used, usedFound := status.Used[api.ResourceCPU]
|
||||||
if !usedFound {
|
if !usedFound {
|
||||||
return false, apierrors.NewForbidden(resourceName, name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed."))
|
return false, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed.")
|
||||||
}
|
}
|
||||||
if used.MilliValue()+deltaCPU.MilliValue() > hardCPU.MilliValue() {
|
if used.MilliValue()+deltaCPU.MilliValue() > hardCPU.MilliValue() {
|
||||||
return false, apierrors.NewForbidden(resourceName, name, fmt.Errorf("Limited to %s CPU", hardCPU.String()))
|
return false, fmt.Errorf("Limited to %s CPU", hardCPU.String())
|
||||||
} else {
|
} else {
|
||||||
status.Used[api.ResourceCPU] = *resource.NewMilliQuantity(used.MilliValue()+deltaCPU.MilliValue(), resource.DecimalSI)
|
status.Used[api.ResourceCPU] = *resource.NewMilliQuantity(used.MilliValue()+deltaCPU.MilliValue(), resource.DecimalSI)
|
||||||
dirty = true
|
dirty = true
|
||||||
|
@ -41,7 +41,7 @@ func getResourceRequirements(cpu, memory string) api.ResourceRequirements {
|
|||||||
func TestAdmissionIgnoresDelete(t *testing.T) {
|
func TestAdmissionIgnoresDelete(t *testing.T) {
|
||||||
namespace := "default"
|
namespace := "default"
|
||||||
handler := NewResourceQuota(&testclient.Fake{})
|
handler := NewResourceQuota(&testclient.Fake{})
|
||||||
err := handler.Admit(admission.NewAttributesRecord(nil, namespace, "pods", "DELETE"))
|
err := handler.Admit(admission.NewAttributesRecord(nil, "Pod", namespace, "pods", "DELETE"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ResourceQuota should admit all deletes", err)
|
t.Errorf("ResourceQuota should admit all deletes", err)
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ func TestIncrementUsagePods(t *testing.T) {
|
|||||||
r := api.ResourcePods
|
r := api.ResourcePods
|
||||||
status.Hard[r] = resource.MustParse("2")
|
status.Hard[r] = resource.MustParse("2")
|
||||||
status.Used[r] = resource.MustParse("1")
|
status.Used[r] = resource.MustParse("1")
|
||||||
dirty, err := IncrementUsage(admission.NewAttributesRecord(&api.Pod{}, namespace, "pods", "CREATE"), status, client)
|
dirty, err := IncrementUsage(admission.NewAttributesRecord(&api.Pod{}, "Pod", namespace, "pods", "CREATE"), status, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error", err)
|
t.Errorf("Unexpected error", err)
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ func TestIncrementUsageMemory(t *testing.T) {
|
|||||||
Volumes: []api.Volume{{Name: "vol"}},
|
Volumes: []api.Volume{{Name: "vol"}},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||||
}}
|
}}
|
||||||
dirty, err := IncrementUsage(admission.NewAttributesRecord(newPod, namespace, "pods", "CREATE"), status, client)
|
dirty, err := IncrementUsage(admission.NewAttributesRecord(newPod, "Pod", namespace, "pods", "CREATE"), status, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error", err)
|
t.Errorf("Unexpected error", err)
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ func TestExceedUsageMemory(t *testing.T) {
|
|||||||
Volumes: []api.Volume{{Name: "vol"}},
|
Volumes: []api.Volume{{Name: "vol"}},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "3Gi")}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "3Gi")}},
|
||||||
}}
|
}}
|
||||||
_, err := IncrementUsage(admission.NewAttributesRecord(newPod, namespace, "pods", "CREATE"), status, client)
|
_, err := IncrementUsage(admission.NewAttributesRecord(newPod, "Pod", namespace, "pods", "CREATE"), status, client)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected memory usage exceeded error")
|
t.Errorf("Expected memory usage exceeded error")
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ func TestIncrementUsageCPU(t *testing.T) {
|
|||||||
Volumes: []api.Volume{{Name: "vol"}},
|
Volumes: []api.Volume{{Name: "vol"}},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||||
}}
|
}}
|
||||||
dirty, err := IncrementUsage(admission.NewAttributesRecord(newPod, namespace, "pods", "CREATE"), status, client)
|
dirty, err := IncrementUsage(admission.NewAttributesRecord(newPod, "Pod", namespace, "pods", "CREATE"), status, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error", err)
|
t.Errorf("Unexpected error", err)
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ func TestExceedUsageCPU(t *testing.T) {
|
|||||||
Volumes: []api.Volume{{Name: "vol"}},
|
Volumes: []api.Volume{{Name: "vol"}},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("500m", "1Gi")}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("500m", "1Gi")}},
|
||||||
}}
|
}}
|
||||||
_, err := IncrementUsage(admission.NewAttributesRecord(newPod, namespace, "pods", "CREATE"), status, client)
|
_, err := IncrementUsage(admission.NewAttributesRecord(newPod, "Pod", namespace, "pods", "CREATE"), status, client)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected CPU usage exceeded error")
|
t.Errorf("Expected CPU usage exceeded error")
|
||||||
}
|
}
|
||||||
@ -248,7 +248,7 @@ func TestExceedUsagePods(t *testing.T) {
|
|||||||
r := api.ResourcePods
|
r := api.ResourcePods
|
||||||
status.Hard[r] = resource.MustParse("1")
|
status.Hard[r] = resource.MustParse("1")
|
||||||
status.Used[r] = resource.MustParse("1")
|
status.Used[r] = resource.MustParse("1")
|
||||||
_, err := IncrementUsage(admission.NewAttributesRecord(&api.Pod{}, namespace, "pods", "CREATE"), status, client)
|
_, err := IncrementUsage(admission.NewAttributesRecord(&api.Pod{}, "Pod", namespace, "pods", "CREATE"), status, client)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error because this would exceed your quota")
|
t.Errorf("Expected error because this would exceed your quota")
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ func TestIncrementUsageServices(t *testing.T) {
|
|||||||
r := api.ResourceServices
|
r := api.ResourceServices
|
||||||
status.Hard[r] = resource.MustParse("2")
|
status.Hard[r] = resource.MustParse("2")
|
||||||
status.Used[r] = resource.MustParse("1")
|
status.Used[r] = resource.MustParse("1")
|
||||||
dirty, err := IncrementUsage(admission.NewAttributesRecord(&api.Service{}, namespace, "services", "CREATE"), status, client)
|
dirty, err := IncrementUsage(admission.NewAttributesRecord(&api.Service{}, "Service", namespace, "services", "CREATE"), status, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error", err)
|
t.Errorf("Unexpected error", err)
|
||||||
}
|
}
|
||||||
@ -299,7 +299,7 @@ func TestExceedUsageServices(t *testing.T) {
|
|||||||
r := api.ResourceServices
|
r := api.ResourceServices
|
||||||
status.Hard[r] = resource.MustParse("1")
|
status.Hard[r] = resource.MustParse("1")
|
||||||
status.Used[r] = resource.MustParse("1")
|
status.Used[r] = resource.MustParse("1")
|
||||||
_, err := IncrementUsage(admission.NewAttributesRecord(&api.Service{}, namespace, "services", "CREATE"), status, client)
|
_, err := IncrementUsage(admission.NewAttributesRecord(&api.Service{}, "Service", namespace, "services", "CREATE"), status, client)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error because this would exceed usage")
|
t.Errorf("Expected error because this would exceed usage")
|
||||||
}
|
}
|
||||||
@ -321,7 +321,7 @@ func TestIncrementUsageReplicationControllers(t *testing.T) {
|
|||||||
r := api.ResourceReplicationControllers
|
r := api.ResourceReplicationControllers
|
||||||
status.Hard[r] = resource.MustParse("2")
|
status.Hard[r] = resource.MustParse("2")
|
||||||
status.Used[r] = resource.MustParse("1")
|
status.Used[r] = resource.MustParse("1")
|
||||||
dirty, err := IncrementUsage(admission.NewAttributesRecord(&api.ReplicationController{}, namespace, "replicationControllers", "CREATE"), status, client)
|
dirty, err := IncrementUsage(admission.NewAttributesRecord(&api.ReplicationController{}, "ReplicationController", namespace, "replicationControllers", "CREATE"), status, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error", err)
|
t.Errorf("Unexpected error", err)
|
||||||
}
|
}
|
||||||
@ -350,7 +350,7 @@ func TestExceedUsageReplicationControllers(t *testing.T) {
|
|||||||
r := api.ResourceReplicationControllers
|
r := api.ResourceReplicationControllers
|
||||||
status.Hard[r] = resource.MustParse("1")
|
status.Hard[r] = resource.MustParse("1")
|
||||||
status.Used[r] = resource.MustParse("1")
|
status.Used[r] = resource.MustParse("1")
|
||||||
_, err := IncrementUsage(admission.NewAttributesRecord(&api.ReplicationController{}, namespace, "replicationControllers", "CREATE"), status, client)
|
_, err := IncrementUsage(admission.NewAttributesRecord(&api.ReplicationController{}, "ReplicationController", namespace, "replicationControllers", "CREATE"), status, client)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error for exceeding hard limits")
|
t.Errorf("Expected error for exceeding hard limits")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user