Skip to content

Commit f284e2e

Browse files
authored
Merge pull request #557 from BlaineEXE/allow-generating-embedded-objectmeta
⚠ Generate Embedded ObjectMeta in the CRDs, plus addressed comments
2 parents ea8d4ea + 1d66658 commit f284e2e

File tree

6 files changed

+87
-2
lines changed

6 files changed

+87
-2
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ require (
1818
k8s.io/apimachinery v0.20.2
1919
sigs.k8s.io/yaml v1.2.0
2020
)
21+

pkg/crd/gen.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ type Generator struct {
8484
// You'll need to use "v1" to get support for features like defaulting,
8585
// along with an API server that supports it (Kubernetes 1.16+).
8686
CRDVersions []string `marker:"crdVersions,optional"`
87+
88+
// GenerateEmbeddedObjectMeta specifies if any embedded ObjectMeta in the CRD should be generated
89+
GenerateEmbeddedObjectMeta *bool `marker:",optional"`
8790
}
8891

8992
func (Generator) CheckFilter() loader.NodeFilter {
@@ -98,6 +101,8 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
98101
Checker: ctx.Checker,
99102
// Perform defaulting here to avoid ambiguity later
100103
AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true,
104+
// Indicates the parser on whether to register the ObjectMeta type or not
105+
GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta == true,
101106
}
102107

103108
AddKnownTypes(parser)
@@ -129,6 +134,9 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
129134
crdRaw := parser.CustomResourceDefinitions[groupKind]
130135
addAttribution(&crdRaw)
131136

137+
// Prevent the top level metadata for the CRD to be generate regardless of the intention in the arguments
138+
FixTopLevelMetadata(crdRaw)
139+
132140
versionedCRDs := make([]interface{}, len(crdVersions))
133141
for i, ver := range crdVersions {
134142
conv, err := AsVersion(crdRaw, schema.GroupVersion{Group: apiext.SchemeGroupVersion.Group, Version: ver})
@@ -269,6 +277,18 @@ func removeDefaultsFromSchemaProps(v *apiextlegacy.JSONSchemaProps) {
269277
}
270278
}
271279

280+
// FixTopLevelMetadata resets the schema for the top-level metadata field which is needed for CRD validation
281+
func FixTopLevelMetadata(crd apiext.CustomResourceDefinition) {
282+
for _, v := range crd.Spec.Versions {
283+
if v.Schema != nil && v.Schema.OpenAPIV3Schema != nil && v.Schema.OpenAPIV3Schema.Properties != nil {
284+
schemaProperties := v.Schema.OpenAPIV3Schema.Properties
285+
if _, ok := schemaProperties["metadata"]; ok {
286+
schemaProperties["metadata"] = apiext.JSONSchemaProps{Type: "object"}
287+
}
288+
}
289+
}
290+
}
291+
272292
// toTrivialVersions strips out all schemata except for the storage schema,
273293
// and moves that up into the root object. This makes the CRD compatible
274294
// with pre 1.13 clusters.

pkg/crd/known_types.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ var KnownPackages = map[string]PackageOverride{
3434
},
3535

3636
"k8s.io/apimachinery/pkg/apis/meta/v1": func(p *Parser, pkg *loader.Package) {
37-
// ObjectMeta is managed by the Kubernetes API server, so no need to
38-
// generate validation for it.
3937
p.Schemata[TypeIdent{Name: "ObjectMeta", Package: pkg}] = apiext.JSONSchemaProps{
4038
Type: "object",
4139
}
@@ -113,6 +111,53 @@ var KnownPackages = map[string]PackageOverride{
113111
},
114112
}
115113

