Introducing a cluster-scoped resource in the wardle.k8s.io group.

The cluster scoped resource has a field that indicates Flunder.Names that are disallowed.
The resource is going to be used by an admission plugin.
The admission plugin will list the cluster-scope resources and check against banned names.

Issue: #47868
pull/6/head
p0lyn0mial 2017-07-03 18:56:56 +02:00
parent 33fc75e223
commit 113e9ba1d3
19 changed files with 459 additions and 57 deletions

View File

@ -30,7 +30,7 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r
if err := announced.NewGroupMetaFactory(
&announced.GroupMetaFactoryArgs{
GroupName: wardle.GroupName,
RootScopedKinds: sets.NewString("APIService"),
RootScopedKinds: sets.NewString("Fischer", "FischerList"),
VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version},
ImportPrefix: "k8s.io/sample-apiserver/pkg/apis/wardle",
AddInternalObjectsToScheme: wardle.AddToScheme,

View File

@ -46,6 +46,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Flunder{},
&FlunderList{},
&Fischer{},
&FischerList{},
)
return nil
}

View File

@ -41,3 +41,26 @@ type Flunder struct {
Spec FlunderSpec
Status FlunderStatus
}
// +genclient=true
// +nonNamespaced=true
type Fischer struct {
metav1.TypeMeta
metav1.ObjectMeta
// DisallowedFlunders holds a list of Flunder.Names that are disallowed.
DisallowedFlunders []string
}
// +genclient=true
// +nonNamespaced=true
// FischerList is a list of Fischer objects.
type FischerList struct {
metav1.TypeMeta
metav1.ListMeta
// Items is a list of Fischers
Items []Fischer
}

View File

@ -47,6 +47,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Flunder{},
&FlunderList{},
&Fischer{},
&FischerList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View File

@ -41,3 +41,25 @@ type Flunder struct {
Spec FlunderSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
Status FlunderStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
// +genclient=true
// +nonNamespaced=true
type Fischer struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// DisallowedFlunders holds a list of Flunder.Names that are disallowed.
DisallowedFlunders []string `json:"disallowedFlunders,omitempty" protobuf:"bytes,2,rep,name=disallowedFlunders"`
}
// +genclient=true
// +nonNamespaced=true
// FischerList is a list of Fischer objects.
type FischerList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []Fischer `json:"items" protobuf:"bytes,2,rep,name=items"`
}

View File

