mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Split pkg/genericapiserver/api/request from ObjectMeta
This commit is contained in:
		@@ -22,23 +22,8 @@ import (
 | 
			
		||||
	"k8s.io/apimachinery/pkg/conversion"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
	"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.
 | 
			
		||||
func HasObjectMetaSystemFieldValues(meta *ObjectMeta) bool {
 | 
			
		||||
	return !meta.CreationTimestamp.Time.IsZero() ||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,45 +28,10 @@ import (
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
	genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&objectMeta)
 | 
			
		||||
	references := objectMeta.OwnerReferences
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,6 @@ import (
 | 
			
		||||
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/resource"
 | 
			
		||||
	genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Returns string version of ResourceName.
 | 
			
		||||
@@ -228,13 +227,3 @@ func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, li
 | 
			
		||||
	}
 | 
			
		||||
	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/errors"
 | 
			
		||||
	"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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +61,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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")
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -70,7 +70,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob
 | 
			
		||||
	objectMeta.DeletionTimestamp = nil
 | 
			
		||||
	objectMeta.DeletionGracePeriodSeconds = nil
 | 
			
		||||
	strategy.PrepareForCreate(ctx, obj)
 | 
			
		||||
	api.FillObjectMetaSystemFields(ctx, objectMeta)
 | 
			
		||||
	FillObjectMetaSystemFields(ctx, objectMeta)
 | 
			
		||||
	api.GenerateName(strategy, objectMeta)
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
	}
 | 
			
		||||
	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")
 | 
			
		||||
		}
 | 
			
		||||
	} 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
 | 
			
		||||
func TestUserContext(t *testing.T) {
 | 
			
		||||
	ctx := genericapirequest.NewContext()
 | 
			
		||||
 
 | 
			
		||||
@@ -381,7 +381,7 @@ func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user