Skip to content

Commit

Permalink
Allow certain kube markers to be ignored
Browse files Browse the repository at this point in the history
  • Loading branch information
jjamroga committed Aug 7, 2024
1 parent 22e66cd commit 480f791
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 4 deletions.
23 changes: 23 additions & 0 deletions integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import (
"path/filepath"
"strings"
"testing"
"regexp"
)

const goldenDir = "testdata/golden/"

func TestOpenAPIGeneration(t *testing.T) {
regexp.MustCompile("(:?kubebuilder:altName)")

testcases := []struct {
name string
id string
Expand Down Expand Up @@ -109,6 +112,26 @@ func TestOpenAPIGeneration(t *testing.T) {
},
wantFiles: []string{"test7/openapiv3.yaml"},
},
{
name: "Test no markers are ignored when ignored_kube_markers is zero length",
id: "test7",
perPackage: false,
genOpts: "yaml=true,single_file=true,proto_oneof=true,int_native=true,multiline_description=true,disable_kube_markers=true,ignored_kube_markers=",
inputFiles: map[string][]string{
"test7": {"./testdata/test7/markers.proto"},
},
wantFiles: []string{"test7/openapiv3.yaml"},
},
{
name: "Test ignored_kube_markers option ignores specific markers",
id: "test8",
perPackage: false,
genOpts: "yaml=true,single_file=true,proto_oneof=true,int_native=true,multiline_description=true,disable_kube_markers=true,ignored_kube_markers=Required",
inputFiles: map[string][]string{
"test8": {"./testdata/test8/markers.proto"},
},
wantFiles: []string{"test8/openapiv3.yaml"},
},
}

