github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/events.go (about) 1 /* 2 Copyright 2020 Gravitational, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package types 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/gravitational/trace" 24 ) 25 26 // String returns text description of this event 27 func (r Event) String() string { 28 if r.Type == OpDelete { 29 return fmt.Sprintf("%v(%v/%v)", r.Type, r.Resource.GetKind(), r.Resource.GetSubKind()) 30 } 31 return fmt.Sprintf("%v(%v)", r.Type, r.Resource) 32 } 33 34 // Event represents an event that happened in the backend 35 type Event struct { 36 // Type is the event type 37 Type OpType 38 // Resource is a modified or deleted resource 39 // in case of deleted resources, only resource header 40 // will be provided 41 Resource Resource 42 } 43 44 // OpType specifies operation type 45 type OpType int 46 47 const ( 48 // OpUnreliable is used to indicate the event stream has become unreliable 49 // for maintaining an up-to-date view of the data. 50 OpUnreliable OpType = iota - 2 51 // OpInvalid is returned for invalid operations 52 OpInvalid 53 // OpInit is returned by the system whenever the system 54 // is initialized, init operation is always sent 55 // as a first event over the channel, so the client 56 // can verify that watch has been established. 57 OpInit 58 // OpPut is returned for Put events 59 OpPut 60 // OpDelete is returned for Delete events 61 OpDelete 62 // OpGet is used for tracking, not present in the event stream 63 OpGet 64 ) 65 66 // String returns user-friendly description of the operation 67 func (o OpType) String() string { 68 switch o { 69 case OpUnreliable: 70 return "Unreliable" 71 case OpInvalid: 72 return "Invalid" 73 case OpInit: 74 return "Init" 75 case OpPut: 76 return "Put" 77 case OpDelete: 78 return "Delete" 79 case OpGet: 80 return "Get" 81 default: 82 return "unknown" 83 } 84 } 85 86 // Watch sets up watch on the event 87 type Watch struct { 88 // Name is used for debugging purposes 89 Name string 90 91 // Kinds specifies kinds of objects to watch 92 // and whether to load secret data for them 93 Kinds []WatchKind 94 95 // QueueSize is an optional queue size 96 QueueSize int 97 98 // MetricComponent is used for reporting 99 MetricComponent string 100 101 // AllowPartialSuccess enables a mode in which a watch will succeed if some of the requested kinds aren't available. 102 // When this is set, the client must inspect the WatchStatus resource attached to the first OpInit event emitted 103 // by the watcher for a list of kinds confirmed by the event source. Kinds requested but omitted from the confirmation 104 // will not be included in the event stream. 105 // If AllowPartialSuccess was set, but OpInit doesn't have a resource attached, it means that the event source 106 // doesn't support partial success and all requested resource kinds should be considered confirmed. 107 AllowPartialSuccess bool 108 } 109 110 // Matches attempts to determine if the supplied event matches 111 // this WatchKind. If the WatchKind is misconfigured, or the 112 // event appears malformed, an error is returned. 113 func (kind WatchKind) Matches(e Event) (bool, error) { 114 if kind.Kind != e.Resource.GetKind() { 115 return false, nil 116 } 117 if kind.Name != "" && kind.Name != e.Resource.GetName() { 118 return false, nil 119 } 120 // we don't have a good model for filtering non-put events, 121 // so only apply filters to OpPut events. 122 if len(kind.Filter) > 0 && e.Type == OpPut { 123 switch res := e.Resource.(type) { 124 case AccessRequest: 125 var filter AccessRequestFilter 126 if err := filter.FromMap(kind.Filter); err != nil { 127 return false, trace.Wrap(err) 128 } 129 return filter.Match(res), nil 130 case WebSession: 131 var filter WebSessionFilter 132 if err := filter.FromMap(kind.Filter); err != nil { 133 return false, trace.Wrap(err) 134 } 135 return filter.Match(res), nil 136 case Lock: 137 var target LockTarget 138 if err := target.FromMap(kind.Filter); err != nil { 139 return false, trace.Wrap(err) 140 } 141 return target.Match(res), nil 142 case CertAuthority: 143 var filter CertAuthorityFilter 144 filter.FromMap(kind.Filter) 145 return filter.Match(res), nil 146 case *HeadlessAuthentication: 147 var filter HeadlessAuthenticationFilter 148 filter.FromMap(kind.Filter) 149 return filter.Match(res), nil 150 default: 151 // we don't know about this filter, let the event through 152 } 153 } 154 return true, nil 155 } 156 157 // IsTrivial returns true iff the WatchKind only specifies a Kind but no other field. 158 func (kind WatchKind) IsTrivial() bool { 159 return kind.SubKind == "" && kind.Name == "" && kind.Version == "" && !kind.LoadSecrets && len(kind.Filter) == 0 160 } 161 162 // Contains determines whether kind (receiver) targets exactly the same or a wider scope of events as the given subset kind. 163 // Generally this means that if kind specifies a filter, its subset must have exactly the same or a narrower one. 164 // Currently, does not take resource versions into account. 165 func (kind WatchKind) Contains(subset WatchKind) bool { 166 // kind and subkind must always be equal 167 if kind.Kind != subset.Kind || kind.SubKind != subset.SubKind { 168 return false 169 } 170 171 if kind.Name != "" && kind.Name != subset.Name { 172 return false 173 } 174 175 if !kind.LoadSecrets && subset.LoadSecrets { 176 return false 177 } 178 179 if kind.Kind == KindCertAuthority { 180 var a, b CertAuthorityFilter 181 a.FromMap(kind.Filter) 182 b.FromMap(subset.Filter) 183 return a.Contains(b) 184 } 185 186 for k, v := range kind.Filter { 187 if subset.Filter[k] != v { 188 return false 189 } 190 } 191 192 return true 193 } 194 195 // Events returns new events interface 196 type Events interface { 197 // NewWatcher returns a new event watcher 198 NewWatcher(ctx context.Context, watch Watch) (Watcher, error) 199 } 200 201 // Watcher returns watcher 202 type Watcher interface { 203 // Events returns channel with events 204 Events() <-chan Event 205 206 // Done returns the channel signaling the closure 207 Done() <-chan struct{} 208 209 // Close closes the watcher and releases 210 // all associated resources 211 Close() error 212 213 // Error returns error associated with watcher 214 Error() error 215 }