Skip to content

Commit 62ad93a

Browse files
authored
Merge remote-tracking branch 'upstream/master' into floating-point-validation
2 parents 618e68e + ca1750d commit 62ad93a

38 files changed

+511
-172
lines changed

go.mod

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,45 @@
11
module sigs.k8s.io/controller-tools
22

3-
go 1.16
3+
go 1.17
44

55
require (
66
github.com/fatih/color v1.12.0
77
github.com/gobuffalo/flect v0.2.3
88
github.com/google/go-cmp v0.5.6
9-
github.com/onsi/ginkgo v1.16.4
10-
github.com/onsi/gomega v1.14.0
11-
github.com/spf13/cobra v1.2.1
9+
github.com/onsi/ginkgo v1.16.5
10+
github.com/onsi/gomega v1.17.0
11+
github.com/spf13/cobra v1.4.0
1212
github.com/spf13/pflag v1.0.5
13-
golang.org/x/tools v0.1.5
13+
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717
14+
gopkg.in/yaml.v2 v2.4.0
1415
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
15-
k8s.io/api v0.22.2
16-
k8s.io/apiextensions-apiserver v0.22.2
17-
k8s.io/apimachinery v0.22.2
18-
sigs.k8s.io/yaml v1.2.0
16+
k8s.io/api v0.24.0-rc.1
17+
k8s.io/apiextensions-apiserver v0.24.0-rc.1
18+
k8s.io/apimachinery v0.24.0-rc.1
19+
sigs.k8s.io/yaml v1.3.0
20+
)
21+
22+
require (
23+
github.com/fsnotify/fsnotify v1.4.9 // indirect
24+
github.com/go-logr/logr v1.2.0 // indirect
25+
github.com/gogo/protobuf v1.3.2 // indirect
26+
github.com/google/gofuzz v1.1.0 // indirect
27+
github.com/inconshreveable/mousetrap v1.0.0 // indirect
28+
github.com/json-iterator/go v1.1.12 // indirect
29+
github.com/mattn/go-colorable v0.1.8 // indirect
30+
github.com/mattn/go-isatty v0.0.12 // indirect
31+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
32+
github.com/modern-go/reflect2 v1.0.2 // indirect
33+
github.com/nxadm/tail v1.4.8 // indirect
34+
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
35+
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
36+
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
37+
golang.org/x/text v0.3.7 // indirect
38+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
39+
gopkg.in/inf.v0 v0.9.1 // indirect
40+
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
41+
k8s.io/klog/v2 v2.60.1 // indirect
42+
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
43+
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
44+
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
1945
)

go.sum

Lines changed: 94 additions & 59 deletions
Large diffs are not rendered by default.

pkg/crd/gen.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ const defaultVersion = v1
4141

