...

Source file src/github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder/recorder.go

Documentation: github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package recorder
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"reflect"
    20  	"time"
    21  
    22  	"github.com/go-logr/logr"
    23  	"github.com/iancoleman/strcase"
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	"k8s.io/client-go/tools/record/util"
    29  	ref "k8s.io/client-go/tools/reference"
    30  	"k8s.io/klog"
    31  	"sigs.k8s.io/controller-runtime/pkg/client"
    32  )
    33  
    34  type ChaosRecorder interface {
    35  	Event(object runtime.Object, ev ChaosEvent)
    36  }
    37  
    38  type chaosRecorder struct {
    39  	log    logr.Logger
    40  	source v1.EventSource
    41  	client client.Client
    42  	scheme *runtime.Scheme
    43  }
    44  
    45  func (r *chaosRecorder) Event(object runtime.Object, ev ChaosEvent) {
    46  	eventtype := ev.Type()
    47  	reason := ev.Reason()
    48  	message := ev.Message()
    49  
    50  	annotations, err := generateAnnotations(ev)
    51  	if err != nil {
    52  		r.log.Error(err, "failed to generate annotations for event", "event", ev)
    53  	}
    54  
    55  	ref, err := ref.GetReference(r.scheme, object)
    56  	if err != nil {
    57  		r.log.Error(err, "fail to construct reference", "object", object)
    58  		return
    59  	}
    60  
    61  	if !util.ValidateEventType(eventtype) {
    62  		klog.Errorf("Unsupported event type: '%v'", eventtype)
    63  		return
    64  	}
    65  
    66  	event := r.makeEvent(ref, annotations, eventtype, reason, message)
    67  	event.Source = r.source
    68  	go func() {
    69  		err := r.client.Create(context.TODO(), event)
    70  		if err != nil {
    71  			r.log.Error(err, "fail to submit event", "event", event)
    72  		}
    73  	}()
    74  }
    75  
    76  func (r *chaosRecorder) makeEvent(ref *v1.ObjectReference, annotations map[string]string, eventtype, reason, message string) *v1.Event {
    77  	t := metav1.Time{Time: time.Now()}
    78  	namespace := ref.Namespace
    79  	if namespace == "" {
    80  		namespace = metav1.NamespaceDefault
    81  	}
    82  	return &v1.Event{
    83  		ObjectMeta: metav1.ObjectMeta{
    84  			Name:        fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()),
    85  			Namespace:   namespace,
    86  			Annotations: annotations,
    87  		},
    88  		InvolvedObject: *ref,
    89  		Reason:         reason,
    90  		Message:        message,
    91  		FirstTimestamp: t,
    92  		LastTimestamp:  t,
    93  		Count:          1,
    94  		Type:           eventtype,
    95  	}
    96  }
    97  
    98  type ChaosEvent interface {
    99  	Type() string
   100  	Reason() string
   101  	Message() string
   102  }
   103  
   104  var allEvents = make(map[string]ChaosEvent)
   105  
   106  func register(ev ...ChaosEvent) {
   107  	for _, ev := range ev {
   108  		val := reflect.ValueOf(ev)
   109  		val = reflect.Indirect(val)
   110  
   111  		allEvents[strcase.ToKebab(val.Type().Name())] = ev
   112  	}
   113  }
   114  
   115  type RecorderBuilder struct {
   116  	c      client.Client
   117  	logger logr.Logger
   118  	scheme *runtime.Scheme
   119  }
   120  
   121  func (b *RecorderBuilder) Build(name string) ChaosRecorder {
   122  	return &chaosRecorder{
   123  		log: b.logger.WithName("event-recorder-" + name),
   124  		source: v1.EventSource{
   125  			Component: name,
   126  		},
   127  		client: b.c,
   128  		scheme: b.scheme,
   129  	}
   130  }
   131  
   132  func NewRecorderBuilder(c client.Client, logger logr.Logger, scheme *runtime.Scheme) *RecorderBuilder {
   133  	return &RecorderBuilder{
   134  		c,
   135  		logger,
   136  		scheme,
   137  	}
   138  }
   139  
   140  type debugRecorder struct {
   141  	Events map[types.NamespacedName][]ChaosEvent
   142  }
   143  
   144  func (d *debugRecorder) Event(object runtime.Object, ev ChaosEvent) {
   145  	obj := object.(metav1.Object)
   146  	id := types.NamespacedName{
   147  		Namespace: obj.GetNamespace(),
   148  		Name:      obj.GetName(),
   149  	}
   150  
   151  	if d.Events[id] == nil {
   152  		d.Events[id] = []ChaosEvent{}
   153  	}
   154  
   155  	d.Events[id] = append(d.Events[id], ev)
   156  }
   157  
   158  func NewDebugRecorder() *debugRecorder {
   159  	return &debugRecorder{
   160  		Events: make(map[types.NamespacedName][]ChaosEvent),
   161  	}
   162  }
   163