Creating Events

It is often useful to publish Event objects from the controller Reconcile function.

Events allow users to see what is going on with a particular object, and allow automated processes to see and respond to them.

Getting Events

Recent Events for an object can be viewed by running kubectl describe

Events are published from a Controller using an EventRecorder,which can be created for a Controller by calling GetRecorder(name string) on a Manager.

Name should be identifiable and descriptive as it will appear in the From column of kubectl describe command.

  1. // Annotation for generating RBAC role for writing Events
  2. // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
  1. // ReconcileContainerSet reconciles a ContainerSet object
  2. type ReconcileContainerSet struct {
  3. client.Client
  4. scheme *runtime.Scheme
  5. recorder record.EventRecorder
  6. }
  1. // newReconciler returns a new reconcile.Reconciler
  2. func newReconciler(mgr manager.Manager) reconcile.Reconciler {
  3. return &ReconcileContainerSet{
  4. Client: mgr.GetClient(),
  5. scheme: mgr.GetScheme(),
  6. recorder: mgr.GetRecorder("containerset-controller"),
  7. }
  8. }

Writing Events

Anatomy of an Event:

  1. Event(object runtime.Object, eventtype, reason, message string)
  • object is the object this event is about.
  • eventtype is the type of this event, and is either Normal or Warning.
  • reason is the reason this event is generated. It should be short and unique with UpperCamelCase format. The value could appear in switch statements by automation.
  • message is intended to be consumed by humans.Building on the example introduced in Controller Example, we can add Events to our reconcile logic using recorder as our EventRecorder
  1. //Reconcile logic up here...
  2. // Create the resource
  3. found := &appsv1.Deployment{}
  4. err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found)
  5. if err != nil && errors.IsNotFound(err) {
  6. log.Printf("Creating Deployment %s/%s\n", deploy.Namespace, deploy.Name)
  7. err = r.Create(context.TODO(), deploy)
  8. if err != nil {
  9. return reconcile.Result{}, err
  10. }
  11. // Write an event to the ContainerSet instance with the namespace and name of the
  12. // created deployment
  13. r.recorder.Event(instance, "Normal", "Created", fmt.Sprintf("Created deployment %s/%s", deploy.Namespace, deploy.Name))
  14. } else if err != nil {
  15. return reconcile.Result{}, err
  16. }
  17. // Preform update
  18. if !reflect.DeepEqual(deploy.Spec, found.Spec) {
  19. found.Spec = deploy.Spec
  20. log.Printf("Updating Deployment %s/%s\n", deploy.Namespace, deploy.Name)
  21. err = r.Update(context.TODO(), found)
  22. if err != nil {
  23. return reconcile.Result{}, err
  24. }
  25. // Write an event to the ContainerSet instance with the namespace and name of the
  26. // updated deployment
  27. r.recorder.Event(instance, "Normal", "Updated", fmt.Sprintf("Updated deployment %s/%s", deploy.Namespace, deploy.Name))
  28. }
  29. return reconcile.Result{}, nil
  30. }