Skip to content

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

Closed
wants to merge 8 commits into from

Conversation

pwittrock
Copy link
Contributor

No description provided.

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jun 18, 2018
Copy link
Contributor

@droot droot left a 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 {
Copy link
Contributor

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 ?

Copy link
Contributor

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)
Copy link
Contributor

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 {
Copy link
Contributor

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)

Copy link
Contributor

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
Copy link
Contributor

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).

Copy link
Contributor Author

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"
)

Copy link
Contributor

@droot droot Jun 22, 2018

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 ?

Copy link
Contributor

@droot droot left a 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)
}
Copy link
Contributor

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
Copy link
Contributor

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,
}})
}
Copy link
Contributor

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)
}
Copy link
Contributor

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.
Copy link
Contributor

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.

Copy link
Contributor

@droot droot left a 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
}
Copy link
Contributor

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 ?

Copy link
Contributor

@droot droot left a 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
}
Copy link
Contributor

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.

@droot
Copy link
Contributor

droot commented Jun 22, 2018

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.

@pwittrock
Copy link
Contributor Author

Copy link
Contributor

@droot droot left a 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
Copy link
Contributor

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)

Copy link
Contributor Author

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.
Copy link
Contributor

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.

Copy link
Contributor Author

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
Copy link
Contributor

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......

Copy link
Contributor Author

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
}
Copy link
Contributor

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

Copy link
Contributor Author

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
Copy link
Contributor

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 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Copy link
Contributor

@droot droot left a 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

@droot
Copy link
Contributor

droot commented Jun 25, 2018

@pwittrock completed the entire review today. lgtm. Feel free to close the PR.

@pwittrock
Copy link
Contributor Author

Comments addressed in #61

@pwittrock pwittrock closed this Jun 26, 2018
Copy link
Contributor

@DirectXMan12 DirectXMan12 left a 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
Copy link
Contributor

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) {
Copy link
Contributor

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.
Copy link
Contributor

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.
Copy link
Contributor

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.
Copy link
Contributor

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 {
Copy link
Contributor

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?

Copy link
Contributor

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 {
Copy link
Contributor

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")
Copy link
Contributor

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)
Copy link
Contributor

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.)
Copy link
Contributor

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?

droot added a commit to droot/controller-runtime that referenced this pull request Jun 26, 2018
@droot droot mentioned this pull request Jun 26, 2018
justinsb pushed a commit to justinsb/controller-runtime that referenced this pull request Dec 7, 2018
DirectXMan12 pushed a commit that referenced this pull request Jan 31, 2020
Disallow pluralized Kinds when creating resources
sttts pushed a commit to sttts/controller-runtime that referenced this pull request Mar 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants