Auto-update dependencies (#196)

Produced via:
  `dep ensure -update knative.dev/test-infra knative.dev/pkg`
/assign n3wscott
/cc n3wscott
This commit is contained in:
Matt Moore 2020-02-05 07:56:31 -08:00 committed by GitHub
parent 5dcbd8b57e
commit 070d8a0d12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 922 additions and 25 deletions

6
Gopkg.lock generated
View File

@ -966,7 +966,7 @@
[[projects]]
branch = "master"
digest = "1:26325ee882afecdb033204b8f2d8e69f0d939f5bcc1a1b151233a7d78d74f7dc"
digest = "1:0fdbfd5bd4573f59828ede757341dd6905ab4fdb0df9fd0aa8ead8fb93900e52"
name = "knative.dev/pkg"
packages = [
"apis",
@ -985,7 +985,7 @@
"metrics/metricskey",
]
pruneopts = "T"
revision = "7ddd3b6a42f6c3db48561e5d9525c66b546bab01"
revision = "b9974987c245c4996a7d1299c3d162a4b0b0ad5e"
[[projects]]
branch = "master"
@ -996,7 +996,7 @@
"tools/dep-collector",
]
pruneopts = "UT"
revision = "7086222c769000dd2122c44de8f43bbb335ad81a"
revision = "77b975af074880c49957946a6d861e063e11f232"
[[projects]]
digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c"

1
vendor/knative.dev/pkg/Gopkg.lock generated vendored
View File

@ -1478,6 +1478,7 @@
"k8s.io/code-generator/cmd/defaulter-gen",
"k8s.io/code-generator/cmd/informer-gen",
"k8s.io/code-generator/cmd/lister-gen",
"k8s.io/code-generator/pkg/namer",
"k8s.io/code-generator/pkg/util",
"k8s.io/gengo/args",
"k8s.io/gengo/generator",

View File

