mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
Add Categories to CRD spec
We can group custom resources into categories i.e. use them with kubectl get all.
This commit is contained in:
parent
da564ef4fb
commit
e7341f4deb
@ -49,6 +49,9 @@ type CustomResourceDefinitionNames struct {
|
||||
Kind string
|
||||
// ListKind is the serialized kind of the list for this resource. Defaults to <kind>List.
|
||||
ListKind string
|
||||
// Categories is a list of grouped resources custom resources belong to (e.g. 'all')
|
||||
// +optional
|
||||
Categories []string
|
||||
}
|
||||
|
||||
// ResourceScope is an enum defining the different scopes available to a custom resource
|
||||
|
@ -53,6 +53,9 @@ type CustomResourceDefinitionNames struct {
|
||||
Kind string `json:"kind" protobuf:"bytes,4,opt,name=kind"`
|
||||
// ListKind is the serialized kind of the list for this resource. Defaults to <kind>List.
|
||||
ListKind string `json:"listKind,omitempty" protobuf:"bytes,5,opt,name=listKind"`
|
||||
// Categories is a list of grouped resources custom resources belong to (e.g. 'all')
|
||||
// +optional
|
||||
Categories []string `json:"categories,omitempty" protobuf:"bytes,6,rep,name=categories"`
|
||||
}
|
||||
|
||||
// ResourceScope is an enum defining the different scopes available to a custom resource
|
||||
|
@ -165,7 +165,6 @@ func ValidateCustomResourceDefinitionNames(names *apiextensions.CustomResourceDe
|
||||
if errs := validationutil.IsDNS1035Label(shortName); len(errs) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("shortNames").Index(i), shortName, strings.Join(errs, ",")))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// kind and listKind may not be the same or parsing become ambiguous
|
||||
@ -173,6 +172,12 @@ func ValidateCustomResourceDefinitionNames(names *apiextensions.CustomResourceDe
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("listKind"), names.ListKind, "kind and listKind may not be the same"))
|
||||
}
|
||||
|
||||
for i, category := range names.Categories {
|
||||
if errs := validationutil.IsDNS1035Label(category); len(errs) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("categories").Index(i), category, strings.Join(errs, ",")))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
|
||||
Kind: crd.Status.AcceptedNames.Kind,
|
||||
Verbs: verbs,
|
||||
ShortNames: crd.Status.AcceptedNames.ShortNames,
|
||||
Categories: crd.Status.AcceptedNames.Categories,
|
||||
})
|
||||
|
||||
if crd.Spec.Subresources != nil && crd.Spec.Subresources.Status != nil {
|
||||
|
@ -459,7 +459,7 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
|
||||
statusSpec,
|
||||
scaleSpec,
|
||||
),
|
||||
r.restOptionsGetter,
|
||||
r.restOptionsGetter, crd.Status.AcceptedNames.Categories,
|
||||
)
|
||||
|
||||
selfLinkPrefix := ""
|
||||
|
@ -182,6 +182,8 @@ func (c *NamingConditionController) calculateNamesAndConditions(in *apiextension
|
||||
newNames.ListKind = requestedNames.ListKind
|
||||
}
|
||||
|
||||
newNames.Categories = requestedNames.Categories
|
||||
|
||||
// if we haven't changed the condition, then our names must be good.
|
||||
if namesAcceptedCondition.Status == apiextensions.ConditionUnknown {
|
||||
namesAcceptedCondition.Status = apiextensions.ConditionTrue
|
||||
|
@ -39,8 +39,8 @@ type CustomResourceStorage struct {
|
||||
Scale *ScaleREST
|
||||
}
|
||||
|
||||
func NewStorage(resource schema.GroupResource, listKind schema.GroupVersionKind, strategy customResourceStrategy, optsGetter generic.RESTOptionsGetter) CustomResourceStorage {
|
||||
customResourceREST, customResourceStatusREST := newREST(resource, listKind, strategy, optsGetter)
|
||||
func NewStorage(resource schema.GroupResource, listKind schema.GroupVersionKind, strategy customResourceStrategy, optsGetter generic.RESTOptionsGetter, categories []string) CustomResourceStorage {
|
||||
customResourceREST, customResourceStatusREST := newREST(resource, listKind, strategy, optsGetter, categories)
|
||||
customResourceRegistry := NewRegistry(customResourceREST)
|
||||
|
||||
s := CustomResourceStorage{
|
||||
@ -71,10 +71,11 @@ func NewStorage(resource schema.GroupResource, listKind schema.GroupVersionKind,
|
||||
// REST implements a RESTStorage for API services against etcd
|
||||
type REST struct {
|
||||
*genericregistry.Store
|
||||
categories []string
|
||||
}
|
||||
|
||||
// newREST returns a RESTStorage object that will work against API services.
|
||||
func newREST(resource schema.GroupResource, listKind schema.GroupVersionKind, strategy customResourceStrategy, optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST) {
|
||||
func newREST(resource schema.GroupResource, listKind schema.GroupVersionKind, strategy customResourceStrategy, optsGetter generic.RESTOptionsGetter, categories []string) (*REST, *StatusREST) {
|
||||
store := &genericregistry.Store{
|
||||
NewFunc: func() runtime.Object { return &unstructured.Unstructured{} },
|
||||
NewListFunc: func() runtime.Object {
|
||||
@ -97,7 +98,15 @@ func newREST(resource schema.GroupResource, listKind schema.GroupVersionKind, st
|
||||
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = NewStatusStrategy(strategy)
|
||||
return &REST{store}, &StatusREST{store: &statusStore}
|
||||
return &REST{store, categories}, &StatusREST{store: &statusStore}
|
||||
}
|
||||
|
||||
// Implement CategoriesProvider
|
||||
var _ rest.CategoriesProvider = &REST{}
|
||||
|
||||
// Categories implements the CategoriesProvider interface. Returns a list of categories a resource is part of.
|
||||
func (r *REST) Categories() []string {
|
||||
return r.categories
|
||||
}
|
||||
|
||||
// StatusREST implements the REST endpoint for changing the status of a CustomResource
|
||||
|
@ -18,6 +18,7 @@ package customresource_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -82,7 +83,7 @@ func newStorage(t *testing.T) (customresource.CustomResourceStorage, *etcdtestin
|
||||
status,
|
||||
scale,
|
||||
),
|
||||
restOptions,
|
||||
restOptions, []string{"all"},
|
||||
)
|
||||
|
||||
return storage, server
|
||||
@ -153,6 +154,19 @@ func TestDelete(t *testing.T) {
|
||||
test.TestDelete(validNewCustomResource())
|
||||
}
|
||||
|
||||
func TestCategories(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.CustomResource.Store.DestroyFunc()
|
||||
|
||||
expected := []string{"all"}
|
||||
actual := storage.CustomResource.Categories()
|
||||
ok := reflect.DeepEqual(actual, expected)
|
||||
if !ok {
|
||||
t.Errorf("categories are not equal. expected = %v actual = %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusUpdate(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
|
@ -388,6 +388,10 @@ func TestDiscovery(t *testing.T) {
|
||||
if !reflect.DeepEqual([]string(r.Verbs), expectedVerbs) {
|
||||
t.Fatalf("Unexpected verbs for resource \"noxus\" in group version %v/%v via discovery: expected=%v got=%v", group, version, expectedVerbs, r.Verbs)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(r.Categories, []string{"all"}) {
|
||||
t.Fatalf("Expected exactly the category \"all\" in group version %v/%v via discovery, got: %v", group, version, r.Categories)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoNamespaceReject(t *testing.T) {
|
||||
|
@ -72,6 +72,7 @@ func NewNoxuCustomResourceDefinition(scope apiextensionsv1beta1.ResourceScope) *
|
||||
Kind: "WishIHadChosenNoxu",
|
||||
ShortNames: []string{"foo", "bar", "abc", "def"},
|
||||
ListKind: "NoxuItemList",
|
||||
Categories: []string{"all"},
|
||||
},
|
||||
Scope: scope,
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user