From f7f5112787685f66dfd9f1f904859d2d78df66a5 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 23 Nov 2024 02:59:39 +0100 Subject: [PATCH 1/2] Fix OpenAPIv2 definitions for dynamic resources --- packages/system/cozystack-api/values.yaml | 2 +- pkg/apis/apps/v1alpha1/register.go | 6 +- pkg/apiserver/apiserver.go | 7 -- pkg/cmd/server/start.go | 86 +++++++++++++++++++++++ 4 files changed, 92 insertions(+), 9 deletions(-) diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 8918555f..403ee10e 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,2 @@ cozystackAPI: - image: ghcr.io/aenix-io/cozystack/cozystack-api:v0.18.0@sha256:d3f817ee20cc502b7c5deffa46a1ad94a6e1a74fa035dbeb65ef742e67fd1fe5 + image: ghcr.io/aenix-io/cozystack/cozystack-api:latest@sha256:96d277a34aff6d9847251da521ca86615af2aae370ec095d046112bc4044ddea diff --git a/pkg/apis/apps/v1alpha1/register.go b/pkg/apis/apps/v1alpha1/register.go index dc48a612..ea5ae605 100644 --- a/pkg/apis/apps/v1alpha1/register.go +++ b/pkg/apis/apps/v1alpha1/register.go @@ -28,6 +28,10 @@ import ( // GroupName holds the API group name. const GroupName = "apps.cozystack.io" +var ( + RegisteredGVKs []schema.GroupVersionKind +) + // SchemeGroupVersion is group version used to register these objects var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} @@ -70,7 +74,7 @@ func RegisterDynamicTypes(scheme *runtime.Scheme, cfg *config.ResourceConfig) er scheme.AddKnownTypeWithName(gvk.GroupVersion().WithKind(kind+"List"), &ApplicationList{}) log.Printf("Registered kind: %s\n", kind) - + RegisteredGVKs = append(RegisteredGVKs, gvk) } return nil diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index f5fbe4b7..aa8ec349 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -31,7 +31,6 @@ import ( "github.com/aenix.io/cozystack/pkg/apis/apps" "github.com/aenix.io/cozystack/pkg/apis/apps/install" - appsv1alpha1 "github.com/aenix.io/cozystack/pkg/apis/apps/v1alpha1" "github.com/aenix.io/cozystack/pkg/config" appsregistry "github.com/aenix.io/cozystack/pkg/registry" applicationstorage "github.com/aenix.io/cozystack/pkg/registry/apps/application" @@ -112,12 +111,6 @@ func (c completedConfig) New() (*AppsServer, error) { apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apps.GroupName, Scheme, metav1.ParameterCodec, Codecs) - // Dynamically register types based on the configuration. - err = appsv1alpha1.RegisterDynamicTypes(Scheme, c.ResourceConfig) - if err != nil { - return nil, fmt.Errorf("failed to register dynamic types: %v", err) - } - // Create a dynamic client for HelmRelease using InClusterConfig. inClusterConfig, err := restclient.InClusterConfig() if err != nil { diff --git a/pkg/cmd/server/start.go b/pkg/cmd/server/start.go index 8cc910ee..70472aed 100644 --- a/pkg/cmd/server/start.go +++ b/pkg/cmd/server/start.go @@ -18,6 +18,7 @@ package server import ( "context" + "encoding/json" "fmt" "io" "net" @@ -37,6 +38,7 @@ import ( utilversionpkg "k8s.io/apiserver/pkg/util/version" "k8s.io/component-base/featuregate" baseversion "k8s.io/component-base/version" + "k8s.io/kube-openapi/pkg/validation/spec" netutils "k8s.io/utils/net" ) @@ -156,6 +158,22 @@ func (o AppsServerOptions) Validate(args []string) error { return utilerrors.NewAggregate(allErrors) } +// DeepCopySchema делает глубокую копию структуры spec.Schema +func DeepCopySchema(schema *spec.Schema) (*spec.Schema, error) { + data, err := json.Marshal(schema) + if err != nil { + return nil, fmt.Errorf("failed to marshal schema: %w", err) + } + + var newSchema spec.Schema + err = json.Unmarshal(data, &newSchema) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal schema: %w", err) + } + + return &newSchema, nil +} + // Config returns the configuration for the API server based on AppsServerOptions func (o *AppsServerOptions) Config() (*apiserver.Config, error) { // TODO: set the "real" external address @@ -165,6 +183,12 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) { return nil, fmt.Errorf("error creating self-signed certificates: %v", err) } + // First, register the dynamic types + err := v1alpha1.RegisterDynamicTypes(apiserver.Scheme, o.ResourceConfig) + if err != nil { + return nil, fmt.Errorf("failed to register dynamic types: %v", err) + } + serverConfig := genericapiserver.NewRecommendedConfig(apiserver.Codecs) serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig( @@ -173,6 +197,68 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) { serverConfig.OpenAPIConfig.Info.Title = "Apps" serverConfig.OpenAPIConfig.Info.Version = "0.1" + serverConfig.OpenAPIConfig.PostProcessSpec = func(swagger *spec.Swagger) (*spec.Swagger, error) { + defs := swagger.Definitions + + // Check basic Application definition + appDef, exists := defs["com.github.aenix.io.cozystack.pkg.apis.apps.v1alpha1.Application"] + if !exists { + return swagger, fmt.Errorf("Application definition not found") + } + + // Check basic ApplicationList definition + listDef, exists := defs["com.github.aenix.io.cozystack.pkg.apis.apps.v1alpha1.ApplicationList"] + if !exists { + return swagger, fmt.Errorf("ApplicationList definition not found") + } + + for _, gvk := range v1alpha1.RegisteredGVKs { + resourceName := fmt.Sprintf("com.github.aenix.io.cozystack.pkg.apis.apps.v1alpha1.%s", gvk.Kind) + newDef, err := DeepCopySchema(&appDef) + if err != nil { + return nil, fmt.Errorf("failed to deepcopy schema for %s: %w", gvk.Kind, err) + } + + // Fix Extensions for resource + if newDef.Extensions == nil { + newDef.Extensions = map[string]interface{}{} + } + newDef.Extensions["x-kubernetes-group-version-kind"] = []map[string]interface{}{ + { + "group": gvk.Group, + "version": gvk.Version, + "kind": gvk.Kind, + }, + } + defs[resourceName] = *newDef + fmt.Printf("PostProcessSpec: Added OpenAPI definition for %s\n", resourceName) + + // List resource + listResourceName := fmt.Sprintf("com.github.aenix.io.cozystack.pkg.apis.apps.v1alpha1.%sList", gvk.Kind) + newListDef, err := DeepCopySchema(&listDef) + if err != nil { + return nil, fmt.Errorf("failed to deepcopy schema for %sList: %w", gvk.Kind, err) + } + + // Fix Extensions for List resource + if newListDef.Extensions == nil { + newListDef.Extensions = map[string]interface{}{} + } + newListDef.Extensions["x-kubernetes-group-version-kind"] = []map[string]interface{}{ + { + "group": gvk.Group, + "version": gvk.Version, + "kind": fmt.Sprintf("%sList", gvk.Kind), + }, + } + defs[listResourceName] = *newListDef + fmt.Printf("PostProcessSpec: Added OpenAPI definition for %s\n", listResourceName) + } + + swagger.Definitions = defs + return swagger, nil + } + serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config( sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), ) From 357dae48d3fdabc6257924f5fde5918bfa577bc6 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 25 Nov 2024 10:09:14 +0100 Subject: [PATCH 2/2] Fix logging --- pkg/apis/apps/v1alpha1/register.go | 5 ++--- pkg/cmd/server/start.go | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/apis/apps/v1alpha1/register.go b/pkg/apis/apps/v1alpha1/register.go index ea5ae605..cedebac7 100644 --- a/pkg/apis/apps/v1alpha1/register.go +++ b/pkg/apis/apps/v1alpha1/register.go @@ -17,12 +17,11 @@ limitations under the License. package v1alpha1 import ( - "log" - "github.com/aenix.io/cozystack/pkg/config" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" ) // GroupName holds the API group name. @@ -73,7 +72,7 @@ func RegisterDynamicTypes(scheme *runtime.Scheme, cfg *config.ResourceConfig) er scheme.AddKnownTypeWithName(gvk, &Application{}) scheme.AddKnownTypeWithName(gvk.GroupVersion().WithKind(kind+"List"), &ApplicationList{}) - log.Printf("Registered kind: %s\n", kind) + klog.V(1).Infof("Registered kind: %s\n", kind) RegisteredGVKs = append(RegisteredGVKs, gvk) } diff --git a/pkg/cmd/server/start.go b/pkg/cmd/server/start.go index 70472aed..6593f17a 100644 --- a/pkg/cmd/server/start.go +++ b/pkg/cmd/server/start.go @@ -38,6 +38,7 @@ import ( utilversionpkg "k8s.io/apiserver/pkg/util/version" "k8s.io/component-base/featuregate" baseversion "k8s.io/component-base/version" + "k8s.io/klog/v2" "k8s.io/kube-openapi/pkg/validation/spec" netutils "k8s.io/utils/net" ) @@ -231,7 +232,7 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) { }, } defs[resourceName] = *newDef - fmt.Printf("PostProcessSpec: Added OpenAPI definition for %s\n", resourceName) + klog.V(6).Infof("PostProcessSpec: Added OpenAPI definition for %s\n", resourceName) // List resource listResourceName := fmt.Sprintf("com.github.aenix.io.cozystack.pkg.apis.apps.v1alpha1.%sList", gvk.Kind) @@ -252,7 +253,7 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) { }, } defs[listResourceName] = *newListDef - fmt.Printf("PostProcessSpec: Added OpenAPI definition for %s\n", listResourceName) + klog.V(6).Infof("PostProcessSpec: Added OpenAPI definition for %s\n", listResourceName) } swagger.Definitions = defs