@ -35,6 +35,10 @@ func init() {
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_Fischer_To_wardle_Fischer,
Convert_wardle_Fischer_To_v1alpha1_Fischer,
Convert_v1alpha1_FischerList_To_wardle_FischerList,
Convert_wardle_FischerList_To_v1alpha1_FischerList,
Convert_v1alpha1_Flunder_To_wardle_Flunder,
Convert_wardle_Flunder_To_v1alpha1_Flunder,
Convert_v1alpha1_FlunderList_To_wardle_FlunderList,
@ -46,6 +50,54 @@ func RegisterConversions(scheme *runtime.Scheme) error {
)
}
func autoConvert_v1alpha1_Fischer_To_wardle_Fischer(in *Fischer, out *wardle.Fischer, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
out.DisallowedFlunders = *(*[]string)(unsafe.Pointer(&in.DisallowedFlunders))
return nil
}
// Convert_v1alpha1_Fischer_To_wardle_Fischer is an autogenerated conversion function.
func Convert_v1alpha1_Fischer_To_wardle_Fischer(in *Fischer, out *wardle.Fischer, s conversion.Scope) error {
return autoConvert_v1alpha1_Fischer_To_wardle_Fischer(in, out, s)
}
func autoConvert_wardle_Fischer_To_v1alpha1_Fischer(in *wardle.Fischer, out *Fischer, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
out.DisallowedFlunders = *(*[]string)(unsafe.Pointer(&in.DisallowedFlunders))
return nil
}
// Convert_wardle_Fischer_To_v1alpha1_Fischer is an autogenerated conversion function.
func Convert_wardle_Fischer_To_v1alpha1_Fischer(in *wardle.Fischer, out *Fischer, s conversion.Scope) error {
return autoConvert_wardle_Fischer_To_v1alpha1_Fischer(in, out, s)
}
func autoConvert_v1alpha1_FischerList_To_wardle_FischerList(in *FischerList, out *wardle.FischerList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
out.Items = *(*[]wardle.Fischer)(unsafe.Pointer(&in.Items))
return nil
}
// Convert_v1alpha1_FischerList_To_wardle_FischerList is an autogenerated conversion function.
func Convert_v1alpha1_FischerList_To_wardle_FischerList(in *FischerList, out *wardle.FischerList, s conversion.Scope) error {
return autoConvert_v1alpha1_FischerList_To_wardle_FischerList(in, out, s)
}
func autoConvert_wardle_FischerList_To_v1alpha1_FischerList(in *wardle.FischerList, out *FischerList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
if in.Items == nil {
out.Items = make([]Fischer, 0)
} else {
out.Items = *(*[]Fischer)(unsafe.Pointer(&in.Items))
}
return nil
}
// Convert_wardle_FischerList_To_v1alpha1_FischerList is an autogenerated conversion function.
func Convert_wardle_FischerList_To_v1alpha1_FischerList(in *wardle.FischerList, out *FischerList, s conversion.Scope) error {
return autoConvert_wardle_FischerList_To_v1alpha1_FischerList(in, out, s)
}
func autoConvert_v1alpha1_Flunder_To_wardle_Flunder(in *Flunder, out *wardle.Flunder, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(&in.Spec, &out.Spec, s); err != nil {

View File

@ -35,6 +35,8 @@ func init() {
// to allow building arbitrary schemes.
func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_Fischer, InType: reflect.TypeOf(&Fischer{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FischerList, InType: reflect.TypeOf(&FischerList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_Flunder, InType: reflect.TypeOf(&Flunder{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FlunderList, InType: reflect.TypeOf(&FlunderList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FlunderSpec, InType: reflect.TypeOf(&FlunderSpec{})},
@ -42,6 +44,47 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
)
}
// DeepCopy_v1alpha1_Fischer is an autogenerated deepcopy function.
func DeepCopy_v1alpha1_Fischer(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*Fischer)
out := out.(*Fischer)
*out = *in
if newVal, err := c.DeepCopy(&in.ObjectMeta); err != nil {
return err
} else {
out.ObjectMeta = *newVal.(*v1.ObjectMeta)
}
if in.DisallowedFlunders != nil {
in, out := &in.DisallowedFlunders, &out.DisallowedFlunders
*out = make([]string, len(*in))
copy(*out, *in)
}
return nil
}
}
// DeepCopy_v1alpha1_FischerList is an autogenerated deepcopy function.
func DeepCopy_v1alpha1_FischerList(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*FischerList)
out := out.(*FischerList)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Fischer, len(*in))
for i := range *in {
if newVal, err := c.DeepCopy(&(*in)[i]); err != nil {
return err
} else {
(*out)[i] = *newVal.(*Fischer)
}
}
}
return nil
}
}
// DeepCopy_v1alpha1_Flunder is an autogenerated deepcopy function.
func DeepCopy_v1alpha1_Flunder(in interface{}, out interface{}, c *conversion.Cloner) error {
{

View File

@ -35,6 +35,8 @@ func init() {
// to allow building arbitrary schemes.
func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_Fischer, InType: reflect.TypeOf(&Fischer{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FischerList, InType: reflect.TypeOf(&FischerList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_Flunder, InType: reflect.TypeOf(&Flunder{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FlunderList, InType: reflect.TypeOf(&FlunderList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FlunderSpec, InType: reflect.TypeOf(&FlunderSpec{})},
@ -42,6 +44,47 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
)
}
// DeepCopy_wardle_Fischer is an autogenerated deepcopy function.
func DeepCopy_wardle_Fischer(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*Fischer)
out := out.(*Fischer)
*out = *in
if newVal, err := c.DeepCopy(&in.ObjectMeta); err != nil {
return err
} else {
out.ObjectMeta = *newVal.(*v1.ObjectMeta)
}
if in.DisallowedFlunders != nil {
in, out := &in.DisallowedFlunders, &out.DisallowedFlunders
*out = make([]string, len(*in))
copy(*out, *in)
}
return nil
}
}
// DeepCopy_wardle_FischerList is an autogenerated deepcopy function.
func DeepCopy_wardle_FischerList(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*FischerList)
out := out.(*FischerList)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Fischer, len(*in))
for i := range *in {
if newVal, err := c.DeepCopy(&(*in)[i]); err != nil {
return err
} else {
(*out)[i] = *newVal.(*Fischer)
}
}
}
return nil
}
}
// DeepCopy_wardle_Flunder is an autogenerated deepcopy function.
func DeepCopy_wardle_Flunder(in interface{}, out interface{}, c *conversion.Cloner) error {
{

View File

@ -33,6 +33,7 @@ go_library(
"//vendor/k8s.io/sample-apiserver/pkg/apis/wardle:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/apis/wardle/install:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/registry/wardle:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/registry/wardle/fischer:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/registry/wardle/flunder:go_default_library",
],
)

View File

@ -30,7 +30,8 @@ import (
"k8s.io/sample-apiserver/pkg/apis/wardle"
"k8s.io/sample-apiserver/pkg/apis/wardle/install"
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
wardlestorage "k8s.io/sample-apiserver/pkg/registry/wardle"
fischerstorage "k8s.io/sample-apiserver/pkg/registry/wardle/fischer"
flunderstorage "k8s.io/sample-apiserver/pkg/registry/wardle/flunder"
)
var (
@ -102,7 +103,8 @@ func (c completedConfig) New() (*WardleServer, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(wardle.GroupName, registry, Scheme, metav1.ParameterCodec, Codecs)
apiGroupInfo.GroupMeta.GroupVersion = v1alpha1.SchemeGroupVersion
v1alpha1storage := map[string]rest.Storage{}
v1alpha1storage["flunders"] = wardlestorage.NewREST(Scheme, c.GenericConfig.RESTOptionsGetter)
v1alpha1storage["flunders"] = flunderstorage.RESTInPeace(Scheme, c.GenericConfig.RESTOptionsGetter)
v1alpha1storage["fischers"] = fischerstorage.RESTInPeace(Scheme, c.GenericConfig.RESTOptionsGetter)
apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage
if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil {

View File

@ -0,0 +1,15 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["registry.go"],
tags = ["automanaged"],
deps = ["//vendor/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library"],
)

View File

@ -0,0 +1,24 @@
/*
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 registry
import genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
// rest implements a RESTStorage for API services against etcd
type REST struct {
*genericregistry.Store
}

View File

@ -25,5 +25,6 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/storage:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/apis/wardle:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/registry:go_default_library",
],
)

View File

@ -0,0 +1,50 @@
/*
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 fischer
import (
"fmt"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/generic"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/sample-apiserver/pkg/apis/wardle"
"k8s.io/sample-apiserver/pkg/registry"
)
// RESTInPeace returns a RESTStorage object that will work against API services.
func RESTInPeace(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *registry.REST {
strategy := NewStrategy(scheme)
store := &genericregistry.Store{
Copier: scheme,
NewFunc: func() runtime.Object { return &wardle.Fischer{} },
NewListFunc: func() runtime.Object { return &wardle.FischerList{} },
PredicateFunc: MatchFischer,
QualifiedResource: wardle.Resource("fischers"),
CreateStrategy: strategy,
UpdateStrategy: strategy,
DeleteStrategy: strategy,
}
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs}
if err := store.CompleteWithOptions(options); err != nil {
err = fmt.Errorf("Unable to create REST storage for fischer resource due to %v. Committing suicide.", err)
panic(err)
}
return &registry.REST{store}
}

View File

@ -0,0 +1,93 @@
/*
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 fischer
import (
"fmt"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/storage"
"k8s.io/apiserver/pkg/storage/names"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/sample-apiserver/pkg/apis/wardle"
)
func NewStrategy(typer runtime.ObjectTyper) fischerStrategy {
return fischerStrategy{typer, names.SimpleNameGenerator}
}
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) {
apiserver, ok := obj.(*wardle.Fischer)
if !ok {
return nil, nil, false, fmt.Errorf("given object is not a Fischer.")
}
return labels.Set(apiserver.ObjectMeta.Labels), fischerToSelectableFields(apiserver), apiserver.Initializers != nil, nil
}
// MatchFischer is the filter used by the generic etcd backend to watch events
// from etcd to clients of the apiserver only interested in specific labels/fields.
func MatchFischer(label labels.Selector, field fields.Selector) storage.SelectionPredicate {
return storage.SelectionPredicate{
Label: label,
Field: field,
GetAttrs: GetAttrs,
}
}
// fischerToSelectableFields returns a field set that represents the object.
func fischerToSelectableFields(obj *wardle.Fischer) fields.Set {
return generic.ObjectMetaFieldsSet(&obj.ObjectMeta, true)
}
type fischerStrategy struct {
runtime.ObjectTyper
names.NameGenerator
}
func (fischerStrategy) NamespaceScoped() bool {
return false
}
func (fischerStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) {
}
func (fischerStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) {
}
func (fischerStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
return field.ErrorList{}
}
func (fischerStrategy) AllowCreateOnUpdate() bool {
return false
}
func (fischerStrategy) AllowUnconditionalUpdate() bool {
return false
}
func (fischerStrategy) Canonicalize(obj runtime.Object) {
}
func (fischerStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList {
return field.ErrorList{}
}

View File

@ -0,0 +1,30 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"etcd.go",
"strategy.go",
],
tags = ["automanaged"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/apis/wardle:go_default_library",
"//vendor/k8s.io/sample-apiserver/pkg/registry:go_default_library",
],
)

View File

@ -14,22 +14,20 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package wardle
package flunder
import (
"fmt"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/generic"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/sample-apiserver/pkg/apis/wardle"
"k8s.io/sample-apiserver/pkg/registry"
)
// rest implements a RESTStorage for API services against etcd
type REST struct {
*genericregistry.Store
}
// NewREST returns a RESTStorage object that will work against API services.
func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST {
// RESTInPeace returns a RESTStorage object that will work against API services.
func RESTInPeace(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *registry.REST {
strategy := NewStrategy(scheme)
store := &genericregistry.Store{
@ -45,7 +43,8 @@ func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST
}
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs}
if err := store.CompleteWithOptions(options); err != nil {
panic(err) // TODO: Propagate error up
err = fmt.Errorf("Unable to create REST storage for flunder resource due to %v. Committing suicide.", err)
panic(err)
}
return &REST{store}
return &registry.REST{store}
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package wardle
package flunder
import (
"fmt"
@ -23,52 +23,16 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/storage"
"k8s.io/apiserver/pkg/storage/names"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/sample-apiserver/pkg/apis/wardle"
)
type apiServerStrategy struct {
runtime.ObjectTyper
names.NameGenerator
}
func NewStrategy(typer runtime.ObjectTyper) apiServerStrategy {
return apiServerStrategy{typer, names.SimpleNameGenerator}
}
func (apiServerStrategy) NamespaceScoped() bool {
return false
}
func (apiServerStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) {
}
func (apiServerStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) {
}
func (apiServerStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
return field.ErrorList{}
// return validation.ValidateFlunder(obj.(*wardle.Flunder))
}
func (apiServerStrategy) AllowCreateOnUpdate() bool {
return false
}
func (apiServerStrategy) AllowUnconditionalUpdate() bool {
return false
}
func (apiServerStrategy) Canonicalize(obj runtime.Object) {
}
func (apiServerStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList {
return field.ErrorList{}
// return validation.ValidateFlunderUpdate(obj.(*wardle.Flunder), old.(*wardle.Flunder))
func NewStrategy(typer runtime.ObjectTyper) flunderStrategy {
return flunderStrategy{typer, names.SimpleNameGenerator}
}
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) {
@ -93,3 +57,37 @@ func MatchFlunder(label labels.Selector, field fields.Selector) storage.Selectio
func FlunderToSelectableFields(obj *wardle.Flunder) fields.Set {
return generic.ObjectMetaFieldsSet(&obj.ObjectMeta, true)
}
type flunderStrategy struct {
runtime.ObjectTyper
names.NameGenerator
}
func (flunderStrategy) NamespaceScoped() bool {
return false
}
func (flunderStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) {
}
func (flunderStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) {
}
func (flunderStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
return field.ErrorList{}
}
func (flunderStrategy) AllowCreateOnUpdate() bool {
return false
}
func (flunderStrategy) AllowUnconditionalUpdate() bool {
return false
}
func (flunderStrategy) Canonicalize(obj runtime.Object) {
}
func (flunderStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList {
return field.ErrorList{}
}

View File

@ -448,9 +448,11 @@ func testAPIResourceList(t *testing.T, client rest.Interface) {
t.Fatalf("Error in unmarshalling response from server %s: %v", "/apis/wardle.k8s.io/v1alpha1", err)
}
assert.Equal(t, groupVersion.String(), apiResourceList.GroupVersion)
assert.Equal(t, 1, len(apiResourceList.APIResources))
assert.Equal(t, "flunders", apiResourceList.APIResources[0].Name)
assert.True(t, apiResourceList.APIResources[0].Namespaced)
assert.Equal(t, 2, len(apiResourceList.APIResources))
assert.Equal(t, "fischers", apiResourceList.APIResources[0].Name)
assert.False(t, apiResourceList.APIResources[0].Namespaced)
assert.Equal(t, "flunders", apiResourceList.APIResources[1].Name)
assert.True(t, apiResourceList.APIResources[1].Namespaced)
}
const (