114+
// ObjectMetaPackages overrides the ObjectMeta in all types
115+
var ObjectMetaPackages = map[string]PackageOverride{
116+
"k8s.io/apimachinery/pkg/apis/meta/v1": func(p *Parser, pkg *loader.Package) {
117+
// execute the KnowPackages for `k8s.io/apimachinery/pkg/apis/meta/v1` if any
118+
if f, ok := KnownPackages["k8s.io/apimachinery/pkg/apis/meta/v1"]; ok {
119+
f(p, pkg)
120+
}
121+
// This is an allow-listed set of properties of ObjectMeta, other runtime properties are not part of this list
122+
// See more discussion: https://github.com/kubernetes-sigs/controller-tools/pull/395#issuecomment-691919433
123+
p.Schemata[TypeIdent{Name: "ObjectMeta", Package: pkg}] = apiext.JSONSchemaProps{
124+
Type: "object",
125+
Properties: map[string]apiext.JSONSchemaProps{
126+
"name": apiext.JSONSchemaProps{
127+
Type: "string",
128+
},
129+
"namespace": apiext.JSONSchemaProps{
130+
Type: "string",
131+
},
132+
"annotations": apiext.JSONSchemaProps{
133+
Type: "object",
134+
AdditionalProperties: &apiext.JSONSchemaPropsOrBool{
135+
Schema: &apiext.JSONSchemaProps{
136+
Type: "string",
137+
},
138+
},
139+
},
140+
"labels": apiext.JSONSchemaProps{
141+
Type: "object",
142+
AdditionalProperties: &apiext.JSONSchemaPropsOrBool{
143+
Schema: &apiext.JSONSchemaProps{
144+
Type: "string",
145+
},
146+
},
147+
},
148+
"finalizers": apiext.JSONSchemaProps{
149+
Type: "array",
150+
Items: &apiext.JSONSchemaPropsOrArray{
151+
Schema: &apiext.JSONSchemaProps{
152+
Type: "string",
153+
},
154+
},
155+
},
156+
},
157+
}
158+
},
159+
}
160+
116161
func boolPtr(b bool) *bool {
117162
return &b
118163
}
@@ -125,4 +170,10 @@ func AddKnownTypes(parser *Parser) {
125170
for pkgName, override := range KnownPackages {
126171
parser.PackageOverrides[pkgName] = override
127172
}
173+
// if we want to generate the embedded ObjectMeta in the CRD we need to add the ObjectMetaPackages
174+
if parser.GenerateEmbeddedObjectMeta {
175+
for pkgName, override := range ObjectMetaPackages {
176+
parser.PackageOverrides[pkgName] = override
177+
}
178+
}
128179
}

pkg/crd/parser.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ type Parser struct {
8686
// because the implementation is too difficult/clunky to promote them to category 3.
8787
// TODO: Should we have a more formal mechanism for putting "type patterns" in each of the above categories?
8888
AllowDangerousTypes bool
89+
90+
// GenerateEmbeddedObjectMeta specifies if any embedded ObjectMeta should be generated
91+
GenerateEmbeddedObjectMeta bool
8992
}
9093

9194
func (p *Parser) init() {

pkg/crd/parser_integration_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func
8484
groupKind := schema.GroupKind{Kind: "CronJob", Group: "testdata.kubebuilder.io"}
8585
parser.NeedCRDFor(groupKind, nil)
8686

87+
By("fixing top level ObjectMeta on the CRD")
88+
crd.FixTopLevelMetadata(parser.CustomResourceDefinitions[groupKind])
89+
8790
By("checking that no errors occurred along the way (expect for type errors)")
8891
Expect(packageErrors(cronJobPkg, packages.TypeError)).NotTo(HaveOccurred())
8992

@@ -133,6 +136,9 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func
133136
groupKind := schema.GroupKind{Kind: "TestQuota", Group: "plural.example.com"}
134137
parser.NeedCRDFor(groupKind, nil)
135138

139+
By("fixing top level ObjectMeta on the CRD")
140+
crd.FixTopLevelMetadata(parser.CustomResourceDefinitions[groupKind])
141+
136142
By("loading the desired YAML")
137143
expectedFile, err := ioutil.ReadFile("plural.example.com_testquotas.yaml")
138144
Expect(err).NotTo(HaveOccurred())

pkg/crd/zz_generated.markerhelp.go

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

0 commit comments

Comments
 (0)