github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/aagent/machine/notifications.go (about) 1 // Copyright (c) 2019-2022, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package machine 6 7 import ( 8 "fmt" 9 "time" 10 11 "github.com/choria-io/go-choria/internal/util" 12 13 cloudevents "github.com/cloudevents/sdk-go/v2" 14 ) 15 16 // TransitionNotification is a notification when a transition completes 17 type TransitionNotification struct { 18 Protocol string `json:"protocol"` 19 Identity string `json:"identity"` 20 ID string `json:"id"` 21 Version string `json:"version"` 22 Timestamp int64 `json:"timestamp"` 23 Machine string `json:"machine"` 24 Transition string `json:"transition"` 25 FromState string `json:"from_state"` 26 ToState string `json:"to_state"` 27 28 Info InfoSource `json:"-"` 29 } 30 31 // String returns a string representation of the event 32 func (t *TransitionNotification) String() string { 33 return fmt.Sprintf("%s %s transitioned via event %s: %s => %s", t.Identity, t.Machine, t.Transition, t.FromState, t.ToState) 34 } 35 36 // CloudEvent creates a cloud event from the transition 37 func (t *TransitionNotification) CloudEvent() cloudevents.Event { 38 event := cloudevents.NewEvent("1.0") 39 40 event.SetType(t.Protocol) 41 event.SetSource("io.choria.machine") 42 event.SetSubject(t.Identity) 43 event.SetID(util.UniqueID()) 44 event.SetTime(time.Unix(t.Timestamp, 0)) 45 event.SetData(cloudevents.ApplicationJSON, t) 46 47 return event 48 } 49 50 // InfoSource provides information about a running machine 51 type InfoSource interface { 52 // Identity retrieves the identity of the node hosting this machine, "unknown" when not set 53 Identity() string 54 // Version returns the version of the machine 55 Version() string 56 // Name is the name of the machine 57 Name() string 58 // State returns the current state of the machine 59 State() string 60 // InstanceID return the unique ID of the machine instance 61 InstanceID() string 62 } 63 64 // WatcherStateNotification is a notification about the state of a watcher 65 type WatcherStateNotification interface { 66 JSON() ([]byte, error) 67 CloudEvent() cloudevents.Event 68 String() string 69 WatcherType() string 70 SenderID() string 71 } 72 73 // NotificationService receives events notifications about the state machine 74 type NotificationService interface { 75 // NotifyPostTransition receives an event after a transition completed 76 NotifyPostTransition(t *TransitionNotification) error 77 78 // NotifyWatcherState receives the current state of a watcher either after running or periodically 79 NotifyWatcherState(watcher string, state WatcherStateNotification) error 80 81 // Debugf logs a message at debug level 82 Debugf(machine InfoSource, watcher string, format string, args ...any) 83 84 // Infof logs a message at info level 85 Infof(machine InfoSource, watcher string, format string, args ...any) 86 87 // Warnf logs a message at warning level 88 Warnf(machine InfoSource, watcher string, format string, args ...any) 89 90 // Errorf logs a message at error level 91 Errorf(machine InfoSource, watcher string, format string, args ...any) 92 } 93 94 // RegisterNotifier adds a new NotificationService to the list of ones to receive notifications 95 func (m *Machine) RegisterNotifier(services ...NotificationService) { 96 m.notifiers = append(m.notifiers, services...) 97 } 98 99 // Debugf implements NotificationService 100 func (m *Machine) Debugf(watcher string, format string, args ...any) { 101 for _, n := range m.notifiers { 102 n.Debugf(m, watcher, format, args...) 103 } 104 } 105 106 // Infof implements NotificationService 107 func (m *Machine) Infof(watcher string, format string, args ...any) { 108 for _, n := range m.notifiers { 109 n.Infof(m, watcher, format, args...) 110 } 111 } 112 113 // Warnf implements NotificationService 114 func (m *Machine) Warnf(watcher string, format string, args ...any) { 115 for _, n := range m.notifiers { 116 n.Warnf(m, watcher, format, args...) 117 } 118 } 119 120 // Errorf implements NotificationService 121 func (m *Machine) Errorf(watcher string, format string, args ...any) { 122 for _, n := range m.notifiers { 123 n.Errorf(m, watcher, format, args...) 124 } 125 } 126 127 // NotifyWatcherState implements NotificationService 128 func (m *Machine) NotifyWatcherState(watcher string, state any) { 129 notification, ok := state.(WatcherStateNotification) 130 if !ok { 131 m.Errorf(watcher, "Could not notify watcher state: state does not implement WatcherStateNotification: %#v", state) 132 return 133 } 134 135 for _, n := range m.notifiers { 136 err := n.NotifyWatcherState(watcher, notification) 137 if err != nil { 138 m.Errorf(watcher, "Could not notify watcher state: %s", err) 139 } 140 } 141 }