Skip to content

Refactor the way our Controllers watch ConfigMaps#1351

Merged
google-prow-robot merged 4 commits intoknative:masterfrom
mattmoor:config-manager
Jun 27, 2018
Merged

Refactor the way our Controllers watch ConfigMaps#1351
google-prow-robot merged 4 commits intoknative:masterfrom
mattmoor:config-manager

Conversation

@mattmoor
Copy link
Copy Markdown
Member

Previously the Revision and Route controllers used a ConfigMap informer directly to watch for changes. This generalizes that pattern into a slightly higher level abstraction under pkg/configurationmanager.

With this configurationmanager.Interface abstraction, Controllers simply register to Watch particular ConfigMaps for changes via a callback:

  cm.Watch("configmap-name", c.receiveSomeConfig)

Once Start() is called on the configurationmanager.Interface all of the registered watchers will be invoked with the initial state of their configs, and if any are missing the call to Start() will return an error. This consolidates the setup and update logic for the various configurations behind a single interface.

This transitions the NetworkConfig and DomainConfig logic, which already employ this pattern (sans abstraction) to this abstraction.

Fixes: #1242

@google-prow-robot google-prow-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Jun 26, 2018
Comment thread pkg/configurationmanager/interface.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd rather this package be called configuration and this interface be called Watcher

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

What about configmap for the package, Interface => Watcher and Watcher => Observer?

I'd like to avoid confusion with our Configuration resources. Yay, naming!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

sounds good

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I went with this, but also renamed New[Fixed] => New{Default,Fixed}Watcher for clarity.

Comment thread pkg/configurationmanager/default.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can follow the client-go convention and not perform a DeepCopy - but I would expect each controller storing said ConfigMap to perform a DeepCopy themselves.

It would be worth documenting this on the configurationmanager interface

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This SGTM.

Comment thread pkg/configurationmanager/default.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Might be useful to add a check to see whether this instance is already started or not and return an error in case it is already started.

Comment thread pkg/controller/route/route.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I like the wording here :-) But might since we are logging below and since we are going to be public soon, might be better off to remove this line.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

My debugging snuck in! Will remove, good catch. 😊

@mdemirhan
Copy link
Copy Markdown
Contributor

/lgtm
/approve

@google-prow-robot google-prow-robot added the lgtm Indicates that a PR is ready to be merged. label Jun 26, 2018
@google-prow-robot google-prow-robot removed the lgtm Indicates that a PR is ready to be merged. label Jun 26, 2018
@mattmoor mattmoor force-pushed the config-manager branch 2 times, most recently from a6ceb7a to 58817da Compare June 26, 2018 19:57
mattmoor added 3 commits June 26, 2018 20:07
Previously the Revision and Route controllers used a ConfigMap informer directly to watch for changes.  This generalizes that pattern into a slightly higher level abstraction under `pkg/configmap`.

With this `configmap.Watcher` abstraction, Controllers simply register to `Watch` particular `ConfigMap`s for changes via a callback:
```go
  cm.Watch("configmap-name", c.receiveSomeConfig)
```

Once `Start()` is called on the `configmap.Watcher` all of the registered `configmap.Observers` will be invoked with the initial state of their `ConfigMap`s, and if any are not found the call to `Start()` will return an error.  This consolidates the setup and update logic for the various configurations behind a single interface.

This transitions the `NetworkConfig` and `DomainConfig` logic, which already employ this pattern (sans abstraction) to this abstraction.

Fixes: knative/serving#1242
Rename `network_config.go` to have a consistent filename with `domainconfig.go`.
Also renamed defaultImpl's `watchers` field to `observers` to be consistent with the original intent.
@mattmoor
Copy link
Copy Markdown
Member Author

/test pull-knative-serving-go-coverage

3 similar comments
@steuhs
Copy link
Copy Markdown
Contributor

steuhs commented Jun 26, 2018

/test pull-knative-serving-go-coverage

@steuhs
Copy link
Copy Markdown
Contributor

steuhs commented Jun 26, 2018

