Skip to content

Commit 58324d7

Browse files
authored
Merge pull request #183 from sttts/sttts-crd-schema-gen
Add crdschema generator
2 parents a653df4 + 3687756 commit 58324d7

37 files changed

+1903
-14
lines changed

Gopkg.lock

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

cmd/controller-gen/main.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
prettyhelp "sigs.k8s.io/controller-tools/pkg/genall/help/pretty"
3232
"sigs.k8s.io/controller-tools/pkg/markers"
3333
"sigs.k8s.io/controller-tools/pkg/rbac"
34+
"sigs.k8s.io/controller-tools/pkg/schemapatcher"
3435
"sigs.k8s.io/controller-tools/pkg/webhook"
3536
)
3637

@@ -46,10 +47,11 @@ var (
4647
// each turns into a command line option,
4748
// and has options for output forms.
4849
allGenerators = map[string]genall.Generator{
49-
"crd": crd.Generator{},
50-
"rbac": rbac.Generator{},
51-
"object": deepcopy.Generator{},
52-
"webhook": webhook.Generator{},
50+
"crd": crd.Generator{},
51+
"rbac": rbac.Generator{},
52+
"object": deepcopy.Generator{},
53+
"webhook": webhook.Generator{},
54+
"schemapatch": schemapatcher.Generator{},
5355
}
5456

5557
// allOutputRules defines the list of all known output rules, giving
@@ -134,6 +136,9 @@ func main() {
134136
# Generate deepcopy/runtime.Object implementations for a particular file
135137
controller-gen object paths=./apis/v1beta1/some_types.go
136138
139+
# Generate OpenAPI v3 schemas for API packages and merge them into existing CRD manifests
140+
controller-gen schemapatch:manifests=./manifests output:dir=./manifests paths=./pkg/apis/...
141+
137142
# Run all the generators for a given project
138143
controller-gen paths=./apis/...
139144

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ require (
2525
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
2626
gopkg.in/inf.v0 v0.9.1 // indirect
2727
gopkg.in/yaml.v2 v2.2.2 // indirect
28+
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
2829
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
2930
k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8
3031
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
8484
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
8585
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
8686
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
87+
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22 h1:0efs3hwEZhFKsCoP8l6dDB1AZWMgnEl3yWXWRZTOaEA=
88+
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
8789
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbuQba2w+SXqezo=
8890
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
8991
k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8 h1:q1Qvjzs/iEdXF6A1a8H3AKVFDzJNcJn3nXMs6R6qFtA=

pkg/crd/gen.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
6262
parser.NeedPackage(root)
6363
}
6464

65-
metav1Pkg := findMetav1(ctx.Roots)
65+
metav1Pkg := FindMetav1(ctx.Roots)
6666
if metav1Pkg == nil {
6767
// no objects in the roots, since nothing imported metav1
6868
return nil
6969
}
7070

7171
// TODO: allow selecting a specific object
72-
kubeKinds := findKubeKinds(parser, metav1Pkg)
72+
kubeKinds := FindKubeKinds(parser, metav1Pkg)
7373
if len(kubeKinds) == 0 {
7474
// no objects in the roots
7575
return nil
@@ -116,9 +116,9 @@ func toTrivialVersions(crd *apiext.CustomResourceDefinition) {
116116
crd.Spec.AdditionalPrinterColumns = canonicalColumns
117117
}
118118

119-
// findMetav1 locates the actual package representing metav1 amongst
119+
// FindMetav1 locates the actual package representing metav1 amongst
120120
// the imports of the roots.
121-
func findMetav1(roots []*loader.Package) *loader.Package {
121+
func FindMetav1(roots []*loader.Package) *loader.Package {
122122
for _, root := range roots {
123123
pkg := root.Imports()["k8s.io/apimachinery/pkg/apis/meta/v1"]
124124
if pkg != nil {
@@ -128,10 +128,10 @@ func findMetav1(roots []*loader.Package) *loader.Package {
128128
return nil
129129
}
130130

131-
// findKubeKinds locates all types that contain TypeMeta and ObjectMeta
131+
// FindKubeKinds locates all types that contain TypeMeta and ObjectMeta
132132
// (and thus may be a Kubernetes object), and returns the corresponding
133133
// group-kinds.
134-
func findKubeKinds(parser *Parser, metav1Pkg *loader.Package) []schema.GroupKind {
134+
func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) []schema.GroupKind {
135135
// TODO(directxman12): technically, we should be finding metav1 per-package
136136
var kubeKinds []schema.GroupKind
137137
for typeIdent, info := range parser.Types {

pkg/crd/parser.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ type Parser struct {
5858
GroupVersions map[*loader.Package]schema.GroupVersion
5959
// CustomResourceDefinitions contains the known CustomResourceDefinitions for types in this parser.
6060
CustomResourceDefinitions map[schema.GroupKind]apiext.CustomResourceDefinition
61+
// FlattenedSchemata contains fully flattened schemata for use in building
62+
// CustomResourceDefinition validation. Each schema has been flattened by the flattener,
63+
// and then embedded fields have been flattened with FlattenEmbedded.
64+
FlattenedSchemata map[TypeIdent]apiext.JSONSchemaProps
6165

6266
// PackageOverrides indicates that the loading of any package with
6367
// the given path should be handled by the given overrider.
@@ -95,6 +99,9 @@ func (p *Parser) init() {
9599
if p.CustomResourceDefinitions == nil {
96100
p.CustomResourceDefinitions = make(map[schema.GroupKind]apiext.CustomResourceDefinition)
97101
}
102+
if p.FlattenedSchemata == nil {
103+
p.FlattenedSchemata = make(map[TypeIdent]apiext.JSONSchemaProps)
104+
}
98105
}
99106

100107
// indexTypes loads all types in the package into Types.
@@ -162,8 +169,20 @@ func (p *Parser) NeedSchemaFor(typ TypeIdent) {
162169
schema := infoToSchema(ctxForInfo)
163170

164171
p.Schemata[typ] = *schema
172+
}
173+
174+
func (p *Parser) NeedFlattenedSchemaFor(typ TypeIdent) {
175+
p.init()
176+
177+
if _, knownSchema := p.FlattenedSchemata[typ]; knownSchema {
178+
return
179+
}
180+
181+
p.NeedSchemaFor(typ)
182+
partialFlattened := p.flattener.FlattenType(typ)
183+
fullyFlattened := FlattenEmbedded(partialFlattened, typ.Package)
165184

166-
return
185+
p.FlattenedSchemata[typ] = *fullyFlattened
167186
}
168187

169188
// NeedCRDFor lives off in spec.go

pkg/crd/spec.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,17 @@ func (p *Parser) NeedCRDFor(groupKind schema.GroupKind, maxDescLen *int) {
160160
if typeInfo == nil {
161161
continue
162162
}
163-
fullSchema := FlattenEmbedded(p.flattener.FlattenType(typeIdent), pkg)
163+
p.NeedFlattenedSchemaFor(typeIdent)
164+
fullSchema := p.FlattenedSchemata[typeIdent]
165+
fullSchema = *fullSchema.DeepCopy() // don't mutate the cache (we might be truncating description, etc)
164166
if maxDescLen != nil {
165-
TruncateDescription(fullSchema, *maxDescLen)
167+
TruncateDescription(&fullSchema, *maxDescLen)
166168
}
167169
ver := apiext.CustomResourceDefinitionVersion{
168170
Name: p.GroupVersions[pkg].Version,
169171
Served: true,
170172
Schema: &apiext.CustomResourceValidation{
171-
OpenAPIV3Schema: fullSchema,
173+
OpenAPIV3Schema: &fullSchema, // fine to take a reference since we deepcopy above
172174
},
173175
}
174176
crd.Spec.Versions = append(crd.Spec.Versions, ver)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package schemapatcher_test
18+
19+
import (
20+
"testing"
21+
22+
. "github.com/onsi/ginkgo"
23+
. "github.com/onsi/gomega"
24+
)
25+
26+
func TestInPlaceCRDSchemaGeneration(t *testing.T) {
27+
RegisterFailHandler(Fail)
28+
RunSpecs(t, "In-Place CRD Patching Suite")
29+
}

0 commit comments

Comments
 (0)