-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Controller v2 libs review #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am reviewing each commit separately. So these comments are reviewing reconcile pkg.
For example if responding to a Pod Delete Event, the Request won't contain that a Pod was deleted, | ||
instead the reconcile function observes this when reading the cluster state and seeing the Pod as missing. | ||
*/ | ||
type Reconcile interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be called Reconciler
because anyone who implements the verb Reconcile
is a Reconciler ?
Like anyone implementing Read(...)
is a io.Reader
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed here -- the name is a bit confusing.
|
||
return result, nil | ||
}) | ||
actualResult, actualErr := instance(request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may be invoke the reconcile using instance.Reconcile
for clarity ?
|
||
// This example declares a simple type that implements reconcile. | ||
func ExampleReconcile() { | ||
type MyReconcileImplementation struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, default example for demonstrating Reconcile
should be struct based not adapter based because 99% use-cases involve a struct where an instance of client
needs to be embedded etc. and speaking from my experience, I have found Adapter pattern a bit difficult to grok for newbies (experience from net/http)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed
// Result contains the result of a Reconcile invocation. | ||
type Result struct { | ||
// Requeue tells the Controller to requeue the reconcile key. Defaults to false. | ||
Requeue bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One question (not scope of reconcile
pkg though). What is the semantics for handling the error returned by the Reconcile()
. Is it going to be simply logging the error and ignoring it ? or using it for re-queuing ? If it is the former, then current controller writer might get surprised a bit (not saying it is a bad thing though).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the latter. will document
"k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be a few comments explaining where this pkg fit in the over-all picture. Who will be the producer/consumer of these objects etc ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comments from review of handler pkg.
// InjectScheme is called by the Controller to provide a singleton scheme to the EnqueueOwner. | ||
func (e *EnqueueOwner) InjectScheme(s *runtime.Scheme) error { | ||
return e.parseOwnerTypeGroupKind(s) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would suggest moving InjectScheme
related code at the bottom from code readability perspective, sort of coming in the way :)
return nil | ||
} | ||
|
||
// If filtered to Controller use all the OwnerReferences |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not filtered
Namespace: object.GetNamespace(), | ||
Name: ref.Name, | ||
}}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its good that we are not performing lookup against the cluster to match the UUIDs for the owner because that would have made handling the cases of owner itself changing difficult.
// Generic is called in response to an event of an unknown type or a synthetic event triggered as a cron or | ||
// external trigger request - e.g. reconcile Autoscaling, or a Webhook. | ||
Generic(workqueue.RateLimitingInterface, event.GenericEvent) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider switching ordering of the parameters. evt is the primary input to to the handler and q is sort of the output after the handling ?
|
||
var _ EventHandler = Funcs{} | ||
|
||
// Funcs allows specifying a subset of EventHandler functions are fields. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment isn't very clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reviewed predicates
return p.GenericFunc(e) | ||
} | ||
return true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like we don't have any default predicates implemented like one diffing resourceVersion
field ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reviewed source pkg, looks good.
} | ||
i.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct}) | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider moving Kind source
above Channel source
from readability perspective. Kind source is much more simpler than channel source, so if someone is looking for a canonical example to implement a source, introducing Kind first is a good idea.
Did a first pass today and reviewed source, handler, predicates, event and reconcile pkgs today. Will review controllers and manager in the second pass today or Monday. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed the manager pkg. Looks good, minor nits.
// TODO(community): Check the return value and write a test | ||
cm.cache.WaitForCacheSync(stop) | ||
|
||
// Start the runnables after the promises |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment is outdated (mentions promises
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
cm.mu.Lock() | ||
defer cm.mu.Unlock() | ||
|
||
// Start the Cache. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: may be move the comment new the startCache
block below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
// Defaults to the kubernetes/client-go scheme.Scheme | ||
Scheme *runtime.Scheme | ||
|
||
// Mapper is the rest mapper used to map go types to Kubernetes APIs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mapper --> MapperProvider provides the rest mapper......
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
// Use the Kubernetes client-go scheme if none is specified | ||
if cm.scheme == nil { | ||
cm.scheme = scheme.Scheme | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be moved to setOptionsDefaults
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Restructured this fn.
} | ||
|
||
// Allow newCache to be mocked | ||
// TODO(directxman12): Figure out how to allow users to request a client without requesting a watch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know this TODO is still valid ? I remember some discussion where it came as already done ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reviewed controller pkg. lgtm
@pwittrock completed the entire review today. lgtm. Feel free to close the PR. |
Comments addressed in #61 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mostly didn't review tests -- focused on the main code.
Apologies if I commented on anything that was already fixed ;-)
// | ||
// Watch may be provided one or more Predicates to filter events before they are given to the EventHandler. | ||
// Events will be passed to the EventHandler iff all provided Predicates evaluate to true. | ||
Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't abbreviate so much, especially in the interface definition, where people will be looking for documentation. eventHandler
and predicates
are fine.
|
||
// New returns a new Controller registered with the Manager. The Manager will ensure that shared Caches have | ||
// been synced before the Controller is Started. | ||
func New(name string, mrg manager.Manager, options Options) (Controller, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mrg
--> mgr
3 Pods exist in the system. Reconcile creates 2 more Pods and sets their OwnerReference to point at the | ||
ReplicationController. | ||
* reconcile works on a single object type. - e.g. it will only reconcile ReplicaSets. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
specify if you wish to trigger reconciles from other objects, you can provide a mapping (e.g. owner references) that maps the object that triggers the reconcile to the object being reconciled
, perhaps?
* Predicates are optional | ||
* Users SHOULD use the provided Predicate implementations, but MAY implement their own Predicates as needed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
give an example here (e.g. generation changed, label selectors, etc)
The following example shows creating a new Controller program which Reconciles ReplicaSet objects in response | ||
to Pod or ReplicaSet events. The Reconcile function simply adds a label to the ReplicaSet. | ||
See the example/main.go for a usage example. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you name things right in the _test
files they'll show up here as examples in the Godoc.
|
||
dst := make(chan event.GenericEvent, cs.DestBufferSize) | ||
go func() { | ||
for evt := range dst { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't you check for a stop signal so you can kill this goroutine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(oh, this'll end when dst
closes, but you should add a note about that)
|
||
// Create implements EventHandler | ||
func (e *Enqueue) Create(q workqueue.RateLimitingInterface, evt event.CreateEvent) { | ||
if evt.Meta == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:-/ I think we want to Inject a logger if we can, so that we can track which enqueue is having issues.
} | ||
// Expect only 1 kind. If there is more than one kind this is probably an edge case such as ListOptions. | ||
if len(kinds) != 1 { | ||
err := fmt.Errorf("Expected exactly 1 kind for OwnerType") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add more info to this error (like kind is probably not a normal API type
)
refGV, err := schema.ParseGroupVersion(ref.APIVersion) | ||
if err != nil { | ||
log.Error(err, "Could not parse OwnerReference GroupVersion", | ||
"OwnerReference", ref.APIVersion) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ownerRef should be the full ownerRef
// | ||
// * Use EnqueueMappendHandler to transform an event for an object to a reconcile of an object | ||
// of a different type - do this for events for types the Controller may be interested in, but doesn't create. | ||
// (e.g. If Foo responds to cluster size events, map Node events to Foo objects.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe mention using indexers if you need to easily look things up?
Disallow pluralized Kinds when creating resources
✨ Rebase to v0.17.2
No description provided.