Skip to content

Commit

Permalink
Add cluster-scoped events in the list of user events
Browse files Browse the repository at this point in the history
  • Loading branch information
jlandowner committed May 23, 2024
1 parent cf2d28a commit c8aa5dd
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 12 deletions.
4 changes: 4 additions & 0 deletions api/v1alpha1/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ func IsPruneDisabled(obj AnnotationHolder) bool {
}
return isDisabled
}

const (
EventAnnKeyUserName = "cosmo-workspace.github.io/user"
)
3 changes: 1 addition & 2 deletions internal/cmd/user/get_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"
"k8s.io/utils/ptr"

"github.com/cosmo-workspace/cosmo/api/v1alpha1"
"github.com/cosmo-workspace/cosmo/pkg/apiconv"
"github.com/cosmo-workspace/cosmo/pkg/cli"
"github.com/cosmo-workspace/cosmo/pkg/clog"
Expand Down Expand Up @@ -125,7 +124,7 @@ func regarding(v *dashv1alpha1.ObjectReference) string {

func (o *GetEventsOption) GetEventsByKubeClient(ctx context.Context) ([]*dashv1alpha1.Event, error) {
c := o.KosmoClient
events, err := c.ListEvents(ctx, v1alpha1.UserNamespace(o.UserName))
events, err := c.ListEventsForUser(ctx, o.UserName)
if err != nil {
return nil, err
}
Expand Down
10 changes: 7 additions & 3 deletions internal/controllers/cluster_instance_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,28 @@ func (r *ClusterInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Requ
inst.Status.TemplateName = tmpl.Name
inst.Status.TemplateResourceVersion = tmpl.ResourceVersion

eventAnn := map[string]string{
cosmov1alpha1.EventAnnKeyUserName: userNameFromOwnerReferences(inst.GetOwnerReferences()),
}

// 1. Build Unstructured objects
objects, err := template.BuildObjects(tmpl.Spec, &inst)
if err != nil {
r.Recorder.Eventf(&inst, corev1.EventTypeWarning, "BuildFailed", "Failed to build manifests from Template: %v", err)
r.Recorder.AnnotatedEventf(&inst, eventAnn, corev1.EventTypeWarning, "BuildFailed", "Failed to build manifests from Template: %v", err)
return ctrl.Result{}, err
}

// 2. Transform the objects
objects, err = transformer.ApplyTransformers(ctx, transformer.AllTransformers(&inst, r.Scheme, tmpl), objects)
if err != nil {
r.Recorder.Eventf(&inst, corev1.EventTypeWarning, "BuildFailed", "Failed to build resources: %v", err)
r.Recorder.AnnotatedEventf(&inst, eventAnn, corev1.EventTypeWarning, "BuildFailed", "Failed to build resources: %v", err)
return ctrl.Result{}, err
}

// 3. Reconcile objects
if errs := r.impl.reconcileObjects(ctx, &inst, objects); len(errs) != 0 {
for _, err := range errs {
r.Recorder.Eventf(&inst, corev1.EventTypeWarning, "SyncFailed", "Failed to sync objects: %v", err)
r.Recorder.AnnotatedEventf(&inst, eventAnn, corev1.EventTypeWarning, "SyncFailed", "Failed to sync objects: %v", err)
}
// requeue
return ctrl.Result{}, fmt.Errorf("apply child objects failed: %w", errs[0])
Expand Down
19 changes: 15 additions & 4 deletions internal/controllers/instance_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ type instanceReconciler struct {
FieldManager string
}

func (r *instanceReconciler) Eventf(inst cosmov1alpha1.InstanceObject, eventtype, reason, messageFmt string, args ...any) {
if inst.GetScope() == meta.RESTScopeRoot {
ann := map[string]string{
cosmov1alpha1.EventAnnKeyUserName: userNameFromOwnerReferences(inst.GetOwnerReferences()),
}
r.Recorder.AnnotatedEventf(inst, ann, eventtype, reason, messageFmt, args...)
} else {
r.Recorder.Eventf(inst, eventtype, reason, messageFmt, args...)
}
}

func (r *instanceReconciler) reconcileObjects(ctx context.Context, inst cosmov1alpha1.InstanceObject, objects []unstructured.Unstructured) []error {
log := clog.FromContext(ctx).WithCaller()
errs := make([]error, 0)
Expand Down Expand Up @@ -162,7 +173,7 @@ func (r *instanceReconciler) reconcileObjects(ctx context.Context, inst cosmov1a
if err != nil {
errs = append(errs, fmt.Errorf("failed to create resource: kind = %s name = %s: %w", built.GetKind(), built.GetName(), err))
} else {
r.Recorder.Eventf(inst, corev1.EventTypeNormal, "Synced", "%s %s is created", built.GetKind(), built.GetName())
r.Eventf(inst, corev1.EventTypeNormal, "Synced", "%s %s is created", built.GetKind(), built.GetName())
}
currAppliedMap[created.GetUID()] = unstToObjectRef(created)

Expand Down Expand Up @@ -190,7 +201,7 @@ func (r *instanceReconciler) reconcileObjects(ctx context.Context, inst cosmov1a
if _, err := r.apply(ctx, &built, r.FieldManager); err != nil {
errs = append(errs, fmt.Errorf("failed to apply resource %s %s: %w", built.GetKind(), built.GetName(), err))
} else {
r.Recorder.Eventf(inst, corev1.EventTypeNormal, "Synced", "%s %s is not desired state, synced", built.GetKind(), built.GetName())
r.Eventf(inst, corev1.EventTypeNormal, "Synced", "%s %s is not desired state, synced", built.GetKind(), built.GetName())
}
}
}
Expand All @@ -203,10 +214,10 @@ func (r *instanceReconciler) reconcileObjects(ctx context.Context, inst cosmov1a
for _, d := range shouldDeletes {
if skip, err := prune(ctx, r.Client, d); err != nil {
log.Error(err, "failed to delete unused obj", "pruneAPIVersion", d.APIVersion, "pruneKind", d.Kind, "pruneName", d.Name, "pruneNamespace", d.Namespace)
r.Recorder.Eventf(inst, corev1.EventTypeWarning, "GCFailed", "Failed to delete unused obj: kind=%s name=%s namespace=%s", d.Kind, d.Name, d.Namespace)
r.Eventf(inst, corev1.EventTypeWarning, "GCFailed", "Failed to delete unused obj: kind=%s name=%s namespace=%s", d.Kind, d.Name, d.Namespace)
} else if !skip {
log.Info("deleted unmanaged object", "apiVersion", d.APIVersion, "kind", d.Kind, "name", d.Name, "namespace", d.Namespace)
r.Recorder.Eventf(inst, corev1.EventTypeNormal, "GC", "Deleted unmanaged object: kind=%s name=%s namespace=%s", d.Kind, d.Name, d.Namespace)
r.Eventf(inst, corev1.EventTypeNormal, "GC", "Deleted unmanaged object: kind=%s name=%s namespace=%s", d.Kind, d.Name, d.Namespace)
}
}
}
Expand Down
11 changes: 10 additions & 1 deletion internal/controllers/template_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -93,7 +94,15 @@ func notifyUpdateToInstances(ctx context.Context, c client.Client, rec record.Ev
if err := c.Status().Update(ctx, inst); err != nil {
errs = append(errs, fmt.Errorf("failed to update instance status: %s: %w", inst.GetName(), err))
}
rec.Eventf(inst, corev1.EventTypeNormal, "TemplateUpdated", "Detected Template %s is updated", tmpl.GetName())

if inst.GetScope() == meta.RESTScopeRoot {
ann := map[string]string{
cosmov1alpha1.EventAnnKeyUserName: userNameFromOwnerReferences(inst.GetOwnerReferences()),
}
rec.AnnotatedEventf(inst, ann, corev1.EventTypeNormal, "TemplateUpdated", "Detected Template %s is updated", tmpl.GetName())
} else {
rec.Eventf(inst, corev1.EventTypeNormal, "TemplateUpdated", "Detected Template %s is updated", tmpl.GetName())
}
}
return errs
}
10 changes: 10 additions & 0 deletions internal/controllers/user_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
Expand Down Expand Up @@ -206,3 +207,12 @@ func (r *UserReconciler) patchNamespaceToUserDesired(ns *corev1.Namespace, user

return nil
}

func userNameFromOwnerReferences(refs []metav1.OwnerReference) string {
for _, ref := range refs {
if ref.Kind == "User" {
return ref.Name
}
}
return ""
}
4 changes: 2 additions & 2 deletions internal/dashboard/user_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ func (s *Server) GetUser(ctx context.Context, req *connect_go.Request[dashv1alph
if err != nil {
return nil, ErrResponse(log, err)
}
events, err := s.Klient.ListEvents(ctx, cosmov1alpha1.UserNamespace(user.Name))
events, err := s.Klient.ListEventsForUser(ctx, user.Name)
if err != nil {
log.Error(err, "failed to list events", "namespace", cosmov1alpha1.UserNamespace(user.Name))
log.Error(err, "failed to list events", "user", user.Name)
}

res := &dashv1alpha1.GetUserResponse{
Expand Down
29 changes: 29 additions & 0 deletions pkg/kosmo/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
apierrs "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"

cosmov1alpha1 "github.com/cosmo-workspace/cosmo/api/v1alpha1"
"github.com/cosmo-workspace/cosmo/pkg/clog"
)

Expand All @@ -21,3 +22,31 @@ func (c *Client) ListEvents(ctx context.Context, namespace string) ([]eventsv1.E
return events.Items, nil
}
}

func (c *Client) ListEventsForUser(ctx context.Context, user string) ([]eventsv1.Event, error) {
ns := cosmov1alpha1.UserNamespace(user)

// List events in user namespace
userEvents, err := c.ListEvents(ctx, ns)
if err != nil {
return nil, err
}

// List events in default namespace which is annotated user name
// cluster scoped events are found in defualt namespace
var defaultEvents eventsv1.EventList
if err := c.List(ctx, &defaultEvents, &client.ListOptions{Namespace: "default"}); err != nil {
return nil, apierrs.NewInternalError(fmt.Errorf("failed to list Event in default namespace: %w", err))
}
for _, e := range defaultEvents.Items {
if e.Annotations == nil {
continue
}
if e.Annotations[cosmov1alpha1.EventAnnKeyUserName] == user {
userEvents = append(userEvents, e)
}
}

return userEvents, nil

}

0 comments on commit c8aa5dd

Please sign in to comment.