From e7a76d14f07fd8c66ac7fbb2d542f13644f99b4e Mon Sep 17 00:00:00 2001 From: Michael Bolot Date: Tue, 2 Jul 2024 13:27:04 -0500 Subject: [PATCH] Adding APIGroups back to the schema Prior schema calculations started with openapiv2 models which included a model for APIGroups. However, new schema calculations use ServerGroupsAndResources first, which omitted these values. This re-adds this type using a static schema. --- pkg/resources/apigroups/apigroup.go | 12 ++++ pkg/schema/converter/k8stonorman.go | 11 +++ pkg/schema/converter/k8stonorman_test.go | 88 ++++++++++++++++-------- 3 files changed, 84 insertions(+), 27 deletions(-) diff --git a/pkg/resources/apigroups/apigroup.go b/pkg/resources/apigroups/apigroup.go index 5bc00825..d40358f6 100644 --- a/pkg/resources/apigroups/apigroup.go +++ b/pkg/resources/apigroups/apigroup.go @@ -7,10 +7,22 @@ import ( "github.com/rancher/apiserver/pkg/store/empty" "github.com/rancher/apiserver/pkg/types" + wschemas "github.com/rancher/wrangler/v3/pkg/schemas" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/discovery" ) +var BaseSchema = types.APISchema{ + Schema: &wschemas.Schema{ + ID: "apigroup", + Attributes: map[string]interface{}{ + "group": "", + "kind": "APIGroup", + "version": "v1", + }, + }, +} + func Template(discovery discovery.DiscoveryInterface) schema.Template { return schema.Template{ ID: "apigroup", diff --git a/pkg/schema/converter/k8stonorman.go b/pkg/schema/converter/k8stonorman.go index 81c65da9..c9d19096 100644 --- a/pkg/schema/converter/k8stonorman.go +++ b/pkg/schema/converter/k8stonorman.go @@ -8,6 +8,8 @@ import ( "github.com/rancher/apiserver/pkg/types" "github.com/rancher/norman/types/convert" + "github.com/rancher/steve/pkg/attributes" + "github.com/rancher/steve/pkg/resources/apigroups" v1 "github.com/rancher/wrangler/v3/pkg/generated/controllers/apiextensions.k8s.io/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/discovery" @@ -82,6 +84,8 @@ func GetGVKForKind(kind *proto.Kind) *schema.GroupVersionKind { func ToSchemas(crd v1.CustomResourceDefinitionClient, client discovery.DiscoveryInterface) (map[string]*types.APISchema, error) { result := map[string]*types.APISchema{} + addTemplateBased(result) + if err := addDiscovery(client, result); err != nil { return nil, err } @@ -96,3 +100,10 @@ func ToSchemas(crd v1.CustomResourceDefinitionClient, client discovery.Discovery return result, nil } + +// some schemas are not based on real resources but are filled-in by a template later on. This function adds the base +// schema so that these endpoints are still recognizable in the api +func addTemplateBased(schemas map[string]*types.APISchema) { + apiGroupGVK := attributes.GVK(&apigroups.BaseSchema) + schemas[GVKToVersionedSchemaID(apiGroupGVK)] = &apigroups.BaseSchema +} diff --git a/pkg/schema/converter/k8stonorman_test.go b/pkg/schema/converter/k8stonorman_test.go index 18313765..7d11de89 100644 --- a/pkg/schema/converter/k8stonorman_test.go +++ b/pkg/schema/converter/k8stonorman_test.go @@ -7,6 +7,7 @@ import ( "github.com/golang/mock/gomock" openapiv2 "github.com/google/gnostic-models/openapiv2" "github.com/rancher/apiserver/pkg/types" + "github.com/rancher/steve/pkg/resources/apigroups" "github.com/rancher/steve/pkg/schema/table" "github.com/rancher/wrangler/v3/pkg/generic/fake" wranglerSchema "github.com/rancher/wrangler/v3/pkg/schemas" @@ -20,34 +21,51 @@ import ( ) func TestToSchemas(t *testing.T) { - gvkExtensionMap := map[any]any{ - gvkExtensionGroup: "TestGroup", - gvkExtensionVersion: "v1", - gvkExtensionKind: "TestResource", - } - gvkExtensionSlice := []any{gvkExtensionMap} - extensionSliceYaml, err := yaml.Marshal(gvkExtensionSlice) - require.NoError(t, err) - gvkSchema := openapiv2.NamedSchema{ - Name: "TestResources", - Value: &openapiv2.Schema{ - Description: "TestResources are test resource created for unit tests", - Type: &openapiv2.TypeItem{ - Value: []string{"object"}, - }, - Properties: &openapiv2.Properties{ - AdditionalProperties: []*openapiv2.NamedSchema{}, - }, - VendorExtension: []*openapiv2.NamedAny{ - { - Name: gvkExtensionName, - Value: &openapiv2.Any{ - Yaml: string(extensionSliceYaml), + createNamedSchema := func(name string, description string, gvk schema.GroupVersionKind) (*openapiv2.NamedSchema, error) { + gvkExtensionMap := map[any]any{ + gvkExtensionGroup: gvk.Group, + gvkExtensionVersion: gvk.Version, + gvkExtensionKind: gvk.Kind, + } + gvkExtensionSlice := []any{gvkExtensionMap} + extensionSliceYaml, err := yaml.Marshal(gvkExtensionSlice) + if err != nil { + return nil, fmt.Errorf("unable to create named schema for %s: %w", name, err) + } + return &openapiv2.NamedSchema{ + Name: name, + Value: &openapiv2.Schema{ + Description: description, + Type: &openapiv2.TypeItem{ + Value: []string{"object"}, + }, + Properties: &openapiv2.Properties{ + AdditionalProperties: []*openapiv2.NamedSchema{}, + }, + VendorExtension: []*openapiv2.NamedAny{ + { + Name: gvkExtensionName, + Value: &openapiv2.Any{ + Yaml: string(extensionSliceYaml), + }, }, }, }, - }, + }, nil } + apiGroupDescription := "APIGroup contains the name, the supported versions, and the preferred version of a group" + gvkSchema, err := createNamedSchema("TestResources", "TestResources are test resource created for unit tests", schema.GroupVersionKind{ + Group: "TestGroup", + Version: "v1", + Kind: "TestResource", + }) + require.NoError(t, err) + apiGroupSchema, err := createNamedSchema("ApiGroups", apiGroupDescription, schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "APIGroup", + }) + require.NoError(t, err) tests := []struct { name string groups []schema.GroupVersion @@ -160,6 +178,7 @@ func TestToSchemas(t *testing.T) { Description: "Test Resource for unit tests", }, }, + "core.v1.apigroup": &apigroups.BaseSchema, }, }, { @@ -194,6 +213,7 @@ func TestToSchemas(t *testing.T) { }, }, }, + "core.v1.apigroup": &apigroups.BaseSchema, }, }, { @@ -260,8 +280,10 @@ func TestToSchemas(t *testing.T) { }, }, }, - wantError: false, - desiredSchema: map[string]*types.APISchema{}, + wantError: false, + desiredSchema: map[string]*types.APISchema{ + "core.v1.apigroup": &apigroups.BaseSchema, + }, }, { name: "discovery error", @@ -305,6 +327,7 @@ func TestToSchemas(t *testing.T) { }, }, }, + "core.v1.apigroup": &apigroups.BaseSchema, }, }, { @@ -326,7 +349,7 @@ func TestToSchemas(t *testing.T) { crds: []v1.CustomResourceDefinition{}, document: &openapiv2.Document{ Definitions: &openapiv2.Definitions{ - AdditionalProperties: []*openapiv2.NamedSchema{&gvkSchema}, + AdditionalProperties: []*openapiv2.NamedSchema{gvkSchema, apiGroupSchema}, }, }, wantError: false, @@ -346,6 +369,17 @@ func TestToSchemas(t *testing.T) { }, }, }, + "core.v1.apigroup": { + Schema: &wranglerSchema.Schema{ + ID: "apigroup", + Attributes: map[string]interface{}{ + "group": "", + "kind": "APIGroup", + "version": "v1", + }, + Description: apiGroupDescription, + }, + }, }, }, {