/test pull-knative-serving-go-coverage

@steuhs
Copy link
Copy Markdown
Contributor

steuhs commented Jun 27, 2018

/test pull-knative-serving-go-coverage

Comment thread pkg/configmap/default.go Outdated
Copy link
Copy Markdown
Member

@dprotaso dprotaso Jun 27, 2018

Choose a reason for hiding this comment

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

It looks like this doesn't block so no need for go

https://github.com/kubernetes/client-go/blob/master/informers/factory.go#L124

Unless you meant to start the di.informer explicitly?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In that case you can remove the shared informer factory sif from defaultImpl

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Interesting. I copied what we do in ./cmd/controller/main.go, which copied: https://github.com/kubernetes/sample-controller/blob/master/main.go#L68-L69.

TIL.

Comment thread pkg/configmap/default.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For readability assign the lambda to a some var

ie.

startInformerFunc := func() error {
   ...
}

if err := startInformerFunc(); err != nil {
   ...
}

or maybe it just simply warrants a separate function

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I split this into a couple sub-functions which I definitely thinks helps this self-document a bit better.

Comment thread pkg/configmap/interface.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Based on prior comments it seems like you could just take in just a single ConfigMapInformer

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Given that the Watch method only takes a name (read: no namespace), I'd like the interface for constructing a Watcher to bear the responsibility of filtering to a single namespace, which AFAIK is only possibly if we own the construction of the SharedInformerFactory that creates the informer.

@google-prow-robot google-prow-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jun 27, 2018
@google-prow-robot google-prow-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jun 27, 2018
split Start into a handful of descriptively named helpers.

Don't Start in a go routine, since it doesn't block on SharedInformerFactory.
@knative-metrics-robot
Copy link
Copy Markdown

The following is the coverage report on pkg/. Say /test pull-knative-serving-go-coverage to run the coverage report again

File Old Coverage New Coverage Delta
pkg/configmap/default.go File not exists 97.3%
pkg/configmap/fixed.go File not exists 100.0%
pkg/configmap/interface.go File not exists 100.0%
pkg/controller/revision/networkconfig.go File not exists 100.0%
pkg/controller/route/route.go 78.9% 78.7% -0.2
pkg/controller/route/domainconfig.go 96.9% 96.4% -0.4
pkg/controller/revision/revision.go 72.1% 71.8% -0.4

*TestCoverage feature is being tested, do not rely on any info here yet

@mattmoor mattmoor changed the title [WIP] Refactor the way our Controllers watch ConfigMaps Refactor the way our Controllers watch ConfigMaps Jun 27, 2018
@mattmoor
Copy link
Copy Markdown
Member Author

Going to remove WIP. I'd started to migrate the Controller usage of /etc/config-foo, but I'll do that in a follow-up PR as it was growing unwieldy and could use some refactoring to make that migration more manageable (e.g. pkg/logging shouldn't directly depend on /etc/config-logging existing).

(my current thinking)
I will likely expand the surface of pkg/configmap to include:

// Load reads a mounted ConfigMap from disk, returns the equivalent of it's `Data` field.
func Load(path string) (map[string]string, error) {...}

Then as I refactor the various parts of ControllerConfig into things like logging.Config I can expose constructors that take the corev1.ConfigMap (for use with Watch), or its .Data field (for use with Load, and delegated to by the ConfigMap variant).

@mdemirhan
Copy link
Copy Markdown
Contributor

/lgtm
/approve

@google-prow-robot google-prow-robot added the lgtm Indicates that a PR is ready to be merged. label Jun 27, 2018
@google-prow-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mattmoor, mdemirhan

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@mattmoor
Copy link
Copy Markdown
Member Author

/hold remove

@mattmoor
Copy link
Copy Markdown
Member Author

/hold cancel

@mattmoor mattmoor removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 27, 2018
@google-prow-robot google-prow-robot merged commit 0999d92 into knative:master Jun 27, 2018
@mattmoor mattmoor deleted the config-manager branch June 27, 2018 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants