diff --git a/apis/test/example/v1alpha1/foo_types.go b/apis/test/example/v1alpha1/foo_types.go index 232612732..ebe255341 100644 --- a/apis/test/example/v1alpha1/foo_types.go +++ b/apis/test/example/v1alpha1/foo_types.go @@ -27,7 +27,7 @@ import ( ) // +genclient -// +genreconciler +// +genreconciler:krshapedlogic=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Foo is for testing. diff --git a/apis/test/pub/v1alpha1/bar_types.go b/apis/test/pub/v1alpha1/bar_types.go index 2227a6142..826dae3fb 100644 --- a/apis/test/pub/v1alpha1/bar_types.go +++ b/apis/test/pub/v1alpha1/bar_types.go @@ -27,7 +27,7 @@ import ( ) // +genclient -// +genreconciler:class=example.com/filter.class +// +genreconciler:class=example.com/filter.class,krshapedlogic=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Bar is for testing. diff --git a/codegen/cmd/injection-gen/generators/packages.go b/codegen/cmd/injection-gen/generators/packages.go index a53dc8b02..287257069 100644 --- a/codegen/cmd/injection-gen/generators/packages.go +++ b/codegen/cmd/injection-gen/generators/packages.go @@ -211,6 +211,15 @@ func isNonNamespaced(tags map[string]map[string]string) bool { return has } +func isKRShaped(tags map[string]map[string]string) bool { + vals, has := tags["genclient"] + if !has { + return false + } + shaped, _ := vals["krshapedlogic"] + return shaped == "true" +} + func vendorless(p string) string { if pos := strings.LastIndex(p, "/vendor/"); pos != -1 { return p[pos+len("/vendor/"):] @@ -424,6 +433,7 @@ func reconcilerPackages(basePackage string, groupPkgName string, gv clientgentyp extracted := extractCommentTags(t) reconcilerClass, hasReconcilerClass := extractReconcilerClassTag(extracted) nonNamespaced := isNonNamespaced(extracted) + isKRShaped := isKRShaped(extracted) packagePath := filepath.Join(packagePath, strings.ToLower(t.Name.Name)) @@ -512,6 +522,7 @@ func reconcilerPackages(basePackage string, groupPkgName string, gv clientgentyp reconcilerClass: reconcilerClass, hasReconcilerClass: hasReconcilerClass, nonNamespaced: nonNamespaced, + isKRShaped: isKRShaped, }) return generators diff --git a/codegen/cmd/injection-gen/generators/reconciler_reconciler.go b/codegen/cmd/injection-gen/generators/reconciler_reconciler.go index 0d098ab60..a0defc4ea 100644 --- a/codegen/cmd/injection-gen/generators/reconciler_reconciler.go +++ b/codegen/cmd/injection-gen/generators/reconciler_reconciler.go @@ -40,6 +40,7 @@ type reconcilerReconcilerGenerator struct { reconcilerClass string hasReconcilerClass bool nonNamespaced bool + isKRShaped bool groupGoName string groupVersion clientgentypes.GroupVersion @@ -74,6 +75,7 @@ func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *ty "version": namer.IC(g.groupVersion.Version.String()), "class": g.reconcilerClass, "hasClass": g.hasReconcilerClass, + "isKRShaped": g.isKRShaped, "nonNamespaced": g.nonNamespaced, "controllerImpl": c.Universe.Type(types.Name{ Package: "knative.dev/pkg/controller", @@ -309,9 +311,17 @@ func (r *reconcilerImpl) Reconcile(ctx {{.contextContext|raw}}, key string) erro logger.Warnw("Failed to set finalizers", zap.Error(err)) } + {{if .isKRShaped}} + reconciler.PreProcessReconcile(ctx, resource) + {{end}} + // 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) + + {{if .isKRShaped}} + reconciler.PostProcessReconcile(ctx, resource) + {{end}} } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "FinalizeKind")) diff --git a/injection/README.md b/injection/README.md index ab452b6e5..d30b090bc 100644 --- a/injection/README.md +++ b/injection/README.md @@ -452,6 +452,28 @@ value of the `` annotation on a resource must match the value provided to `NewImpl` (or `NewReconcile`) for `ReconcileKind` or `FinalizeKind` to be called for that resource. +#### Annotation based common logic + +**krshaped=true may become the default if omitted in the future** + +Reconcilers can handle common logic for resources that conform to the KRShaped +interface. This allows the generated code to automatically increment +ObservedGeneration. + +```go +// +genreconciler:krshapedlogic=true +``` + +Setting this annotation will emit the following in the generated reconciler. + +```go +reconciler.PreProcessReconcile(ctx, resource) + +reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + +reconciler.PostProcessReconcile(ctx, resource) +``` + #### Stubs To get started, or to use as reference. It is intended to be copied out of the