Skip to content

Commit

Permalink
Fix OpenAPIv2 definitions for dynamic resources
Browse files Browse the repository at this point in the history
  • Loading branch information
kvaps committed Nov 23, 2024
1 parent 647a557 commit f7f5112
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 9 deletions.
2 changes: 1 addition & 1 deletion packages/system/cozystack-api/values.yaml
Original file line number Diff line number Diff line change
@@ -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
6 changes: 5 additions & 1 deletion pkg/apis/apps/v1alpha1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}

Expand Down Expand Up @@ -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
Expand Down
7 changes: 0 additions & 7 deletions pkg/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down
86 changes: 86 additions & 0 deletions pkg/cmd/server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package server

import (
"context"
"encoding/json"
"fmt"
"io"
"net"
Expand All @@ -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"
)

Expand Down Expand Up @@ -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
Expand All @@ -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(
Expand All @@ -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),
)
Expand Down

0 comments on commit f7f5112

Please sign in to comment.