Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: misc refactors to the OpenAPI generator #6429

Merged
merged 1 commit into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 7 additions & 63 deletions kubernetes-model-generator/openapi/generator/cmd/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,7 @@ import (
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/cmd/generated_openapi"
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/pkg/openapi"
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/pkg/openshift"
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/pkg/parser"
"strings"

networkattachmentdefinition "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
openshiftbaremetaloperatorv1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
openshiftclusterapiprovidermetal3v1beta1 "github.com/metal3-io/cluster-api-provider-metal3/api/v1beta1"
openshiftconfigv1 "github.com/openshift/api/config/v1"
openshiftcloudcredentialoperatorv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1"
openshiftclusternetworkoperatorv1 "github.com/openshift/cluster-network-operator/pkg/apis/network/v1"
openshiftclusternodetuningoperatorv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1"
openshifthivev1 "github.com/openshift/hive/apis/hive/v1"
openshiftinstallerv1 "github.com/openshift/installer/pkg/types"
operatorframeworkv1 "github.com/operator-framework/api/pkg/operators/v1"
operatorframeworkv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
olm "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
prometheusoperatorv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/spf13/cobra"
"k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/validation/spec"
"time"
)

Expand All @@ -55,57 +37,19 @@ func init() {

var openApiRun = func(cobraCmd *cobra.Command, args []string) {
startTime := time.Now()
fmt.Printf("OpenAPI JSON schema generation started...\n%s\n", strings.Join([]string{
// Force imports so that modules are present in go.mod
networkattachmentdefinition.SchemeGroupVersion.String(),
olm.SchemeGroupVersion.String(),
openshiftbaremetaloperatorv1alpha1.GroupVersion.String(),
openshiftconfigv1.SchemeGroupVersion.String(),
openshiftcloudcredentialoperatorv1.GroupVersion.String(),
openshiftclusterapiprovidermetal3v1beta1.GroupVersion.String(),
openshiftclusternetworkoperatorv1.GroupVersion.String(),
openshiftclusternodetuningoperatorv1.SchemeGroupVersion.String(),
openshifthivev1.SchemeGroupVersion.String(),
"install.openshift.io/" + openshiftinstallerv1.InstallConfigVersion + " (" + strings.Join(openshiftinstallerv1.PlatformNames, ", ") + ")",
operatorframeworkv1alpha1.SchemeGroupVersion.String(),
operatorframeworkv1.GroupVersion.String(),
prometheusoperatorv1.SchemeGroupVersion.String(),
}, "\n"))
fmt.Println("OpenAPI JSON schema generation started...")
var targetDirectory string
if len(args) > 0 {
targetDirectory = args[0]
} else {
targetDirectory = "."
}
openApiGenerator := openapi.NewGenerator(targetDirectory, "openshift-generated")
openShiftModule := parser.NewModule(openshift.PackagePatterns...)
/////////////////////////////////////////////////////////////////////////////////
// Ported from github.com/openshift/api/openapi/cmd/models-schema/main.go
refFunc := func(name string) spec.Ref {
return spec.MustCreateRef(fmt.Sprintf("#/definitions/%s", openShiftModule.ApiName(name)))
}
defs := generated_openapi.GetOpenAPIDefinitions(refFunc)
for k, v := range defs {
// Marc: Use gengo to complete information for the definition
fabric8Info := openShiftModule.ExtractInfo(k)
if v.Schema.ExtraProps == nil {
v.Schema.ExtraProps = make(map[string]interface{})
}
v.Schema.ExtraProps["x-fabric8-info"] = fabric8Info

// Replace top-level schema with v2 if a v2 schema is embedded
// so that the output of this program is always in OpenAPI v2.
// This is done by looking up an extension that marks the embedded v2
// schema, and, if the v2 schema is found, make it the resulting schema for
// the type.
if schema, ok := v.Schema.Extensions[common.ExtensionV2Schema]; ok {
if v2Schema, isOpenAPISchema := schema.(spec.Schema); isOpenAPISchema {
openApiGenerator.PutDefinition(openShiftModule.ApiName(k), v2Schema)
continue
}
}
openApiGenerator.PutDefinition(openShiftModule.ApiName(k), v.Schema)
}
openApiGenerator := openapi.NewGenerator(
targetDirectory,
"openshift-generated",
generated_openapi.GetOpenAPIDefinitions,
openshift.PackagePatterns...,
)
if err := openApiGenerator.WriteDefinitions(); err != nil {
panic(fmt.Errorf("error writing OpenAPI schema: %w", err))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright (C) 2015 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main

import (
"fmt"
networkattachmentdefinition "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
openshiftbaremetaloperatorv1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
openshiftclusterapiprovidermetal3v1beta1 "github.com/metal3-io/cluster-api-provider-metal3/api/v1beta1"
openshiftconfigv1 "github.com/openshift/api/config/v1"
openshiftcloudcredentialoperatorv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1"
openshiftclusternetworkoperatorv1 "github.com/openshift/cluster-network-operator/pkg/apis/network/v1"
openshiftclusternodetuningoperatorv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1"
openshifthivev1 "github.com/openshift/hive/apis/hive/v1"
openshiftinstallerv1 "github.com/openshift/installer/pkg/types"
operatorframeworkv1 "github.com/operator-framework/api/pkg/operators/v1"
operatorframeworkv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
olm "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
prometheusoperatorv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/spf13/cobra"
"strings"
)

var supportedApis = &cobra.Command{
Use: "supported-apis",
Short: "Lists the APIs supported by this generator",
Run: supportedApisRun,
}

func init() {
rootCmd.AddCommand(supportedApis)
}

// Forces imports so that modules are present in go.mod
var supportedApisRun = func(cobraCmd *cobra.Command, args []string) {
fmt.Printf("This generator generates OpenAPI schemas for the following supported APIs:\n%s\n", strings.Join([]string{
networkattachmentdefinition.SchemeGroupVersion.String(),
olm.SchemeGroupVersion.String(),
openshiftbaremetaloperatorv1alpha1.GroupVersion.String(),
openshiftconfigv1.SchemeGroupVersion.String(),
openshiftcloudcredentialoperatorv1.GroupVersion.String(),
openshiftclusterapiprovidermetal3v1beta1.GroupVersion.String(),
openshiftclusternetworkoperatorv1.GroupVersion.String(),
openshiftclusternodetuningoperatorv1.SchemeGroupVersion.String(),
openshifthivev1.SchemeGroupVersion.String(),
"install.openshift.io/" + openshiftinstallerv1.InstallConfigVersion + " (" + strings.Join(openshiftinstallerv1.PlatformNames, ", ") + ")",
operatorframeworkv1alpha1.SchemeGroupVersion.String(),
operatorframeworkv1.GroupVersion.String(),
prometheusoperatorv1.SchemeGroupVersion.String(),
}, "\n"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,73 @@ package openapi
import (
"encoding/json"
"fmt"
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/pkg/parser"
"k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/validation/spec"
"os"
"path/filepath"
"strings"
)

type JsonGenerator struct {
type JsonGenerator interface {
WriteDefinitions() error
}

type jsonGenerator struct {
name string
targetDirectory string
definitions map[string]spec.Schema
parserModule *parser.Module
}

func NewGenerator(targetDirectory string, name string) *JsonGenerator {
return &JsonGenerator{
func NewGenerator(
targetDirectory string,
name string,
getDefinitionsFunc func(callback common.ReferenceCallback) map[string]common.OpenAPIDefinition,
patterns ...string,
) JsonGenerator {
g := &jsonGenerator{
name: name,
targetDirectory: targetDirectory,
definitions: make(map[string]spec.Schema),
parserModule: parser.NewModule(patterns...),
}
defs := getDefinitionsFunc(g.refFunc)
// Ported and adapted from github.com/openshift/api/openapi/cmd/models-schema/main.go
// https://github.com/openshift/api/blob/b1f700bdd8d22c4033be4e4e9ef751d89ade42e8/openapi/cmd/models-schema/main.go#L30-L44
for k, v := range defs {
g.addFabric8Info(k, &v)
// Replace top-level schema with v2 if a v2 schema is embedded
// so that the output of this program is always in OpenAPI v2.
// This is done by looking up an extension that marks the embedded v2
// schema, and, if the v2 schema is found, make it the resulting schema for
// the type.
if schema, ok := v.Schema.Extensions[common.ExtensionV2Schema]; ok {
if v2Schema, isOpenAPISchema := schema.(spec.Schema); isOpenAPISchema {
g.definitions[g.parserModule.ApiName(k)] = v2Schema
continue
}
}
g.definitions[g.parserModule.ApiName(k)] = v.Schema
}
return g
}

func (g *JsonGenerator) PutDefinition(name string, schema spec.Schema) {
g.definitions[name] = schema
// Ported and adapted from github.com/openshift/api/openapi/cmd/models-schema/main.go
// https://github.com/openshift/api/blob/b1f700bdd8d22c4033be4e4e9ef751d89ade42e8/openapi/cmd/models-schema/main.go#L25-L27
func (g *jsonGenerator) refFunc(name string) spec.Ref {
return spec.MustCreateRef(fmt.Sprintf("#/definitions/%s", g.parserModule.ApiName(name)))
}

func (g *JsonGenerator) WriteDefinitions() error {
func (g *jsonGenerator) addFabric8Info(k string, v *common.OpenAPIDefinition) {
// Marc: Use gengo to complete information for the definition
fabric8Info := g.parserModule.ExtractInfo(k)
if v.Schema.ExtraProps == nil {
v.Schema.ExtraProps = make(map[string]interface{})
}
v.Schema.ExtraProps["x-fabric8-info"] = fabric8Info
}

func (g *jsonGenerator) WriteDefinitions() error {
data, err := json.MarshalIndent(&spec.Swagger{
SwaggerProps: spec.SwaggerProps{
Definitions: g.definitions,
Expand All @@ -66,19 +108,3 @@ func (g *JsonGenerator) WriteDefinitions() error {
}
return nil
}

// FriendlyName returns an OpenAPI friendly name for the given name.
// From vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go
// https://github.com/kubernetes/apiserver/blob/60d1ca672541e1b30b558e32e53cad7c172345a6/pkg/endpoints/openapi/openapi.go#L136-L147
func FriendlyName(name string) string {
nameParts := strings.Split(name, "/")
// Reverse first part. e.g., io.k8s... instead of k8s.io...
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
parts := strings.Split(nameParts[0], ".")
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
parts[i], parts[j] = parts[j], parts[i]
}
nameParts[0] = strings.Join(parts, ".")
}
return strings.Join(nameParts, ".")
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Package parser provides functionality to extract information from Go types and packages using gengo.
package parser

import (
"fmt"
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/pkg/kubernetes"
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/pkg/openapi"
"k8s.io/gengo/v2/parser"
"k8s.io/gengo/v2/types"
"strings"
Expand Down Expand Up @@ -73,17 +74,22 @@ func (oam *Module) ExtractInfo(definitionName string) *Fabric8Info {
return fabric8Info
}

// ApiName returns the completed definition name for the OpenAPI component
// The standard definition name is usually based on the module name + package name + type name.
// However, Kubernetes comment tags include augmented information such as the groupName and versionName.
// This method attempts to resolve the additional information from the gengo processed/parsed package and
// type information.
func (oam *Module) ApiName(definitionName string) string {
// Don't treat k8s.io types, json is expected to contain the full Go definition name instead of the group/version
if strings.HasPrefix(definitionName, "k8s.io/") {
return openapi.FriendlyName(definitionName)
return FriendlyName(definitionName)
}
lastSeparator := strings.LastIndex(definitionName, ".")
typeName := definitionName[lastSeparator+1:]
pkg := oam.resolvePackage(definitionName)
gn := groupName(pkg)
if gn == "" {
return openapi.FriendlyName(definitionName)
return FriendlyName(definitionName)
}
groupParts := strings.Split(gn, ".")
for i, j := 0, len(groupParts)-1; i < j; i, j = i+1, j-1 {
Expand Down Expand Up @@ -171,3 +177,19 @@ func scope(typ *types.Type) string {
}
return scope
}

// FriendlyName returns an OpenAPI friendly name for the given name.
// From vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go
// https://github.com/kubernetes/apiserver/blob/60d1ca672541e1b30b558e32e53cad7c172345a6/pkg/endpoints/openapi/openapi.go#L136-L147
func FriendlyName(name string) string {
nameParts := strings.Split(name, "/")
// Reverse first part. e.g., io.k8s... instead of k8s.io...
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
parts := strings.Split(nameParts[0], ".")
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
parts[i], parts[j] = parts[j], parts[i]
}
nameParts[0] = strings.Join(parts, ".")
}
return strings.Join(nameParts, ".")
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,43 +22,13 @@ import (
"fmt"
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/pkg/openapi"
"github.com/fabric8io/kubernetes-client/kubernetes-model-generator/openapi/generator/pkg/openshift"
"strings"

networkattachmentdefinition "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
openshiftbaremetaloperatorv1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
openshiftclusterapiprovidermetal3v1beta1 "github.com/metal3-io/cluster-api-provider-metal3/api/v1beta1"
openshiftconfigv1 "github.com/openshift/api/config/v1"
openshiftcloudcredentialoperatorv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1"
openshiftclusternetworkoperatorv1 "github.com/openshift/cluster-network-operator/pkg/apis/network/v1"
openshiftclusternodetuningoperatorv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1"
openshifthivev1 "github.com/openshift/hive/apis/hive/v1"
openshiftinstallerv1 "github.com/openshift/installer/pkg/types"
operatorframeworkv1 "github.com/operator-framework/api/pkg/operators/v1"
operatorframeworkv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
olm "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
prometheusoperatorv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"k8s.io/kube-openapi/cmd/openapi-gen/args"
"time"
)

func main() {
startTime := time.Now()
fmt.Printf("OpenAPI code generation started...\n%s\n", strings.Join([]string{
// Force imports so that modules are present in go.mod
networkattachmentdefinition.SchemeGroupVersion.String(),
olm.SchemeGroupVersion.String(),
openshiftbaremetaloperatorv1alpha1.GroupVersion.String(),
openshiftconfigv1.SchemeGroupVersion.String(),
openshiftcloudcredentialoperatorv1.GroupVersion.String(),
openshiftclusterapiprovidermetal3v1beta1.GroupVersion.String(),
openshiftclusternetworkoperatorv1.GroupVersion.String(),
openshiftclusternodetuningoperatorv1.SchemeGroupVersion.String(),
openshifthivev1.SchemeGroupVersion.String(),
"install.openshift.io/" + openshiftinstallerv1.InstallConfigVersion + " (" + strings.Join(openshiftinstallerv1.PlatformNames, ", ") + ")",
operatorframeworkv1alpha1.SchemeGroupVersion.String(),
operatorframeworkv1.GroupVersion.String(),
prometheusoperatorv1.SchemeGroupVersion.String(),
}, "\n"))
fmt.Println("OpenAPI code generation started...")
err := (&openapi.GoGenerator{
Args: args.Args{
OutputFile: "zz_generated.openapi.go",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@
<configuration >
<settings combine.self="append">
<urls>
<url>https://raw.githubusercontent.com/kubernetes-sigs/kube-storage-version-migrator/5c8923c5ff96ceb4435f66b986b5aec2dd0cbc22/manifests/storage_migration_crd.yaml</url>
<url>https://raw.githubusercontent.com/kubernetes-sigs/kube-storage-version-migrator/5c8923c5ff96ceb4435f66b986b5aec2dd0cbc22/manifests/storage_state_crd.yaml</url>
<url>https://raw.githubusercontent.com/kubernetes-sigs/kube-storage-version-migrator/${openapi.storageversionmigrator-revision}/manifests/storage_migration_crd.yaml</url>
<url>https://raw.githubusercontent.com/kubernetes-sigs/kube-storage-version-migrator/${openapi.storageversionmigrator-revision}/manifests/storage_state_crd.yaml</url>
</urls>
<packageMappings combine.self="append">
<io.k8s.migration.storagestates>io.fabric8.openshift.api.model.storageversionmigrator</io.k8s.migration.storagestates>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@
<configuration >
<settings combine.self="append">
<urls>
<url>https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/5bb9e1542cf987458db181bedee7c051a1538dc1/doc/crds/whereabouts.cni.cncf.io_ippools.yaml</url>
<url>https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/5bb9e1542cf987458db181bedee7c051a1538dc1/doc/crds/whereabouts.cni.cncf.io_nodeslicepools.yaml</url>
<url>https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/5bb9e1542cf987458db181bedee7c051a1538dc1/doc/crds/whereabouts.cni.cncf.io_overlappingrangeipreservations.yaml</url>
<url>https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/${openapi.whereabouts-revision}/doc/crds/whereabouts.cni.cncf.io_ippools.yaml</url>
<url>https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/${openapi.whereabouts-revision}/doc/crds/whereabouts.cni.cncf.io_nodeslicepools.yaml</url>
<url>https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/${openapi.whereabouts-revision}/doc/crds/whereabouts.cni.cncf.io_overlappingrangeipreservations.yaml</url>
</urls>
<packageMappings combine.self="append">
<io.cncf.cni.whereabouts.ippools>io.fabric8.openshift.api.model.whereabouts</io.cncf.cni.whereabouts.ippools>
Expand Down
3 changes: 2 additions & 1 deletion kubernetes-model-generator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@
<skipTests>false</skipTests>
<testExclusionPattern>**/*KubernetesTest.java</testExclusionPattern>
<openapi.schema.kubernetes-latest>${project.parent.basedir}/openapi/schemas/kubernetes-1.30.0.json</openapi.schema.kubernetes-latest>
<!-- Contains Paths. Retrieve from a real cluster -->
<openapi.schema.openshift-generated>${project.parent.basedir}/openapi/schemas/openshift-generated.json</openapi.schema.openshift-generated>
<openapi.openshift-version>4.17</openapi.openshift-version>
<openapi.storageversionmigrator-revision>5c8923c5ff96ceb4435f66b986b5aec2dd0cbc22</openapi.storageversionmigrator-revision>
<openapi.whereabouts-revision>5bb9e1542cf987458db181bedee7c051a1538dc1</openapi.whereabouts-revision>
<osgi.require-capability>
osgi.extender;
filter:="(osgi.extender=osgi.serviceloader.registrar)"
Expand Down
Loading