mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-12 05:21:58 +00:00
Split pkg/genericapiserver/api/request from ObjectMeta
This commit is contained in:
parent
55bee3ad21
commit
57e3a57c10
@ -22,23 +22,8 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/conversion"
|
"k8s.io/apimachinery/pkg/conversion"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
|
||||||
"k8s.io/kubernetes/pkg/util/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
|
|
||||||
func FillObjectMetaSystemFields(ctx genericapirequest.Context, meta *ObjectMeta) {
|
|
||||||
meta.CreationTimestamp = metav1.Now()
|
|
||||||
// allows admission controllers to assign a UID earlier in the request processing
|
|
||||||
// to support tracking resources pending creation.
|
|
||||||
uid, found := genericapirequest.UIDFrom(ctx)
|
|
||||||
if !found {
|
|
||||||
uid = uuid.NewUUID()
|
|
||||||
}
|
|
||||||
meta.UID = uid
|
|
||||||
meta.SelfLink = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values.
|
// HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values.
|
||||||
func HasObjectMetaSystemFieldValues(meta *ObjectMeta) bool {
|
func HasObjectMetaSystemFieldValues(meta *ObjectMeta) bool {
|
||||||
return !meta.CreationTimestamp.Time.IsZero() ||
|
return !meta.CreationTimestamp.Time.IsZero() ||
|
||||||
|
@ -28,45 +28,10 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
|
||||||
"k8s.io/kubernetes/pkg/util/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ meta.Object = &api.ObjectMeta{}
|
var _ meta.Object = &api.ObjectMeta{}
|
||||||
|
|
||||||
// TestFillObjectMetaSystemFields validates that system populated fields are set on an object
|
|
||||||
func TestFillObjectMetaSystemFields(t *testing.T) {
|
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
|
||||||
resource := api.ObjectMeta{}
|
|
||||||
api.FillObjectMetaSystemFields(ctx, &resource)
|
|
||||||
if resource.CreationTimestamp.Time.IsZero() {
|
|
||||||
t.Errorf("resource.CreationTimestamp is zero")
|
|
||||||
} else if len(resource.UID) == 0 {
|
|
||||||
t.Errorf("resource.UID missing")
|
|
||||||
}
|
|
||||||
// verify we can inject a UID
|
|
||||||
uid := uuid.NewUUID()
|
|
||||||
ctx = genericapirequest.WithUID(ctx, uid)
|
|
||||||
resource = api.ObjectMeta{}
|
|
||||||
api.FillObjectMetaSystemFields(ctx, &resource)
|
|
||||||
if resource.UID != uid {
|
|
||||||
t.Errorf("resource.UID expected: %v, actual: %v", uid, resource.UID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestHasObjectMetaSystemFieldValues validates that true is returned if and only if all fields are populated
|
|
||||||
func TestHasObjectMetaSystemFieldValues(t *testing.T) {
|
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
|
||||||
resource := api.ObjectMeta{}
|
|
||||||
if api.HasObjectMetaSystemFieldValues(&resource) {
|
|
||||||
t.Errorf("the resource does not have all fields yet populated, but incorrectly reports it does")
|
|
||||||
}
|
|
||||||
api.FillObjectMetaSystemFields(ctx, &resource)
|
|
||||||
if !api.HasObjectMetaSystemFieldValues(&resource) {
|
|
||||||
t.Errorf("the resource does have all fields populated, but incorrectly reports it does not")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getObjectMetaAndOwnerReferences() (objectMeta api.ObjectMeta, metaOwnerReferences []metav1.OwnerReference) {
|
func getObjectMetaAndOwnerReferences() (objectMeta api.ObjectMeta, metaOwnerReferences []metav1.OwnerReference) {
|
||||||
fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&objectMeta)
|
fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&objectMeta)
|
||||||
references := objectMeta.OwnerReferences
|
references := objectMeta.OwnerReferences
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns string version of ResourceName.
|
// Returns string version of ResourceName.
|
||||||
@ -228,13 +227,3 @@ func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, li
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidNamespace returns false if the namespace on the context differs from the resource. If the resource has no namespace, it is set to the value in the context.
|
|
||||||
// TODO(sttts): move into pkg/genericapiserver/api
|
|
||||||
func ValidNamespace(ctx genericapirequest.Context, resource *ObjectMeta) bool {
|
|
||||||
ns, ok := genericapirequest.NamespaceFrom(ctx)
|
|
||||||
if len(resource.Namespace) == 0 {
|
|
||||||
resource.Namespace = ns
|
|
||||||
}
|
|
||||||
return ns == resource.Namespace && ok
|
|
||||||
}
|
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/validation/genericvalidation"
|
"k8s.io/kubernetes/pkg/api/validation/genericvalidation"
|
||||||
path "k8s.io/kubernetes/pkg/api/validation/path"
|
"k8s.io/kubernetes/pkg/api/validation/path"
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
if strategy.NamespaceScoped() {
|
if strategy.NamespaceScoped() {
|
||||||
if !api.ValidNamespace(ctx, objectMeta) {
|
if !ValidNamespace(ctx, objectMeta) {
|
||||||
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -70,7 +70,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob
|
|||||||
objectMeta.DeletionTimestamp = nil
|
objectMeta.DeletionTimestamp = nil
|
||||||
objectMeta.DeletionGracePeriodSeconds = nil
|
objectMeta.DeletionGracePeriodSeconds = nil
|
||||||
strategy.PrepareForCreate(ctx, obj)
|
strategy.PrepareForCreate(ctx, obj)
|
||||||
api.FillObjectMetaSystemFields(ctx, objectMeta)
|
FillObjectMetaSystemFields(ctx, objectMeta)
|
||||||
api.GenerateName(strategy, objectMeta)
|
api.GenerateName(strategy, objectMeta)
|
||||||
|
|
||||||
// ClusterName is ignored and should not be saved
|
// ClusterName is ignored and should not be saved
|
||||||
|
47
pkg/api/rest/meta.go
Normal file
47
pkg/api/rest/meta.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
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 rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
|
"k8s.io/kubernetes/pkg/util/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
|
||||||
|
func FillObjectMetaSystemFields(ctx genericapirequest.Context, meta *api.ObjectMeta) {
|
||||||
|
meta.CreationTimestamp = metav1.Now()
|
||||||
|
// allows admission controllers to assign a UID earlier in the request processing
|
||||||
|
// to support tracking resources pending creation.
|
||||||
|
uid, found := genericapirequest.UIDFrom(ctx)
|
||||||
|
if !found {
|
||||||
|
uid = uuid.NewUUID()
|
||||||
|
}
|
||||||
|
meta.UID = uid
|
||||||
|
meta.SelfLink = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidNamespace returns false if the namespace on the context differs from the resource. If the resource has no namespace, it is set to the value in the context.
|
||||||
|
// TODO(sttts): move into pkg/genericapiserver/api
|
||||||
|
func ValidNamespace(ctx genericapirequest.Context, resource *api.ObjectMeta) bool {
|
||||||
|
ns, ok := genericapirequest.NamespaceFrom(ctx)
|
||||||
|
if len(resource.Namespace) == 0 {
|
||||||
|
resource.Namespace = ns
|
||||||
|
}
|
||||||
|
return ns == resource.Namespace && ok
|
||||||
|
}
|
87
pkg/api/rest/meta_test.go
Normal file
87
pkg/api/rest/meta_test.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
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 rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
|
"k8s.io/kubernetes/pkg/util/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestFillObjectMetaSystemFields validates that system populated fields are set on an object
|
||||||
|
func TestFillObjectMetaSystemFields(t *testing.T) {
|
||||||
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
|
resource := api.ObjectMeta{}
|
||||||
|
FillObjectMetaSystemFields(ctx, &resource)
|
||||||
|
if resource.CreationTimestamp.Time.IsZero() {
|
||||||
|
t.Errorf("resource.CreationTimestamp is zero")
|
||||||
|
} else if len(resource.UID) == 0 {
|
||||||
|
t.Errorf("resource.UID missing")
|
||||||
|
}
|
||||||
|
// verify we can inject a UID
|
||||||
|
uid := uuid.NewUUID()
|
||||||
|
ctx = genericapirequest.WithUID(ctx, uid)
|
||||||
|
resource = api.ObjectMeta{}
|
||||||
|
FillObjectMetaSystemFields(ctx, &resource)
|
||||||
|
if resource.UID != uid {
|
||||||
|
t.Errorf("resource.UID expected: %v, actual: %v", uid, resource.UID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestHasObjectMetaSystemFieldValues validates that true is returned if and only if all fields are populated
|
||||||
|
func TestHasObjectMetaSystemFieldValues(t *testing.T) {
|
||||||
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
|
resource := api.ObjectMeta{}
|
||||||
|
if api.HasObjectMetaSystemFieldValues(&resource) {
|
||||||
|
t.Errorf("the resource does not have all fields yet populated, but incorrectly reports it does")
|
||||||
|
}
|
||||||
|
FillObjectMetaSystemFields(ctx, &resource)
|
||||||
|
if !api.HasObjectMetaSystemFieldValues(&resource) {
|
||||||
|
t.Errorf("the resource does have all fields populated, but incorrectly reports it does not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update
|
||||||
|
func TestValidNamespace(t *testing.T) {
|
||||||
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
|
namespace, _ := genericapirequest.NamespaceFrom(ctx)
|
||||||
|
resource := api.ReplicationController{}
|
||||||
|
if !ValidNamespace(ctx, &resource.ObjectMeta) {
|
||||||
|
t.Fatalf("expected success")
|
||||||
|
}
|
||||||
|
if namespace != resource.Namespace {
|
||||||
|
t.Fatalf("expected resource to have the default namespace assigned during validation")
|
||||||
|
}
|
||||||
|
resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}}
|
||||||
|
if ValidNamespace(ctx, &resource.ObjectMeta) {
|
||||||
|
t.Fatalf("Expected error that resource and context errors do not match because resource has different namespace")
|
||||||
|
}
|
||||||
|
ctx = genericapirequest.NewContext()
|
||||||
|
if ValidNamespace(ctx, &resource.ObjectMeta) {
|
||||||
|
t.Fatalf("Expected error that resource and context errors do not match since context has no namespace")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = genericapirequest.NewContext()
|
||||||
|
ns := genericapirequest.NamespaceValue(ctx)
|
||||||
|
if ns != "" {
|
||||||
|
t.Fatalf("Expected the empty string")
|
||||||
|
}
|
||||||
|
}
|
@ -81,7 +81,7 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx genericapirequest.Context, ob
|
|||||||
return kerr
|
return kerr
|
||||||
}
|
}
|
||||||
if strategy.NamespaceScoped() {
|
if strategy.NamespaceScoped() {
|
||||||
if !api.ValidNamespace(ctx, objectMeta) {
|
if !ValidNamespace(ctx, objectMeta) {
|
||||||
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -43,33 +43,6 @@ func TestNamespaceContext(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update
|
|
||||||
func TestValidNamespace(t *testing.T) {
|
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
|
||||||
namespace, _ := genericapirequest.NamespaceFrom(ctx)
|
|
||||||
resource := api.ReplicationController{}
|
|
||||||
if !api.ValidNamespace(ctx, &resource.ObjectMeta) {
|
|
||||||
t.Fatalf("expected success")
|
|
||||||
}
|
|
||||||
if namespace != resource.Namespace {
|
|
||||||
t.Fatalf("expected resource to have the default namespace assigned during validation")
|
|
||||||
}
|
|
||||||
resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}}
|
|
||||||
if api.ValidNamespace(ctx, &resource.ObjectMeta) {
|
|
||||||
t.Fatalf("Expected error that resource and context errors do not match because resource has different namespace")
|
|
||||||
}
|
|
||||||
ctx = genericapirequest.NewContext()
|
|
||||||
if api.ValidNamespace(ctx, &resource.ObjectMeta) {
|
|
||||||
t.Fatalf("Expected error that resource and context errors do not match since context has no namespace")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = genericapirequest.NewContext()
|
|
||||||
ns := genericapirequest.NamespaceValue(ctx)
|
|
||||||
if ns != "" {
|
|
||||||
t.Fatalf("Expected the empty string")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TestUserContext validates that a userinfo can be get/set on a context object
|
//TestUserContext validates that a userinfo can be get/set on a context object
|
||||||
func TestUserContext(t *testing.T) {
|
func TestUserContext(t *testing.T) {
|
||||||
ctx := genericapirequest.NewContext()
|
ctx := genericapirequest.NewContext()
|
||||||
|
@ -381,7 +381,7 @@ func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.
|
|||||||
}
|
}
|
||||||
|
|
||||||
service := obj.(*api.Service)
|
service := obj.(*api.Service)
|
||||||
if !api.ValidNamespace(ctx, &service.ObjectMeta) {
|
if !rest.ValidNamespace(ctx, &service.ObjectMeta) {
|
||||||
return nil, false, errors.NewConflict(api.Resource("services"), service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
|
return nil, false, errors.NewConflict(api.Resource("services"), service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user