mirror of
https://github.com/outbackdingo/cozystack.git
synced 2026-01-27 10:18:39 +00:00
Fix OpenAPIv2 definitions for dynamic resources (#484)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced OpenAPI schema handling for the Apps API server. - Introduced a method for deep copying schema structures to improve resource definition management. - **Bug Fixes** - Improved error handling during server configuration to ensure proper reporting of setup issues. - **Refactor** - Removed dynamic type registration for the `v1alpha1` API version to simplify server initialization. - **Chores** - Updated image tag for the CozyStack API to the latest version. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -17,17 +17,20 @@ 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.
|
||||
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"}
|
||||
|
||||
@@ -69,8 +72,8 @@ 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)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -18,6 +18,7 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@@ -37,6 +38,8 @@ 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"
|
||||
)
|
||||
|
||||
@@ -156,6 +159,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 +184,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 +198,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
|
||||
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)
|
||||
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
|
||||
klog.V(6).Infof("PostProcessSpec: Added OpenAPI definition for %s\n", listResourceName)
|
||||
}
|
||||
|
||||
swagger.Definitions = defs
|
||||
return swagger, nil
|
||||
}
|
||||
|
||||
serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(
|
||||
sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user