4242
// Generator generates CustomResourceDefinition objects.
4343
type Generator struct {
44+
// IgnoreUnexportedFields indicates that we should skip unexported fields.
45+
//
46+
// Left unspecified, the default is false.
47+
IgnoreUnexportedFields *bool `marker:",optional"`
48+
4449
// AllowDangerousTypes allows types which are usually omitted from CRD generation
4550
// because they are not recommended.
4651
//
@@ -80,12 +85,20 @@ func (Generator) CheckFilter() loader.NodeFilter {
8085
func (Generator) RegisterMarkers(into *markers.Registry) error {
8186
return crdmarkers.Register(into)
8287
}
88+
89+
// transformRemoveCRDStatus ensures we do not write the CRD status field.
90+
func transformRemoveCRDStatus(obj map[string]interface{}) error {
91+
delete(obj, "status")
92+
return nil
93+
}
94+
8395
func (g Generator) Generate(ctx *genall.GenerationContext) error {
8496
parser := &Parser{
8597
Collector: ctx.Collector,
8698
Checker: ctx.Checker,
8799
// Perform defaulting here to avoid ambiguity later
88-
AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true,
100+
IgnoreUnexportedFields: g.IgnoreUnexportedFields != nil && *g.IgnoreUnexportedFields == true,
101+
AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true,
89102
// Indicates the parser on whether to register the ObjectMeta type or not
90103
GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta == true,
91104
}
@@ -139,7 +152,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
139152
} else {
140153
fileName = fmt.Sprintf("%s_%s.%s.yaml", crdRaw.Spec.Group, crdRaw.Spec.Names.Plural, crdVersions[i])
141154
}
142-
if err := ctx.WriteYAML(fileName, crd); err != nil {
155+
if err := ctx.WriteYAML(fileName, []interface{}{crd}, genall.WithTransform(transformRemoveCRDStatus)); err != nil {
143156
return err
144157
}
145158
}

pkg/crd/markers/validation.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ var ValidationMarkers = mustMakeAllWithPrefix("kubebuilder:validation", markers.
6767
XPreserveUnknownFields{},
6868
XEmbeddedResource{},
6969
XIntOrString{},
70+
XValidation{},
7071
)
7172

7273
// FieldOnlyMarkers list field-specific validation markers (i.e. those markers that don't make
@@ -271,6 +272,17 @@ func isIntegral(value float64) bool {
271272
return value == math.Trunc(value) && !math.IsNaN(value) && !math.IsInf(value, 0)
272273
}
273274

275+
// +controllertools:marker:generateHelp:category="CRD validation"
276+
// XValidation marks a field as requiring a value for which a given
277+
// expression evaluates to true.
278+
//
279+
// This marker may be repeated to specify multiple expressions, all of
280+
// which must evaluate to true.
281+
type XValidation struct {
282+
Rule string
283+
Message string `marker:",optional"`
284+
}
285+
274286
func (m Maximum) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
275287
if !hasNumericType(schema) {
276288
return fmt.Errorf("must apply maximum to a numeric value, found %s", schema.Type)
@@ -473,3 +485,11 @@ func (m XIntOrString) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
473485
}
474486

475487
func (m XIntOrString) ApplyFirst() {}
488+
489+
func (m XValidation) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
490+
schema.XValidations = append(schema.XValidations, apiext.ValidationRule{
491+
Rule: m.Rule,
492+
Message: m.Message,
493+
})
494+
return nil
495+
}

pkg/crd/markers/zz_generated.markerhelp.go

Lines changed: 24 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/crd/parser.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ type Parser struct {
8787
// TODO: Should we have a more formal mechanism for putting "type patterns" in each of the above categories?
8888
AllowDangerousTypes bool
8989

90+
// IgnoreUnexportedFields specifies if unexported fields on the struct should be skipped
91+
IgnoreUnexportedFields bool
92+
9093
// GenerateEmbeddedObjectMeta specifies if any embedded ObjectMeta should be generated
9194
GenerateEmbeddedObjectMeta bool
9295
}
@@ -178,7 +181,7 @@ func (p *Parser) NeedSchemaFor(typ TypeIdent) {
178181
// avoid tripping recursive schemata, like ManagedFields, by adding an empty WIP schema
179182
p.Schemata[typ] = apiext.JSONSchemaProps{}
180183

181-
schemaCtx := newSchemaContext(typ.Package, p, p.AllowDangerousTypes)
184+
schemaCtx := newSchemaContext(typ.Package, p, p.AllowDangerousTypes, p.IgnoreUnexportedFields)
182185
ctxForInfo := schemaCtx.ForInfo(info)
183186

184187
pkgMarkers, err := markers.PackageMarkers(p.Collector, typ.Package)

pkg/crd/parser_integration_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,10 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func
7272
reg := &markers.Registry{}
7373
Expect(crdmarkers.Register(reg)).To(Succeed())
7474
parser := &crd.Parser{
75-
Collector: &markers.Collector{Registry: reg},
76-
Checker: &loader.TypeChecker{},
77-
AllowDangerousTypes: true, // need to allow “dangerous types” in this file for testing
75+
Collector: &markers.Collector{Registry: reg},
76+
Checker: &loader.TypeChecker{},
77+
IgnoreUnexportedFields: true,
78+
AllowDangerousTypes: true, // need to allow “dangerous types” in this file for testing
7879
}
7980
crd.AddKnownTypes(parser)
8081

pkg/crd/schema.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,28 +69,31 @@ type schemaContext struct {
6969
schemaRequester schemaRequester
7070
PackageMarkers markers.MarkerValues
7171

72-
allowDangerousTypes bool
72+
allowDangerousTypes bool
73+
ignoreUnexportedFields bool
7374
}
7475

7576
// newSchemaContext constructs a new schemaContext for the given package and schema requester.
7677
// It must have type info added before use via ForInfo.
77-
func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTypes bool) *schemaContext {
78+
func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTypes, ignoreUnexportedFields bool) *schemaContext {
7879
pkg.NeedTypesInfo()
7980
return &schemaContext{
80-
pkg: pkg,
81-
schemaRequester: req,
82-
allowDangerousTypes: allowDangerousTypes,
81+
pkg: pkg,
82+
schemaRequester: req,
83+
allowDangerousTypes: allowDangerousTypes,
84+
ignoreUnexportedFields: ignoreUnexportedFields,
8385
}
8486
}
8587

8688
// ForInfo produces a new schemaContext with containing the same information
8789
// as this one, except with the given type information.
8890
func (c *schemaContext) ForInfo(info *markers.TypeInfo) *schemaContext {
8991
return &schemaContext{
90-
pkg: c.pkg,
91-
info: info,
92-
schemaRequester: c.schemaRequester,
93-
allowDangerousTypes: c.allowDangerousTypes,
92+
pkg: c.pkg,
93+
info: info,
94+
schemaRequester: c.schemaRequester,
95+
allowDangerousTypes: c.allowDangerousTypes,
96+
ignoreUnexportedFields: c.ignoreUnexportedFields,
9497
}
9598
}
9699

@@ -339,6 +342,11 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON
339342
}
340343

