-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Implement InjectRecorder #23
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
pkg/recorder/recorder.go
Outdated
"k8s.io/client-go/tools/record" | ||
) | ||
|
||
type RecorderGetFuncType func(string, *runtime.Scheme) record.EventRecorder |
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 don't think the interface should take the Scheme. This should be set by the manager.Manager so users don't need to do the wiring themselves.
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 this is an interface instead of a function, we can provide the interface. Maybe RecoderProvider
?
pkg/recorder/recorder.go
Outdated
|
||
func GetEventRecorderFor(name string, scheme *runtime.Scheme) record.EventRecorder { | ||
if eventBroadcaster == nil { | ||
cs := config.GetKubernetesClientSetOrDie() |
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.
We should get the clientset from the manager.Manager, or have users set it on a struct. All components should use the same client.
8bd21b3
to
fb97e26
Compare
pkg/manager/manager.go
Outdated
|
||
cm.recorderProvider = recorder.NewProvider() | ||
cm.recorderProvider.SetScheme(cm.scheme) | ||
cm.recorderProvider.SetClientSet(clientconfig.GetKubernetesClientSetOrDieWithConfig(config)) |
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.
We shouldn't be dying. This function returns an error, we should return an error instead of panicing.
pkg/recorder/recorder.go
Outdated
} | ||
|
||
// NewProvider create a new Provider instance. | ||
func NewProvider() Provider { |
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 New
pattern is useful when step requires synchronous steps, or setup can fail. Since we don't have either in this case, I am not sure how much value this provides.
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 eventbroadercaster setup could be done here.
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.
We should either take the deps in the New function or inject them with Inject functions. provider doesn't implement either inject.Scheme or inject.Config so it can't automatically get its deps from manager.SetFields(provider). If we are making the implementation internal, it doesn't really matter which we choose since we can change it without breaking consumers. New
is probably the simpler approach for now, so I'd go with that.
e.g. either
// setup clientset and stuff here
New(config *rest.Config, s scheme *runtime.Scheme) { ... }
or
// Setup clientset and stuff here
(p *provider) InjectClient() {...}
(p *provider) InjectScheme() {...}
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.
Yah, I think we do inject for things that cross components, and here we just make it once, so a New function should be enough.
pkg/recorder/recorder.go
Outdated
return nil, fmt.Errorf("must call SetScheme to specify Scheme before getting recorder") | ||
} | ||
|
||
if p.eventBroadcaster == 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.
This need to be threadsafe. Either wrap it in a sync.Once.Do
call, or put it in "New"
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.
good catch
pkg/manager/manager.go
Outdated
@@ -131,5 +133,9 @@ func New(config *rest.Config, options Options) (Manager, error) { | |||
|
|||
cm.fieldIndexes = cm.cache | |||
cm.client = client.DelegatingClient{ReadInterface: cm.cache, WriteInterface: writeObj} | |||
|
|||
cm.recorderProvider = recorder.NewProvider() |
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 a function to manager.go for calling the provider - e.g. add this to the Manager interface and implement it on manager.
type Manager interface {
...
// GetRecorder returns a new EventRecorder for the provided name
GetRecorder(name string) (record.EventRecorder, 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.
what the function for? you mean we should not take the provider as a field of manager, and pass it into the recorder injection?
pkg/recorder/recorder.go
Outdated
} | ||
|
||
// NewProvider create a new Provider instance. | ||
func NewProvider() Provider { |
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.
Lets move New
under pkg/internal
until we are sure we know users will need to get informers directly. They should be able to get them through the manager.Manager.
pkg/runtime/inject/inject.go
Outdated
// Recorder is used by the ControllerManager to inject recorder into Sources, EventHandlers, Predicates, and | ||
// Reconciles | ||
type Recorder interface { | ||
InjectRecorder(provider recorder.Provider) 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.
Document this.
pkg/recorder/recorder_test.go
Outdated
package recorder_test | ||
|
||
import ( | ||
"fmt" |
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.
Also update the pkg/controller/controller_integration_test.go with a case that uses an EventRecorder and creates and event from the Reconcile loop, then the test checks that the event was recorded.
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.
sure thing, just have not got time to make it today
Headed in the right direction. Left a few comments on how we want to structure things. Please run |
have not inject recorder into the components, and want to make clear its boundary:
|
1fcca7d
to
d748c8b
Compare
SGTM |
return cm, nil | ||
} | ||
|
||
// setOptionsDefaults set default values for Options 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.
+1
pkg/manager/manager_test.go
Outdated
@@ -442,3 +473,10 @@ func (i *injectable) InjectStopChannel(stop <-chan struct{}) error { | |||
func (i *injectable) Start(<-chan struct{}) error { | |||
return nil | |||
} | |||
|
|||
func (i *injectable) InjectRecorder(provider recorder.Provider) 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.
If we aren't injecting this, we don't need it.
provider, err := recorder.NewProvider(cfg, scheme.Scheme) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
recorder := provider.GetEventRecorderFor("test") |
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.
Can you also test that the event recorder will publish events?
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
65fb07a
to
2d0510c
Compare
evtWatcher, err := clientset.CoreV1().Events("default").Watch(metav1.ListOptions{}) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
resultEvent := <-evtWatcher.ResultChan() |
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 is an awesome way to both test the watching of these events and make the test run faster without polling!
@@ -122,6 +128,10 @@ func (cm *controllerManager) GetCache() cache.Cache { | |||
return cm.cache | |||
} | |||
|
|||
func (cm *controllerManager) GetRecorder(name string) record.EventRecorder { |
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.
Please add a comment for this function
Implement InjectRecorder
Address: kubernetes-sigs/kubebuilder#255