for _, tc := range testcases {
Expand Down
6 changes: 6 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func generate(request pluginpb.CodeGeneratorRequest) (*pluginpb.CodeGeneratorRes
disableKubeMarkers := false

var messagesWithEmptySchema []string
var ignoredKubeMarkers []string

p := extractParams(request.GetParameter())
for k, v := range p {
Expand Down Expand Up @@ -147,6 +148,10 @@ func generate(request pluginpb.CodeGeneratorRequest) (*pluginpb.CodeGeneratorRes
default:
return nil, fmt.Errorf("unknown value '%s' for disable_kube_markers", v)
}
} else if k == "ignored_kube_markers" {
if len(v) > 0 {
ignoredKubeMarkers = strings.Split(v, "+")
}
} else {
return nil, fmt.Errorf("unknown argument '%s' specified", k)
}
Expand Down Expand Up @@ -184,6 +189,7 @@ func generate(request pluginpb.CodeGeneratorRequest) (*pluginpb.CodeGeneratorRes
protoOneof,
intNative,
disableKubeMarkers,
ignoredKubeMarkers,
)
return g.generateOutput(filesToGen)
}
Expand Down
5 changes: 4 additions & 1 deletion openapiGenerator.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ type openapiGenerator struct {
// If set to true, kubebuilder markers and validations such as PreserveUnknownFields, MinItems, default, and all CEL rules will be omitted from the OpenAPI schema.
// The Type and Required markers will be maintained.
disableKubeMarkers bool

ignoredKubeMarkers []string
}

type DescriptionConfiguration struct {
Expand All @@ -143,8 +145,9 @@ func newOpenAPIGenerator(
protoOneof bool,
intNative bool,
disableKubeMarkers bool,
ignoredKubeMarkers []string,
) *openapiGenerator {
mRegistry, err := markers.NewRegistry()
mRegistry, err := markers.NewRegistry(ignoredKubeMarkers)
if err != nil {
log.Panicf("error initializing marker registry: %v", err)
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/markers/constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,10 @@ func (m Example) ApplyToSchema(o *openapi3.Schema) {
o.Example = m.Value
}

type AltName string

func (a AltName) ApplyToSchema(o *openapi3.Schema) {}

// Schemaless marks a field as being a schemaless object.
//
// Schemaless objects are not introspected, so you must provide
Expand Down
16 changes: 13 additions & 3 deletions pkg/markers/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"reflect"

"sigs.k8s.io/controller-tools/pkg/markers"
"regexp"
"fmt"
"strings"
)

const (
Expand All @@ -17,13 +20,20 @@ type definitionWithHelp struct {
}

type Registry struct {
mRegistry *markers.Registry
mRegistry *markers.Registry
ignoredKubeMarkersRegex *regexp.Regexp
}

func NewRegistry() (*Registry, error) {
func NewRegistry(ignoredKubeMarkers []string) (*Registry, error) {
var ignoredKubeMarkersRegexp *regexp.Regexp
if len(ignoredKubeMarkers) > 0 {
toIgnore := strings.Join(ignoredKubeMarkers, "|")
ignoredKubeMarkersRegexp = regexp.MustCompile(fmt.Sprintf("(?:%s)", toIgnore))
}
mReg := &markers.Registry{}
r := &Registry{
mRegistry: mReg,
mRegistry: mReg,
ignoredKubeMarkersRegex: ignoredKubeMarkersRegexp,
}
return r, Register(mReg)
}
Expand Down
22 changes: 22 additions & 0 deletions pkg/markers/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,12 @@ func (r *Registry) ApplyRulesToSchema(
o *openapi3.Schema,
target markers.TargetType,
) error {

for _, rule := range rules {
if r.isIgnoredKubeMarker(rule) {
continue
}

defn := r.mRegistry.Lookup(rule, target)
if defn == nil {
return fmt.Errorf("no definition found for rule: %s", rule)
Expand All @@ -164,6 +169,10 @@ func (r *Registry) GetSchemaType(
target markers.TargetType,
) Type {
for _, rule := range rules {
if r.isIgnoredKubeMarker(rule) {
continue
}

defn := r.mRegistry.Lookup(rule, target)
if defn == nil {
log.Panicf("no definition found for rule: %s", rule)
Expand All @@ -183,6 +192,10 @@ func (r *Registry) IsRequired(
rules []string,
) bool {
for _, rule := range rules {
if r.isIgnoredKubeMarker(rule) {
continue
}

defn := r.mRegistry.Lookup(rule, markers.DescribesField)
if defn == nil {
log.Panicf("no definition found for rule: %s", rule)
Expand All @@ -191,5 +204,14 @@ func (r *Registry) IsRequired(
return true
}
}

return false
}

func (r *Registry) isIgnoredKubeMarker(rule string) bool {
if r.ignoredKubeMarkersRegex == nil {
return false
}

return r.ignoredKubeMarkersRegex.MatchString(rule)
}
47 changes: 47 additions & 0 deletions testdata/golden/test8/openapiv3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
components:
schemas:
test7.Msg:
description: This is a top-level message.
properties:
a:
format: int32
type: integer
blist:
items:
type: string
type: array
nested:
properties:
a:
type: string
b:
type: string
c:
type: string
d:
type: string
defaultValue:
type: string
embedded:
type: string
intOrString:
type: string
schemaless:
description: Schemaless field
type: string
type: object
object:
description: Should maintain valid Type marker and not enumerate subfields.
type: object
x-kubernetes-preserve-unknown-fields: true
recursive:
type: object
x-kubernetes-preserve-unknown-fields: true
val:
x-kubernetes-preserve-unknown-fields: true
type: object
info:
title: OpenAPI Spec for Solo APIs.
version: ""
openapi: 3.0.1
paths: null
85 changes: 85 additions & 0 deletions testdata/test8/markers.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
syntax = "proto3";

package test7;

import "struct.proto";

// This is a top-level message.
//
// +kubebuilder:pruning:PreserveUnknownFields
message Msg {
// +kubebuilder:pruning:PreserveUnknownFields
Nested nested = 1;

// +kubebuilder:validation:Maximum=100
// +kubebuilder:validation:Minimum=5
// +kubebuilder:validation:ExclusiveMaximum=true
// +kubebuilder:validation:ExclusiveMinimum=true
// +kubebuilder:validation:MultipleOf=2
// +kubebuilder:validation:XValidation:rule="self != 27",message="must not equal 27"
int32 a = 2;

// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=5
// +kubebuilder:validation:UniqueItems=true
repeated string blist = 3;

// +kubebuilder:validation:Type=value
google.protobuf.Value val = 4;

// Should maintain valid Type marker and not enumerate subfields.
//
// +kubebuilder:validation:Type=object
Nested2 object = 5;

// +kubebuilder:validation:Type=object
Recursive recursive = 6;

// This is a nested message.
//
// +kubebuilder:validation:MinProperties=1
// +kubebuilder:validation:MaxProperties=2
message Nested {
// +kubebuilder:validation:Pattern="^[a-zA-Z0-9_]*$"
// +kubebuilder:validation:Required
string a = 1;

// +kubebuilder:validation:Enum=Allow;Forbid;Replace
// +kubebuilder:validation:Required
string b = 2;

// +kubebuilder:validation:MaxLength=100
// +kubebuilder:validation:MinLength=1
string c = 3;

// +kubebuilder:validation:Format=date-time
string d = 4;

// +kubebuilder:validation:XIntOrString
string int_or_string = 5;

// +kubebuilder:default=forty-two
// +kubebuilder:example=forty-two
string default_value = 6;

// Schemaless field
//
// +kubebuilder:validation:Schemaless
string schemaless = 7;

// +kubebuilder:validation:EmbeddedResource
// +kubebuilder:validation:Nullable
string embedded = 8;
}

message Nested2 {
string a = 1;
string b = 2;
int32 c = 3;
}

message Recursive {
Recursive r = 1;
}
}

0 comments on commit 480f791

Please sign in to comment.