341344
for _, field := range ctx.info.Fields {
345+
// Skip if the field is not an inline field, ignoreUnexportedFields is true, and the field is not exported
346+
if field.Name != "" && ctx.ignoreUnexportedFields && !ast.IsExported(field.Name) {
347+
continue
348+
}
349+
342350
jsonTag, hasTag := field.Tag.Lookup("json")
343351
if !hasTag {
344352
// if the field doesn't have a JSON tag, it doesn't belong in output (and shouldn't exist in a serialized type)

pkg/crd/schema_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func transform(t *testing.T, expr string) *apiext.JSONSchemaProps {
6363
pkg.NeedTypesInfo()
6464
failIfErrors(t, pkg.Errors)
6565

66-
schemaContext := newSchemaContext(pkg, nil, true).ForInfo(&markers.TypeInfo{})
66+
schemaContext := newSchemaContext(pkg, nil, true, false).ForInfo(&markers.TypeInfo{})
6767
// yick: grab the only type definition
6868
definedType := pkg.Syntax[0].Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).Type
6969
result := typeToSchema(schemaContext, definedType)

pkg/crd/spec.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,5 @@ func (p *Parser) NeedCRDFor(groupKind schema.GroupKind, maxDescLen *int) {
164164
packages[0].AddError(fmt.Errorf("CRD for %s with version(s) %v does not serve any version", groupKind, crd.Spec.Versions))
165165
}
166166

167-
// NB(directxman12): CRD's status doesn't have omitempty markers, which means things
168-
// get serialized as null, which causes the validator to freak out. Manually set
169-
// these to empty till we get a better solution.
170-
crd.Status.Conditions = []apiext.CustomResourceDefinitionCondition{}
171-
crd.Status.StoredVersions = []string{}
172-
173167
p.CustomResourceDefinitions[groupKind] = crd
174168
}

0 commit comments

Comments
 (0)