github.com/verrazzano/verrazzano@v1.7.0/platform-operator/experimental/event/event.go (about) 1 // Copyright (c) 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package event 5 6 import ( 7 "context" 8 "encoding/base64" 9 "fmt" 10 moduleapi "github.com/verrazzano/verrazzano-modules/module-operator/apis/platform/v1alpha1" 11 "github.com/verrazzano/verrazzano-modules/pkg/controller/result" 12 "github.com/verrazzano/verrazzano-modules/pkg/vzlog" 13 "github.com/verrazzano/verrazzano/platform-operator/constants" 14 corev1 "k8s.io/api/core/v1" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 "k8s.io/apimachinery/pkg/types" 17 "sigs.k8s.io/controller-runtime/pkg/client" 18 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 19 "sigs.k8s.io/yaml" 20 ) 21 22 // EventType is the type of event 23 type EventType string 24 25 // EventType constants 26 const ( 27 // IntegrateSingleRequestEvent is a request to integrate a single module 28 IntegrateSingleRequestEvent EventType = "integrate-single" 29 30 // IntegrateCascadeRequestEvent is an event request to integrate the other modules except the one 31 // in the event payload (since it will already have been integrated) 32 IntegrateCascadeRequestEvent EventType = "integrate-cascade" 33 ) 34 35 // DataKey is a configmap data key 36 type DataKey string 37 38 // DataKey constants 39 const ( 40 EventDataKey DataKey = "event" 41 ) 42 43 // Action is the lifecycle action 44 type Action string 45 46 // Action constants 47 const ( 48 Installed Action = "installed" 49 Upgraded Action = "upgraded" 50 Deleted Action = "deleted" 51 ) 52 53 // ModuleIntegrationEvent contains the event data 54 type ModuleIntegrationEvent struct { 55 EventType 56 Action 57 58 // Cascade true indicates that the single-module integration controller should potentially create an 59 // event to integrate other modules 60 Cascade bool 61 ResourceNSN types.NamespacedName 62 ModuleName string 63 ModuleVersion string 64 TargetNamespace string 65 } 66 67 // NewModuleIntegrationEvent creates a ModuleIntegrationEvent event struct for a module 68 func NewModuleIntegrationEvent(module *moduleapi.Module, action Action, eventType EventType, cascade bool) *ModuleIntegrationEvent { 69 return &ModuleIntegrationEvent{ 70 Cascade: cascade, 71 EventType: eventType, 72 Action: action, 73 ResourceNSN: types.NamespacedName{Namespace: module.Namespace, Name: module.Name}, 74 ModuleName: module.Spec.ModuleName, 75 ModuleVersion: module.Spec.Version, 76 TargetNamespace: module.Spec.TargetNamespace, 77 } 78 } 79 80 // CreateModuleIntegrationEvent creates a ModuleIntegrationEvent event for a module 81 func CreateModuleIntegrationEvent(log vzlog.VerrazzanoLogger, cli client.Client, module *moduleapi.Module, action Action) result.Result { 82 return createEvent(log, cli, NewModuleIntegrationEvent(module, action, IntegrateSingleRequestEvent, true)) 83 } 84 85 // CreateModuleIntegrationCascadeEvent creates a ModuleIntegrationEvent event for a module to integrate other modules 86 func CreateModuleIntegrationCascadeEvent(log vzlog.VerrazzanoLogger, cli client.Client, sourceEvent *ModuleIntegrationEvent) result.Result { 87 // Use the fields from the input event to create a new event of a different type 88 ev := *sourceEvent 89 ev.EventType = IntegrateCascadeRequestEvent 90 ev.Cascade = false 91 return createEvent(log, cli, &ev) 92 } 93 94 // CreateNonCascadingModuleIntegrationEvent creates a ModuleIntegrationEvent event for a module with no cascading 95 func CreateNonCascadingModuleIntegrationEvent(log vzlog.VerrazzanoLogger, cli client.Client, module *moduleapi.Module, action Action) result.Result { 96 return createEvent(log, cli, NewModuleIntegrationEvent(module, action, IntegrateSingleRequestEvent, false)) 97 } 98 99 // createEvent creates a lifecycle event 100 func createEvent(log vzlog.VerrazzanoLogger, cli client.Client, ev *ModuleIntegrationEvent) result.Result { 101 y, err := yaml.Marshal(ev) 102 if err != nil { 103 log.ErrorfThrottled("Failed to unmarshal event configmap for module %s: %v", ev.ModuleName, err) 104 result.NewResultShortRequeueDelayWithError(err) 105 } 106 // convert to base64 107 encoded := base64.StdEncoding.EncodeToString(y) 108 109 cm := &corev1.ConfigMap{ 110 ObjectMeta: metav1.ObjectMeta{ 111 Name: getEventResourceName(ev.ResourceNSN.Name, string(ev.Action), string(ev.EventType)), 112 Namespace: ev.ResourceNSN.Namespace, 113 }, 114 } 115 _, err = controllerutil.CreateOrUpdate(context.TODO(), cli, cm, func() error { 116 if cm.Labels == nil { 117 cm.Labels = make(map[string]string) 118 } 119 // Always replace existing event data for this module-action 120 cm.Labels[constants.VerrazzanoModuleEventLabel] = string(ev.EventType) 121 cm.Data = make(map[string]string) 122 cm.Data[string(EventDataKey)] = encoded 123 return nil 124 }) 125 if err != nil { 126 log.ErrorfThrottled("Failed to create or update event configmap for module %s: %v", ev.ModuleName, err) 127 return result.NewResultShortRequeueDelayWithError(err) 128 } 129 130 return result.NewResult() 131 } 132 133 // ConfigMapToModuleIntegrationEvent converts an event configmap to a ModuleIntegrationEvent 134 func ConfigMapToModuleIntegrationEvent(log vzlog.VerrazzanoLogger, cm *corev1.ConfigMap) (*ModuleIntegrationEvent, error) { 135 decoded, err := base64.StdEncoding.DecodeString(cm.Data[string(EventDataKey)]) 136 if err != nil { 137 return nil, err 138 } 139 ev := ModuleIntegrationEvent{} 140 if err := yaml.Unmarshal(decoded, &ev); err != nil { 141 return nil, err 142 } 143 return &ev, nil 144 } 145 146 func getEventResourceName(name string, action string, eventType string) string { 147 return fmt.Sprintf("event-%s-%s-%s", name, action, eventType) 148 }