diff --git a/Gopkg.lock b/Gopkg.lock index 494182c5..32d541e1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -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" diff --git a/vendor/knative.dev/pkg/Gopkg.lock b/vendor/knative.dev/pkg/Gopkg.lock index 1b4dbc3b..3f615e1e 100644 --- a/vendor/knative.dev/pkg/Gopkg.lock +++ b/vendor/knative.dev/pkg/Gopkg.lock @@ -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", diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/args/args.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/args/args.go index a1a1a5a9..38b60630 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/args/args.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/args/args.go @@ -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. diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go index 11d394c8..6d7ccf5c 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/client.go @@ -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. diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeclient.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeclient.go index 47bf9d14..001170a7 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeclient.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeclient.go @@ -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. diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeduck.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeduck.go index df036c61..3ae52467 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeduck.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeduck.go @@ -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. diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakefactory.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakefactory.go index e4edaf70..8b71a7de 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakefactory.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakefactory.go @@ -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. diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go index c8e42230..d0a93f52 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go @@ -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. diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/namesystems.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/namesystems.go index 19749529..a99e1957 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/namesystems.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/namesystems.go @@ -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 { diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go index 2b14c4bd..d18c3347 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go @@ -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, diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go new file mode 100644 index 00000000..897b71b0 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go @@ -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}}) +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go new file mode 100644 index 00000000..6f5ab7d7 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go @@ -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 +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go new file mode 100644 index 00000000..a9d75163 --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go @@ -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() +} +` diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler_stub.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler_stub.go new file mode 100644 index 00000000..5d8d904e --- /dev/null +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler_stub.go @@ -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) +} +` diff --git a/vendor/knative.dev/pkg/hack/generate-knative.sh b/vendor/knative.dev/pkg/hack/generate-knative.sh index 3e03a906..cbd95707 100755 --- a/vendor/knative.dev/pkg/hack/generate-knative.sh +++ b/vendor/knative.dev/pkg/hack/generate-knative.sh @@ -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 -