mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-11 04:52:08 +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/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"))
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user