Skip to content

Commit

Permalink
Merge pull request #351 from aruiz14/v1-generating-handlers-unique-apply
Browse files Browse the repository at this point in the history
[v1.1] Allow GeneratingHandlers to skip Apply if resource version didn't change
  • Loading branch information
mattfarina committed Jan 10, 2024
2 parents ae13f88 + 74f2278 commit b5a5a52
Show file tree
Hide file tree
Showing 22 changed files with 1,142 additions and 21 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.19
require (
github.com/evanphx/json-patch v4.12.0+incompatible
github.com/ghodss/yaml v1.0.0
github.com/golang/mock v1.6.0
github.com/moby/locker v1.0.1
github.com/pkg/errors v0.9.1
github.com/rancher/lasso v0.0.0-20221227210133-6ea88ca2fbcc
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -805,6 +806,7 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
Expand Down
5 changes: 3 additions & 2 deletions pkg/apply/fake/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ var _ apply.Apply = (*FakeApply)(nil)

type FakeApply struct {
Objects []*objectset.ObjectSet
Count int
}

func (f *FakeApply) Apply(set *objectset.ObjectSet) error {
f.Objects = append(f.Objects, set)
f.Count++
return nil
}

func (f *FakeApply) ApplyObjects(objs ...runtime.Object) error {
os := objectset.NewObjectSet()
os.Add(objs...)
f.Objects = append(f.Objects, os)
return nil
return f.Apply(os)
}

func (f *FakeApply) WithCacheTypes(igs ...apply.InformerGetter) apply.Apply {
Expand Down
56 changes: 51 additions & 5 deletions pkg/controller-gen/generators/type_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,14 @@ func (c *{{.lowerName}}Cache) GetByIndex(indexName, key string) (result []*{{.ve
}
{{ if .hasStatus -}}
// {{.type}}StatusHandler is executed for every added or modified {{.type}}. Should return the new status to be updated
type {{.type}}StatusHandler func(obj *{{.version}}.{{.type}}, status {{.version}}.{{.statusType}}) ({{.version}}.{{.statusType}}, error)
// {{.type}}GeneratingHandler is the top-level handler that is executed for every {{.type}} event. It extends {{.type}}StatusHandler by a returning a slice of child objects to be passed to apply.Apply
type {{.type}}GeneratingHandler func(obj *{{.version}}.{{.type}}, status {{.version}}.{{.statusType}}) ([]runtime.Object, {{.version}}.{{.statusType}}, error)
// Register{{.type}}StatusHandler configures a {{.type}}Controller to execute a {{.type}}StatusHandler for every events observed.
// If a non-empty condition is provided, it will be updated in the status conditions for every handler execution
func Register{{.type}}StatusHandler(ctx context.Context, controller {{.type}}Controller, condition condition.Cond, name string, handler {{.type}}StatusHandler) {
statusHandler := &{{.lowerName}}StatusHandler{
client: controller,
Expand All @@ -326,6 +330,8 @@ func Register{{.type}}StatusHandler(ctx context.Context, controller {{.type}}Con
controller.AddGenericHandler(ctx, name, From{{.type}}HandlerToHandler(statusHandler.sync))
}
// Register{{.type}}GeneratingHandler configures a {{.type}}Controller to execute a {{.type}}GeneratingHandler for every events observed, passing the returned objects to the provided apply.Apply.
// If a non-empty condition is provided, it will be updated in the status conditions for every handler execution
func Register{{.type}}GeneratingHandler(ctx context.Context, controller {{.type}}Controller, apply apply.Apply,
condition condition.Cond, name string, handler {{.type}}GeneratingHandler, opts *generic.GeneratingHandlerOptions) {
statusHandler := &{{.lowerName}}GeneratingHandler{
Expand All @@ -347,6 +353,7 @@ type {{.lowerName}}StatusHandler struct {
handler {{.type}}StatusHandler
}
// sync is executed on every resource addition or modification. Executes the configured handlers and sends the updated status to the Kubernetes API
func (a *{{.lowerName}}StatusHandler) sync(key string, obj *{{.version}}.{{.type}}) (*{{.version}}.{{.type}}, error) {
if obj == nil {
return obj, nil
Expand Down Expand Up @@ -388,12 +395,14 @@ func (a *{{.lowerName}}StatusHandler) sync(key string, obj *{{.version}}.{{.type
type {{.lowerName}}GeneratingHandler struct {
{{.type}}GeneratingHandler
apply apply.Apply
opts generic.GeneratingHandlerOptions
gvk schema.GroupVersionKind
name string
apply apply.Apply
opts generic.GeneratingHandlerOptions
gvk schema.GroupVersionKind
name string
seen sync.Map
}
// Remove handles the observed deletion of a resource, cascade deleting every associated resource previously applied
func (a *{{.lowerName}}GeneratingHandler) Remove(key string, obj *{{.version}}.{{.type}}) (*{{.version}}.{{.type}}, error) {
if obj != nil {
return obj, nil
Expand All @@ -403,12 +412,17 @@ func (a *{{.lowerName}}GeneratingHandler) Remove(key string, obj *{{.version}}.{
obj.Namespace, obj.Name = kv.RSplit(key, "/")
obj.SetGroupVersionKind(a.gvk)
if a.opts.UniqueApplyForResourceVersion {
a.seen.Delete(key)
}
return nil, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj).
WithSetID(a.name).
ApplyObjects()
}
// Handle executes the configured {{.type}}GeneratingHandler and pass the resulting objects to apply.Apply, finally returning the new status of the resource
func (a *{{.lowerName}}GeneratingHandler) Handle(obj *{{.version}}.{{.type}}, status {{.version}}.{{.statusType}}) ({{.version}}.{{.statusType}}, error) {
if !obj.DeletionTimestamp.IsZero() {
return status, nil
Expand All @@ -418,11 +432,43 @@ func (a *{{.lowerName}}GeneratingHandler) Handle(obj *{{.version}}.{{.type}}, st
if err != nil {
return newStatus, err
}
if !a.isNewResourceVersion(obj) {
return newStatus, nil
}
return newStatus, generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
err = generic.ConfigureApplyForObject(a.apply, obj, &a.opts).
WithOwner(obj).
WithSetID(a.name).
ApplyObjects(objs...)
if err != nil {
return newStatus, err
}
a.storeResourceVersion(obj)
return newStatus, nil
}
// isNewResourceVersion detects if a specific resource version was already successfully processed.
// Only used if UniqueApplyForResourceVersion is set in generic.GeneratingHandlerOptions
func (a *{{.lowerName}}GeneratingHandler) isNewResourceVersion(obj *{{.version}}.{{.type}}) bool {
if !a.opts.UniqueApplyForResourceVersion {
return true
}
// Apply once per resource version
key := obj.Namespace + "/" + obj.Name
previous, ok := a.seen.Load(key)
return !ok || previous != obj.ResourceVersion
}
// storeResourceVersion keeps track of the latest resource version of an object for which Apply was executed
// Only used if UniqueApplyForResourceVersion is set in generic.GeneratingHandlerOptions
func (a *{{.lowerName}}GeneratingHandler) storeResourceVersion(obj *{{.version}}.{{.type}}) {
if !a.opts.UniqueApplyForResourceVersion {
return
}
key := obj.Namespace + "/" + obj.Name
a.seen.Store(key, obj.ResourceVersion)
}
{{- end }}
`
1 change: 1 addition & 0 deletions pkg/controller-gen/generators/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
var (
Imports = []string{
"context",
"sync",
"time",
"k8s.io/client-go/rest",
"github.com/rancher/lasso/pkg/client",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b5a5a52

Please sign in to comment.