@ -27,6 +27,7 @@ import (
type CustomArgs struct {
VersionedClientSetPackage string
ExternalVersionsInformersPackage string
ListersPackage string
}
// NewDefaults returns default arguments for the generator.
@ -41,6 +42,7 @@ func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&ca.VersionedClientSetPackage, "versioned-clientset-package", ca.VersionedClientSetPackage, "the full package name for the versioned injection clientset to use")
fs.StringVar(&ca.ExternalVersionsInformersPackage, "external-versions-informers-package", ca.ExternalVersionsInformersPackage, "the full package name for the external versions injection informer to use")
fs.StringVar(&ca.ListersPackage, "listers-package", ca.ListersPackage, "the full package name for client listers to use")
}
// Validate checks the given arguments.

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubernetes Authors.
Copyright 2019 The Knative Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubernetes Authors.
Copyright 2019 The Knative Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubernetes Authors.
Copyright 2019 The Knative Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubernetes Authors.
Copyright 2019 The Knative Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubernetes Authors.
Copyright 2019 The Knative Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -19,6 +19,7 @@ package generators
import (
"strings"
codegennamer "k8s.io/code-generator/pkg/namer"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
@ -28,13 +29,26 @@ func NameSystems() namer.NameSystems {
pluralExceptions := map[string]string{
"Endpoints": "Endpoints",
}
publicPluralNamer := namer.NewPublicPluralNamer(pluralExceptions)
publicNamer := &ExceptionNamer{
Exceptions: map[string]string{},
KeyFunc: func(t *types.Type) string {
return t.Name.Package + "." + t.Name.Name
},
Delegate: namer.NewPublicNamer(0),
}
return namer.NameSystems{
"public": namer.NewPublicNamer(0),
"private": namer.NewPrivateNamer(0),
"raw": namer.NewRawNamer("", nil),
"publicPlural": namer.NewPublicPluralNamer(pluralExceptions),
"publicPlural": publicPluralNamer,
"allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions),
"lowercaseSingular": &lowercaseSingularNamer{},
"apiGroup": codegennamer.NewTagOverrideNamer("publicPlural", publicPluralNamer),
"versionedClientset": &versionedClientsetNamer{public: publicNamer},
}
}
@ -46,6 +60,22 @@ func (n *lowercaseSingularNamer) Name(t *types.Type) string {
return strings.ToLower(t.Name.Name)
}
type versionedClientsetNamer struct {
public *ExceptionNamer
}
func (r *versionedClientsetNamer) Name(t *types.Type) string {
// Turns type into a GroupVersion type string based on package.
parts := strings.Split(t.Name.Package, "/")
group := parts[len(parts)-2]
version := parts[len(parts)-1]
g := r.public.Name(&types.Type{Name: types.Name{Name: group, Package: t.Name.Package}})
v := r.public.Name(&types.Type{Name: types.Name{Name: version, Package: t.Name.Package}})
return g + v
}
// DefaultNameSystem returns the default name system for ordering the types to be
// processed by the generators in this package.
func DefaultNameSystem() string {

View File

@ -17,7 +17,6 @@ limitations under the License.
package generators
import (
"fmt"
"path"
"path/filepath"
"strings"
@ -87,6 +86,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
var typesWithInformers []*types.Type
var duckTypes []*types.Type
var reconcilerTypes []*types.Type
for _, t := range p.Types {
tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if tags.NeedsInformerInjection() {
@ -95,6 +95,9 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
if tags.NeedsDuckInjection() {
duckTypes = append(duckTypes, t)
}
if tags.NeedsReconciler() {
reconcilerTypes = append(reconcilerTypes, t)
}
}
groupVersionsEntry, ok := targetGroupVersions[groupPackageName]
@ -122,6 +125,14 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
// Generate a duck-typed informer for each type.
packageList = append(packageList, versionDuckPackages(versionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, duckTypes, customArgs)...)
}
if len(reconcilerTypes) != 0 {
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
reconcilerTypes = orderer.OrderTypes(reconcilerTypes)
// Generate a reconciler and controller for each type.
packageList = append(packageList, reconcilerPackages(versionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, reconcilerTypes, customArgs)...)
}
}
return packageList
@ -131,7 +142,8 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
type Tags struct {
util.Tags
GenerateDuck bool
GenerateDuck bool
GenerateReconciler bool
}
func (t Tags) NeedsInformerInjection() bool {
@ -142,6 +154,10 @@ func (t Tags) NeedsDuckInjection() bool {
return t.GenerateDuck
}
func (t Tags) NeedsReconciler() bool {
return t.GenerateReconciler
}
// MustParseClientGenTags calls ParseClientGenTags but instead of returning error it panics.
func MustParseClientGenTags(lines []string) Tags {
ret := Tags{
@ -151,6 +167,7 @@ func MustParseClientGenTags(lines []string) Tags {
values := types.ExtractCommentTags("+", lines)
// log.Printf("GOT values %v", values)
_, ret.GenerateDuck = values["genduck"]
_, ret.GenerateReconciler = values["genreconciler"]
return ret
}
@ -203,7 +220,7 @@ func versionClientsPackages(basePackage string, boilerplate []byte, customArgs *
// Fake
vers = append(vers, &generator.DefaultPackage{
PackageName: "fake",
PackagePath: packagePath + "/fake",
PackagePath: filepath.Join(packagePath, "fake"),
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
@ -212,9 +229,9 @@ func versionClientsPackages(basePackage string, boilerplate []byte, customArgs *
DefaultGen: generator.DefaultGen{
OptionalName: "fake",
},
outputPackage: packagePath + "/fake",
outputPackage: filepath.Join(packagePath, "fake"),
imports: generator.NewImportTracker(),
fakeClientPkg: customArgs.VersionedClientSetPackage + "/fake",
fakeClientPkg: filepath.Join(customArgs.VersionedClientSetPackage, "fake"),
clientInjectionPkg: packagePath,
})
@ -246,7 +263,7 @@ func versionFactoryPackages(basePackage string, boilerplate []byte, customArgs *
OptionalName: "factory",
},
outputPackage: packagePath,
cachingClientSetPackage: fmt.Sprintf("%s/client", basePackage),
cachingClientSetPackage: filepath.Join(basePackage, "client"),
sharedInformerFactoryPackage: customArgs.ExternalVersionsInformersPackage,
imports: generator.NewImportTracker(),
})
@ -262,7 +279,7 @@ func versionFactoryPackages(basePackage string, boilerplate []byte, customArgs *
// Fake
vers = append(vers, &generator.DefaultPackage{
PackageName: "fake",
PackagePath: packagePath + "/fake",
PackagePath: filepath.Join(packagePath, "fake"),
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
@ -271,9 +288,9 @@ func versionFactoryPackages(basePackage string, boilerplate []byte, customArgs *
DefaultGen: generator.DefaultGen{
OptionalName: "fake",
},
outputPackage: packagePath + "/fake",
outputPackage: filepath.Join(packagePath, "fake"),
factoryInjectionPkg: packagePath,
fakeClientInjectionPkg: fmt.Sprintf("%s/client/fake", basePackage),
fakeClientInjectionPkg: filepath.Join(basePackage, "client", "fake"),
sharedInformerFactoryPackage: customArgs.ExternalVersionsInformersPackage,
imports: generator.NewImportTracker(),
})
@ -333,7 +350,7 @@ func versionInformerPackages(basePackage string, groupPkgName string, gv clientg
// Fake
vers = append(vers, &generator.DefaultPackage{
PackageName: "fake",
PackagePath: packagePath + "/fake",
PackagePath: filepath.Join(packagePath, "fake"),
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
// Impl
@ -341,13 +358,13 @@ func versionInformerPackages(basePackage string, groupPkgName string, gv clientg
DefaultGen: generator.DefaultGen{
OptionalName: "fake",
},
outputPackage: packagePath + "/fake",
outputPackage: filepath.Join(packagePath, "fake"),
imports: generator.NewImportTracker(),
typeToGenerate: t,
groupVersion: gv,
groupGoName: groupGoName,
informerInjectionPkg: packagePath,
fakeFactoryInjectionPkg: factoryPackagePath + "/fake",
fakeFactoryInjectionPkg: filepath.Join(factoryPackagePath, "fake"),
})
return generators
@ -361,6 +378,126 @@ func versionInformerPackages(basePackage string, groupPkgName string, gv clientg
return vers
}
func reconcilerPackages(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, customArgs *informergenargs.CustomArgs) []generator.Package {
packagePath := filepath.Join(basePackage, "reconciler", groupPkgName, strings.ToLower(gv.Version.NonEmpty()))
vers := make([]generator.Package, 0, len(typesToGenerate))
for _, t := range typesToGenerate {
// Fix for golang iterator bug.
t := t
packagePath := filepath.Join(packagePath, strings.ToLower(t.Name.Name))
clientPackagePath := filepath.Join(basePackage, "client")
informerPackagePath := filepath.Join(basePackage, "informers", groupPkgName, strings.ToLower(gv.Version.NonEmpty()), strings.ToLower(t.Name.Name))
listerPackagePath := filepath.Join(customArgs.ListersPackage, groupPkgName, strings.ToLower(gv.Version.NonEmpty()))
// Controller
vers = append(vers, &generator.DefaultPackage{
PackageName: strings.ToLower(t.Name.Name),
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
// Impl
generators = append(generators, &reconcilerControllerGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "controller",
},
outputPackage: packagePath,
imports: generator.NewImportTracker(),
clientPkg: clientPackagePath,
informerPackagePath: informerPackagePath,
schemePkg: filepath.Join(customArgs.VersionedClientSetPackage, "scheme"),
})
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.NeedsReconciler()
},
})
// Controller Stub
vers = append(vers, &generator.DefaultPackage{
PackageName: strings.ToLower(t.Name.Name),
PackagePath: filepath.Join(packagePath, "stub"),
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
// Impl
generators = append(generators, &reconcilerControllerStubGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "controller",
},
reconcilerPkg: packagePath,
outputPackage: filepath.Join(packagePath, "stub"),
imports: generator.NewImportTracker(),
informerPackagePath: informerPackagePath,
})
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.NeedsReconciler()
},
})
// Reconciler
vers = append(vers, &generator.DefaultPackage{
PackageName: strings.ToLower(t.Name.Name),
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
// Impl
generators = append(generators, &reconcilerReconcilerGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "reconciler",
},
outputPackage: packagePath,
imports: generator.NewImportTracker(),
clientsetPkg: customArgs.VersionedClientSetPackage,
listerName: t.Name.Name + "Lister",
listerPkg: listerPackagePath,
})
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.NeedsReconciler()
},
})
// Reconciler Stub
vers = append(vers, &generator.DefaultPackage{
PackageName: strings.ToLower(t.Name.Name),
PackagePath: filepath.Join(packagePath, "stub"),
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
// Impl
generators = append(generators, &reconcilerReconcilerStubGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "reconciler",
},
reconcilerPkg: packagePath,
outputPackage: filepath.Join(packagePath, "stub"),
imports: generator.NewImportTracker(),
})
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.NeedsReconciler()
},
})
}
return vers
}
func versionDuckPackages(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, customArgs *informergenargs.CustomArgs) []generator.Package {
packagePath := filepath.Join(basePackage, "ducks", groupPkgName, strings.ToLower(gv.Version.NonEmpty()))
@ -370,7 +507,7 @@ func versionDuckPackages(basePackage string, groupPkgName string, gv clientgenty
// Fix for golang iterator bug.
t := t
packagePath := packagePath + "/" + strings.ToLower(t.Name.Name)
packagePath := filepath.Join(packagePath, strings.ToLower(t.Name.Name))
// Impl
vers = append(vers, &generator.DefaultPackage{
@ -401,7 +538,7 @@ func versionDuckPackages(basePackage string, groupPkgName string, gv clientgenty
// Fake
vers = append(vers, &generator.DefaultPackage{
PackageName: "fake",
PackagePath: packagePath + "/fake",
PackagePath: filepath.Join(packagePath, "fake"),
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
// Impl
@ -409,7 +546,7 @@ func versionDuckPackages(basePackage string, groupPkgName string, gv clientgenty
DefaultGen: generator.DefaultGen{
OptionalName: "fake",
},
outputPackage: packagePath + "/fake",
outputPackage: filepath.Join(packagePath, "fake"),
imports: generator.NewImportTracker(),
typeToGenerate: t,
groupVersion: gv,

View File

@ -0,0 +1,131 @@
/*
Copyright 2020 The Knative Authors.
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 generators
import (
"io"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/klog"
)
// reconcilerControllerGenerator produces a file for setting up the reconciler
// with injection.
type reconcilerControllerGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
filtered bool
clientPkg string
schemePkg string
informerPackagePath string
}
var _ generator.Generator = (*reconcilerControllerGenerator)(nil)
func (g *reconcilerControllerGenerator) Filter(c *generator.Context, t *types.Type) bool {
// We generate a single client, so return true once.
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *reconcilerControllerGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *reconcilerControllerGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
func (g *reconcilerControllerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "{{", "}}")
klog.V(5).Infof("processing type %v", t)
m := map[string]interface{}{
"type": t,
"controllerImpl": c.Universe.Type(types.Name{
Package: "knative.dev/pkg/controller",
Name: "Impl",
}),
"loggingFromContext": c.Universe.Function(types.Name{
Package: "knative.dev/pkg/logging",
Name: "FromContext",
}),
"corev1EventSource": c.Universe.Function(types.Name{
Package: "k8s.io/api/core/v1",
Name: "EventSource",
}),
"clientGet": c.Universe.Function(types.Name{
Package: g.clientPkg,
Name: "Get",
}),
"informerGet": c.Universe.Function(types.Name{
Package: g.informerPackagePath,
Name: "Get",
}),
"schemeScheme": c.Universe.Function(types.Name{
Package: "k8s.io/client-go/kubernetes/scheme",
Name: "Scheme",
}),
"schemeAddToScheme": c.Universe.Function(types.Name{
Package: g.schemePkg,
Name: "Scheme",
}),
}
sw.Do(reconcilerControllerNewImpl, m)
return sw.Error()
}
var reconcilerControllerNewImpl = `
const (
defaultControllerAgentName = "{{.type|lowercaseSingular}}-controller"
defaultFinalizerName = "{{.type|lowercaseSingular}}"
)
func NewImpl(ctx context.Context, r Interface) *{{.controllerImpl|raw}} {
logger := {{.loggingFromContext|raw}}(ctx)
{{.type|lowercaseSingular}}Informer := {{.informerGet|raw}}(ctx)
c := &reconcilerImpl{
Client: {{.clientGet|raw}}(ctx),
Lister: {{.type|lowercaseSingular}}Informer.Lister(),
Recorder: record.NewBroadcaster().NewRecorder(
scheme.Scheme, {{.corev1EventSource|raw}}{Component: defaultControllerAgentName}),
FinalizerName: defaultFinalizerName,
reconciler: r,
}
impl := controller.NewImpl(c, logger, "{{.type|allLowercasePlural}}")
return impl
}
func init() {
{{.schemeAddToScheme|raw}}({{.schemeScheme|raw}})
}
`

View File

@ -0,0 +1,114 @@
/*
Copyright 2020 The Knative Authors.
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 generators
import (
"io"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/klog"
)
// reconcilerControllerStubGenerator produces a file of the stub of the
// controller for a custom impl with injection.
type reconcilerControllerStubGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
filtered bool
reconcilerPkg string
informerPackagePath string
}
var _ generator.Generator = (*reconcilerControllerStubGenerator)(nil)
func (g *reconcilerControllerStubGenerator) Filter(c *generator.Context, t *types.Type) bool {
// We generate a single client, so return true once.
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *reconcilerControllerStubGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *reconcilerControllerStubGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
func (g *reconcilerControllerStubGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "{{", "}}")
klog.V(5).Infof("processing type %v", t)
m := map[string]interface{}{
"type": t,
"informerGet": c.Universe.Function(types.Name{
Package: g.informerPackagePath,
Name: "Get",
}),
"controllerImpl": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "Impl"}),
"reconcilerNewImpl": c.Universe.Type(types.Name{
Package: g.reconcilerPkg,
Name: "NewImpl",
}),
"loggingFromContext": c.Universe.Function(types.Name{
Package: "knative.dev/pkg/logging",
Name: "FromContext",
}),
}
sw.Do(reconcilerControllerStub, m)
return sw.Error()
}
var reconcilerControllerStub = `
// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT
// NewController creates a Reconciler for {{.type|public}} and returns the result of NewImpl.
func NewController(
ctx context.Context,
cmw configmap.Watcher,
) *{{.controllerImpl|raw}} {
logger := {{.loggingFromContext|raw}}(ctx)
{{.type|lowercaseSingular}}Informer := {{.informerGet|raw}}(ctx)
// TODO: setup additional informers here.
r := &Reconciler{}
impl := {{.reconcilerNewImpl|raw}}(ctx, r)
logger.Info("Setting up event handlers.")
{{.type|lowercaseSingular}}Informer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue))
// TODO: add additional informer event handlers here.
return impl
}
`

View File

@ -0,0 +1,356 @@
/*
Copyright 2020 The Knative Authors.
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 generators
import (
"io"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/klog"
)
// reconcilerReconcilerGenerator produces a reconciler struct for the given type.
type reconcilerReconcilerGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
filtered bool
clientsetPkg string
listerName string
listerPkg string
}
var _ generator.Generator = (*reconcilerReconcilerGenerator)(nil)
func (g *reconcilerReconcilerGenerator) Filter(c *generator.Context, t *types.Type) bool {
// We generate a single client, so return true once.
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *reconcilerReconcilerGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *reconcilerReconcilerGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "{{", "}}")
klog.V(5).Infof("processing type %v", t)
m := map[string]interface{}{
"type": t,
"controllerImpl": c.Universe.Type(types.Name{
Package: "knative.dev/pkg/controller",
Name: "Impl",
}),
"controllerReconciler": c.Universe.Type(types.Name{
Package: "knative.dev/pkg/controller",
Name: "Reconciler",
}),
"corev1EventSource": c.Universe.Function(types.Name{
Package: "k8s.io/api/core/v1",
Name: "EventSource",
}),
"corev1EventTypeNormal": c.Universe.Type(types.Name{
Package: "k8s.io/api/core/v1",
Name: "EventTypeNormal",
}),
"corev1EventTypeWarning": c.Universe.Type(types.Name{
Package: "k8s.io/api/core/v1",
Name: "EventTypeWarning",
}),
"reconcilerEvent": c.Universe.Type(types.Name{Package: "knative.dev/pkg/reconciler", Name: "Event"}),
"reconcilerReconcilerEvent": c.Universe.Type(types.Name{Package: "knative.dev/pkg/reconciler", Name: "ReconcilerEvent"}),
// Deps
"clientsetInterface": c.Universe.Type(types.Name{Name: "Interface", Package: g.clientsetPkg}),
"resourceLister": c.Universe.Type(types.Name{Name: g.listerName, Package: g.listerPkg}),
// K8s types
"recordEventRecorder": c.Universe.Type(types.Name{Name: "EventRecorder", Package: "k8s.io/client-go/tools/record"}),
// methods
"loggingFromContext": c.Universe.Function(types.Name{
Package: "knative.dev/pkg/logging",
Name: "FromContext",
}),
"cacheSplitMetaNamespaceKey": c.Universe.Function(types.Name{
Package: "k8s.io/client-go/tools/cache",
Name: "SplitMetaNamespaceKey",
}),
"retryRetryOnConflict": c.Universe.Function(types.Name{
Package: "k8s.io/client-go/util/retry",
Name: "RetryOnConflict",
}),
"apierrsIsNotFound": c.Universe.Function(types.Name{
Package: "k8s.io/apimachinery/pkg/api/errors",
Name: "IsNotFound",
}),
"metav1GetOptions": c.Universe.Function(types.Name{
Package: "k8s.io/apimachinery/pkg/apis/meta/v1",
Name: "GetOptions",
}),
"zapSugaredLogger": c.Universe.Type(types.Name{
Package: "go.uber.org/zap",
Name: "SugaredLogger",
}),
}
sw.Do(reconcilerInterfaceFactory, m)
sw.Do(reconcilerNewReconciler, m)
sw.Do(reconcilerImplFactory, m)
sw.Do(reconcilerStatusFactory, m)
// TODO(n3wscott): Follow-up to add support for managing finalizers.
// sw.Do(reconcilerFinalizerFactory, m)
return sw.Error()
}
var reconcilerInterfaceFactory = `
// Interface defines the strongly typed interfaces to be implemented by a
// controller reconciling {{.type|raw}}.
type Interface interface {
// ReconcileKind implements custom logic to reconcile {{.type|raw}}. Any changes
// to the objects .Status or .Finalizers will be propagated to the stored
// object. It is recommended that implementors do not call any update calls
// for the Kind inside of ReconcileKind, it is the responsibility of the calling
// controller to propagate those properties.
ReconcileKind(ctx context.Context, o *{{.type|raw}}) {{.reconcilerEvent|raw}}
}
// reconcilerImpl implements controller.Reconciler for {{.type|raw}} resources.
type reconcilerImpl struct {
// Client is used to write back status updates.
Client {{.clientsetInterface|raw}}
// Listers index properties about resources
Lister {{.resourceLister|raw}}
// Recorder is an event recorder for recording Event resources to the
// Kubernetes API.
Recorder {{.recordEventRecorder|raw}}
// FinalizerName is the name of the finalizer to use when finalizing the
// resource.
FinalizerName string
// reconciler is the implementation of the business logic of the resource.
reconciler Interface
}
// Check that our Reconciler implements controller.Reconciler
var _ controller.Reconciler = (*reconcilerImpl)(nil)
`
var reconcilerNewReconciler = `
func NewReconciler(ctx context.Context, logger *{{.zapSugaredLogger|raw}}, client {{.clientsetInterface|raw}}, lister {{.resourceLister|raw}}, recorder {{.recordEventRecorder|raw}}, r Interface) {{.controllerReconciler|raw}} {
return &reconcilerImpl{
Client: client,
Lister: lister,
Recorder: recorder,
FinalizerName: defaultFinalizerName,
reconciler: r,
}
}
`
var reconcilerImplFactory = `
// Reconcile implements controller.Reconciler
func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
logger := {{.loggingFromContext|raw}}(ctx)
// Convert the namespace/name string into a distinct namespace and name
namespace, name, err := {{.cacheSplitMetaNamespaceKey|raw}}(key)
if err != nil {
logger.Errorf("invalid resource key: %s", key)
return nil
}
// TODO(n3wscott): this is needed for serving.
// If our controller has configuration state, we'd "freeze" it and
// attach the frozen configuration to the context.
// ctx = r.configStore.ToContext(ctx)
// Get the resource with this namespace/name.
original, err := r.Lister.{{.type|apiGroup}}(namespace).Get(name)
if {{.apierrsIsNotFound|raw}}(err) {
// The resource may no longer exist, in which case we stop processing.
logger.Errorf("resource %q no longer exists", key)
return nil
} else if err != nil {
return err
}
// Don't modify the informers copy.
resource := original.DeepCopy()
// Reconcile this copy of the resource and then write back any status
// updates regardless of whether the reconciliation errored out.
reconcileEvent := r.reconciler.ReconcileKind(ctx, resource)
// TODO(n3wscott): Follow-up to add support for managing finalizers.
// Synchronize the finalizers.
//if equality.Semantic.DeepEqual(original.Finalizers, resource.Finalizers) {
// // If we didn't change finalizers then don't call updateFinalizers.
//} else if _, updated, fErr := r.updateFinalizers(ctx, resource); fErr != nil {
// logger.Warnw("Failed to update finalizers", zap.Error(fErr))
// r.Recorder.Eventf(resource, {{.corev1EventTypeWarning|raw}}, "UpdateFailed",
// "Failed to update finalizers for %q: %v", resource.Name, fErr)
// return fErr
//} else if updated {
// // There was a difference and updateFinalizers said it updated and did not return an error.
// r.Recorder.Eventf(resource, {{.corev1EventTypeNormal|raw}}, "Updated", "Updated %q finalizers", resource.GetName())
//}
// Synchronize the status.
if equality.Semantic.DeepEqual(original.Status, resource.Status) {
// If we didn't change anything then don't call updateStatus.
// This is important because the copy we loaded from the injectionInformer's
// cache may be stale and we don't want to overwrite a prior update
// to status with this stale state.
} else if err = r.updateStatus(original, resource); err != nil {
logger.Warnw("Failed to update resource status", zap.Error(err))
r.Recorder.Eventf(resource, {{.corev1EventTypeWarning|raw}}, "UpdateFailed",
"Failed to update status for %q: %v", resource.Name, err)
return err
}
// Report the reconciler event, if any.
if reconcileEvent != nil {
logger.Errorw("ReconcileKind returned an event", zap.Error(reconcileEvent))
var event *{{.reconcilerReconcilerEvent|raw}}
if reconciler.EventAs(reconcileEvent, &event) {
r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...)
return nil
} else {
r.Recorder.Event(resource, {{.corev1EventTypeWarning|raw}}, "InternalError", reconcileEvent.Error())
return reconcileEvent.Error()
}
}
return nil
}
`
var reconcilerStatusFactory = `
func (r *reconcilerImpl) updateStatus(existing *{{.type|raw}}, desired *{{.type|raw}}) error {
existing = existing.DeepCopy()
return RetryUpdateConflicts(func(attempts int) (err error) {
// The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API.
if attempts > 0 {
existing, err = r.Client.{{.type|versionedClientset}}().{{.type|apiGroup}}(desired.Namespace).Get(desired.Name, {{.metav1GetOptions|raw}}{})
if err != nil {
return err
}
}
// If there's nothing to update, just return.
if reflect.DeepEqual(existing.Status, desired.Status) {
return nil
}
existing.Status = desired.Status
_, err = r.Client.{{.type|versionedClientset}}().{{.type|apiGroup}}(existing.Namespace).UpdateStatus(existing)
return err
})
}
// TODO: move this to knative.dev/pkg/reconciler
// RetryUpdateConflicts retries the inner function if it returns conflict errors.
// This can be used to retry status updates without constantly reenqueuing keys.
func RetryUpdateConflicts(updater func(int) error) error {
attempts := 0
return {{.retryRetryOnConflict|raw}}(retry.DefaultRetry, func() error {
err := updater(attempts)
attempts++
return err
})
}
`
var reconcilerFinalizerFactory = `
// Update the Finalizers of the resource.
func (r *reconcilerImpl) updateFinalizers(ctx context.Context, desired *{{.type|raw}}) (*{{.type|raw}}, bool, error) {
actual, err := r.Lister.{{.type|apiGroup}}(desired.Namespace).Get(desired.Name)
if err != nil {
return nil, false, err
}
// Don't modify the informers copy.
existing := actual.DeepCopy()
var finalizers []string
// If there's nothing to update, just return.
existingFinalizers := sets.NewString(existing.Finalizers...)
desiredFinalizers := sets.NewString(desired.Finalizers...)
if desiredFinalizers.Has(r.FinalizerName) {
if existingFinalizers.Has(r.FinalizerName) {
// Nothing to do.
return desired, false, nil
}
// Add the finalizer.
finalizers = append(existing.Finalizers, r.FinalizerName)
} else {
if !existingFinalizers.Has(r.FinalizerName) {
// Nothing to do.
return desired, false, nil
}
// Remove the finalizer.
existingFinalizers.Delete(r.FinalizerName)
finalizers = existingFinalizers.List()
}
mergePatch := map[string]interface{}{
"metadata": map[string]interface{}{
"finalizers": finalizers,
"resourceVersion": existing.ResourceVersion,
},
}
patch, err := json.Marshal(mergePatch)
if err != nil {
return desired, false, err
}
update, err := r.Client.{{.type|versionedClientset}}().{{.type|apiGroup}}(desired.Namespace).Patch(existing.Name, types.MergePatchType, patch)
return update, true, err
}
func (r *reconcilerImpl) setFinalizer(a *{{.type|raw}}) {
finalizers := sets.NewString(a.Finalizers...)
finalizers.Insert(r.FinalizerName)
a.Finalizers = finalizers.List()
}
func (r *reconcilerImpl) unsetFinalizer(a *{{.type|raw}}) {
finalizers := sets.NewString(a.Finalizers...)
finalizers.Delete(r.FinalizerName)
a.Finalizers = finalizers.List()
}
`

View File

@ -0,0 +1,122 @@
/*
Copyright 2020 The Knative Authors.
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 generators
import (
"io"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/klog"
)
// reconcilerReconcilerStubGenerator produces a file of the stub of how to
// implement the reconciler.
type reconcilerReconcilerStubGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
filtered bool
reconcilerPkg string
}
var _ generator.Generator = (*reconcilerReconcilerStubGenerator)(nil)
func (g *reconcilerReconcilerStubGenerator) Filter(c *generator.Context, t *types.Type) bool {
// We generate a single client, so return true once.
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *reconcilerReconcilerStubGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *reconcilerReconcilerStubGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
func (g *reconcilerReconcilerStubGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "{{", "}}")
klog.V(5).Infof("processing type %v", t)
m := map[string]interface{}{
"type": t,
"reconcilerEvent": c.Universe.Type(types.Name{
Package: "knative.dev/pkg/reconciler",
Name: "Event",
}),
"reconcilerNewEvent": c.Universe.Function(types.Name{
Package: "knative.dev/pkg/reconciler",
Name: "NewEvent",
}),
"reconcilerInterface": c.Universe.Type(types.Name{
Package: g.reconcilerPkg,
Name: "Interface",
}),
"corev1EventTypeNormal": c.Universe.Type(types.Name{
Package: "k8s.io/api/core/v1",
Name: "EventTypeNormal",
}),
}
sw.Do(reconcilerReconcilerStub, m)
return sw.Error()
}
var reconcilerReconcilerStub = `
// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT
// newReconciledNormal makes a new reconciler event with event type Normal, and
// reason {{.type|public}}Reconciled.
func newReconciledNormal(namespace, name string) reconciler.Event {
return {{.reconcilerNewEvent|raw}}({{.corev1EventTypeNormal|raw}}, "{{.type|public}}Reconciled", "{{.type|public}} reconciled: \"%s/%s\"", namespace, name)
}
// Reconciler implements controller.Reconciler for {{.type|public}} resources.
type Reconciler struct {
// TODO: add additional requirements here.
}
// Check that our Reconciler implements Interface
var _ {{.reconcilerInterface|raw}} = (*Reconciler)(nil)
// ReconcileKind implements Interface.ReconcileKind.
func (r *Reconciler) ReconcileKind(ctx context.Context, o *{{.type|raw}}) {{.reconcilerEvent|raw}} {
if o.GetDeletionTimestamp() != nil {
// Check for a DeletionTimestamp. If present, elide the normal reconcile logic.
// When a controller needs finalizer handling, it would go here.
return nil
}
o.Status.InitializeConditions()
// TODO: add custom reconciliation logic here.
o.Status.ObservedGeneration = o.Generation
return newReconciledNormal(o.Namespace, o.Name)
}
`

View File

@ -80,6 +80,10 @@ if grep -qw "injection" <<<"${GENS}"; then
EXTERNAL_INFORMER_PKG="${CLIENT_PKG}/informers/externalversions"
fi
if [[ -z "${LISTERS_PKG:-}" ]]; then
LISTERS_PKG="${CLIENT_PKG}/listers"
fi
echo "Generating injection for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}"
# Clear old injection
@ -89,7 +93,7 @@ if grep -qw "injection" <<<"${GENS}"; then
--input-dirs $(codegen::join , "${FQ_APIS[@]}") \
--versioned-clientset-package ${VERSIONED_CLIENTSET_PKG} \
--external-versions-informers-package ${EXTERNAL_INFORMER_PKG} \
--listers-package ${LISTERS_PKG} \
--output-package ${OUTPUT_PKG} \
"$@"
fi