github.com/cloudwan/edgelq-sdk@v1.15.4/iam/access/v1alpha2/service_account/service_account.pb.watcher.go (about) 1 // Code generated by protoc-gen-goten-access 2 // Resource: ServiceAccount 3 // DO NOT EDIT!!! 4 5 package service_account_access 6 7 import ( 8 "context" 9 "errors" 10 "fmt" 11 "sync/atomic" 12 13 "google.golang.org/grpc" 14 "google.golang.org/protobuf/proto" 15 16 gotenaccess "github.com/cloudwan/goten-sdk/runtime/access" 17 gotenobservability "github.com/cloudwan/goten-sdk/runtime/observability" 18 gotenresource "github.com/cloudwan/goten-sdk/runtime/resource" 19 "github.com/cloudwan/goten-sdk/types/view" 20 "github.com/cloudwan/goten-sdk/types/watch_type" 21 22 service_account_client "github.com/cloudwan/edgelq-sdk/iam/client/v1alpha2/service_account" 23 service_account "github.com/cloudwan/edgelq-sdk/iam/resources/v1alpha2/service_account" 24 ) 25 26 // TODO: This watcher is for stateless watch type only de facto as of now. 27 // Ordering and multiple filters do not cooperate at all. 28 // We could: 29 // * Add Cursor as parameter to NewWatcher + page size to WatcherConfig 30 // * Add ResetCursor method to Watcher - only one page available at the time byt still dynamic 31 // * Merge many pages with sorting/pagination within watcher and forward aggregated changes. 32 33 // Watcher is higher level stateful watcher with dynamic + multi filter support. 34 type Watcher struct { 35 client service_account_client.ServiceAccountServiceClient 36 config *WatcherConfig 37 outputEvtChan chan WatcherEvent 38 iOutputEvtChan chan gotenaccess.WatcherEvent 39 queryWatcherStates map[int]*queryWatcherState 40 watcherEvtsChan chan *QueryWatcherEvent 41 filters []*WatcherFilterParams 42 filtersResetChan chan struct { 43 f []*WatcherFilterParams 44 v int32 45 } 46 inSyncFlag int32 47 nextIdentifier int 48 watcherCtx context.Context 49 watcherCtxCancel context.CancelFunc 50 useIChan int32 51 nextFiltersVersion int32 52 filtersVersion int32 53 } 54 55 type WatcherConfig struct { 56 *gotenaccess.WatcherConfigBase 57 58 // common params that must be shared across queries 59 WatchType watch_type.WatchType 60 View view.View 61 FieldMask *service_account.ServiceAccount_FieldMask 62 OrderBy *service_account.OrderBy 63 ChunkSize int 64 } 65 66 type WatcherFilterParams struct { 67 Parent *service_account.ParentName 68 Filter *service_account.Filter 69 } 70 71 func (p *WatcherFilterParams) String() string { 72 if p == nil { 73 return "<nil>" 74 } 75 return fmt.Sprintf("%s.%s", p.Parent, p.Filter) 76 } 77 78 func (p *WatcherFilterParams) GetIFilter() gotenresource.Filter { 79 return p.Filter 80 } 81 82 func (p *WatcherFilterParams) GetIParentName() gotenresource.Name { 83 return p.Parent 84 } 85 86 type queryWatcherState struct { 87 cancel context.CancelFunc 88 watcher *QueryWatcher 89 inSync bool 90 cache map[service_account.Name]*service_account.ServiceAccount 91 filter *WatcherFilterParams 92 inSnapshot bool 93 pendingSnapshot []*service_account.ServiceAccountChange 94 } 95 96 func NewWatcher(client service_account_client.ServiceAccountServiceClient, config *WatcherConfig, filters ...*WatcherFilterParams) *Watcher { 97 ctx, cancel := context.WithCancel(context.Background()) 98 watcher := &Watcher{ 99 client: client, 100 config: config, 101 filters: filters, 102 outputEvtChan: make(chan WatcherEvent, config.WatcherEventBufferSize), 103 queryWatcherStates: map[int]*queryWatcherState{}, 104 watcherEvtsChan: make(chan *QueryWatcherEvent, config.WatcherEventBufferSize), 105 filtersResetChan: make(chan struct { 106 f []*WatcherFilterParams 107 v int32 108 }, 5), 109 watcherCtx: ctx, 110 watcherCtxCancel: cancel, 111 } 112 watcher.filtersResetChan <- struct { 113 f []*WatcherFilterParams 114 v int32 115 }{f: filters, v: 0} 116 return watcher 117 } 118 119 func (pw *Watcher) Events() <-chan WatcherEvent { 120 return pw.outputEvtChan 121 } 122 123 func (pw *Watcher) IEvents() <-chan gotenaccess.WatcherEvent { 124 if atomic.CompareAndSwapInt32(&pw.useIChan, 0, 1) { 125 pw.iOutputEvtChan = make(chan gotenaccess.WatcherEvent, pw.config.WatcherEventBufferSize) 126 go func() { 127 for { 128 select { 129 case <-pw.watcherCtx.Done(): 130 return 131 case evt := <-pw.outputEvtChan: 132 select { 133 case <-pw.watcherCtx.Done(): 134 return 135 case pw.iOutputEvtChan <- &evt: 136 } 137 } 138 } 139 }() 140 } 141 return pw.iOutputEvtChan 142 } 143 144 func (pw *Watcher) InSync() bool { 145 return atomic.LoadInt32(&pw.inSyncFlag) > 0 146 } 147 148 func (pw *Watcher) GetFilters() []*WatcherFilterParams { 149 copied := make([]*WatcherFilterParams, 0, len(pw.filters)) 150 for _, query := range pw.filters { 151 cQuery := &WatcherFilterParams{} 152 if query.Parent != nil { 153 cQuery.Parent = &service_account.ParentName{} 154 *cQuery.Parent = *query.Parent 155 } 156 if query.Filter != nil { 157 strValue, _ := query.Filter.ProtoString() 158 cQuery.Filter = &service_account.Filter{} 159 _ = cQuery.Filter.ParseProtoString(strValue) 160 } 161 copied = append(copied, cQuery) 162 } 163 return copied 164 } 165 166 func (pw *Watcher) GetIFilters() []gotenaccess.WatcherFilterParams { 167 filters := pw.GetFilters() 168 result := make([]gotenaccess.WatcherFilterParams, 0, len(filters)) 169 for _, filter := range filters { 170 result = append(result, filter) 171 } 172 return result 173 } 174 175 func (pw *Watcher) ResetFilters(ctx context.Context, filters ...*WatcherFilterParams) (int32, error) { 176 pw.nextFiltersVersion++ 177 pw.filters = filters 178 select { 179 case <-ctx.Done(): 180 return -1, ctx.Err() 181 case pw.filtersResetChan <- struct { 182 f []*WatcherFilterParams 183 v int32 184 }{f: filters, v: pw.nextFiltersVersion}: 185 } 186 return pw.nextFiltersVersion, nil 187 } 188 189 func (pw *Watcher) ResetIFilters(ctx context.Context, filters ...gotenaccess.WatcherFilterParams) (int32, error) { 190 typedFilters := make([]*WatcherFilterParams, 0, len(filters)) 191 for _, filter := range filters { 192 typedFilters = append(typedFilters, filter.(*WatcherFilterParams)) 193 } 194 return pw.ResetFilters(ctx, typedFilters...) 195 } 196 197 func (pw *Watcher) Run(ctx context.Context) error { 198 log := gotenobservability.LoggerFromContext(ctx). 199 WithField("watcher", "serviceAccount-watcher") 200 ctx = gotenobservability.LoggerToContext(ctx, log) 201 202 log.Debugf("running") 203 defer func() { 204 for _, state := range pw.queryWatcherStates { 205 state.cancel() 206 } 207 pw.watcherCtxCancel() 208 }() 209 210 for { 211 select { 212 case newFilters := <-pw.filtersResetChan: 213 pw.filtersVersion = newFilters.v 214 pw.resetFilters(ctx, newFilters.f) 215 case evt := <-pw.watcherEvtsChan: 216 if evt.LostSync { 217 pw.onQueryLostSync(ctx, evt) 218 } else if evt.CheckSize { 219 pw.onQueryVerifySnapshotSize(ctx, evt) 220 } else if evt.Reset { 221 pw.onQueryResetStateIndicator(evt) 222 } else { 223 pw.onQueryChanges(ctx, evt) 224 } 225 case <-ctx.Done(): 226 log.Debugf("context done, reason: %s", ctx.Err()) 227 if errors.Is(ctx.Err(), context.Canceled) { 228 return nil 229 } else { 230 return ctx.Err() 231 } 232 } 233 } 234 } 235 236 func (pw *Watcher) resetFilters(ctx context.Context, filters []*WatcherFilterParams) { 237 filtersMap := map[string]*WatcherFilterParams{} 238 for _, filter := range filters { 239 filtersMap[filter.String()] = filter 240 } 241 242 // Eliminate existing queries from queriesMap, eliminate queries that should be stopped 243 for identifier, state := range pw.queryWatcherStates { 244 key := state.filter.String() 245 if _, exists := filtersMap[key]; !exists { 246 state.cancel() 247 delete(pw.queryWatcherStates, identifier) 248 } else { 249 delete(filtersMap, key) 250 } 251 } 252 253 // start new queries with new filters 254 for _, filter := range filtersMap { 255 wctx, cancel := context.WithCancel(ctx) 256 newWatcher := NewQueryWatcher( 257 pw.nextIdentifier, 258 pw.client, 259 &QueryWatcherParams{ 260 Parent: filter.Parent, 261 Filter: filter.Filter, 262 View: pw.config.View, 263 FieldMask: pw.config.FieldMask, 264 OrderBy: pw.config.OrderBy, 265 ChunkSize: pw.config.ChunkSize, 266 WatchType: pw.config.WatchType, 267 RecoveryDeadline: pw.config.RecoveryDeadline, 268 RetryTimeout: pw.config.RetryTimeout, 269 }, 270 pw.watcherEvtsChan) 271 pw.queryWatcherStates[pw.nextIdentifier] = &queryWatcherState{ 272 cancel: cancel, 273 watcher: newWatcher, 274 cache: map[service_account.Name]*service_account.ServiceAccount{}, 275 filter: filter, 276 inSnapshot: true, 277 } 278 pw.nextIdentifier++ 279 280 go func() { 281 _ = newWatcher.Run(wctx) 282 }() 283 } 284 285 // if all in sync (possible if queries were eliminated with ResetFilters call), send snapshot, otherwise 286 // communicate "lost sync" 287 if pw.allInSync() { 288 pw.processSnapshot(ctx) 289 } else if pw.inSyncFlag > 0 { 290 pw.processSyncLost(ctx) 291 } 292 } 293 294 func (pw *Watcher) onQueryLostSync(ctx context.Context, evt *QueryWatcherEvent) { 295 state := pw.queryWatcherStates[evt.Identifier] 296 if state == nil { 297 return 298 } 299 state.inSync = false 300 state.cache = map[service_account.Name]*service_account.ServiceAccount{} 301 state.inSnapshot = true 302 if pw.inSyncFlag > 0 { 303 pw.processSyncLost(ctx) 304 } 305 } 306 307 func (pw *Watcher) onQueryVerifySnapshotSize(ctx context.Context, evt *QueryWatcherEvent) { 308 state := pw.queryWatcherStates[evt.Identifier] 309 if state == nil { 310 return 311 } 312 currentSize := state.computeSize(evt.Changes) 313 if currentSize != evt.SnapshotSize { 314 gotenobservability.LoggerFromContext(ctx). 315 Warnf("Detected mismatch in snapshot size for filter %s: expected %d, has %d", 316 state.filter, evt.SnapshotSize, currentSize) 317 state.cancel() 318 delete(pw.queryWatcherStates, evt.Identifier) 319 320 // refresh this particular watcher 321 wctx, cancel := context.WithCancel(ctx) 322 newWatcher := NewQueryWatcher( 323 pw.nextIdentifier, 324 pw.client, 325 &QueryWatcherParams{ 326 Parent: state.filter.Parent, 327 Filter: state.filter.Filter, 328 View: pw.config.View, 329 FieldMask: pw.config.FieldMask, 330 OrderBy: pw.config.OrderBy, 331 ChunkSize: pw.config.ChunkSize, 332 WatchType: pw.config.WatchType, 333 RecoveryDeadline: pw.config.RecoveryDeadline, 334 RetryTimeout: pw.config.RetryTimeout, 335 }, 336 pw.watcherEvtsChan) 337 pw.queryWatcherStates[pw.nextIdentifier] = &queryWatcherState{ 338 cancel: cancel, 339 watcher: newWatcher, 340 cache: state.cache, 341 filter: state.filter, 342 inSnapshot: true, 343 inSync: state.inSync, 344 } 345 pw.nextIdentifier++ 346 347 go func() { 348 _ = newWatcher.Run(wctx) 349 }() 350 } 351 } 352 353 func (pw *Watcher) onQueryResetStateIndicator(evt *QueryWatcherEvent) { 354 state := pw.queryWatcherStates[evt.Identifier] 355 if state == nil { 356 return 357 } 358 state.inSnapshot = true 359 state.pendingSnapshot = nil 360 } 361 362 func (pw *Watcher) onQueryChanges(ctx context.Context, evt *QueryWatcherEvent) { 363 var changes []*WatcherEventChange 364 state := pw.queryWatcherStates[evt.Identifier] 365 if state == nil { 366 return 367 } 368 369 // evt.InSync is set when snapshot is complete or for every incremental update 370 // Since Watcher is stateful, we will collect query snapshot data without processing 371 // till its complete. 372 if state.inSnapshot { 373 state.pendingSnapshot = append(state.pendingSnapshot, evt.Changes...) 374 if evt.InSync { 375 // processes snapshot for this query only 376 // changes however may be only a diff from previous known state 377 changes = state.processSnapshot() 378 } 379 } else { 380 changes = state.transform(evt.Changes) 381 } 382 if evt.InSync { 383 if !state.inSync { 384 state.inSync = true 385 if pw.allInSync() { 386 pw.processSnapshot(ctx) 387 return 388 } 389 } else if pw.inSyncFlag > 0 { 390 evt := &WatcherEvent{WatcherEventBase: gotenaccess.NewWatcherEventBase(false, pw.filtersVersion), Changes: changes} 391 pw.sendEvent(ctx, evt) 392 } 393 } 394 } 395 396 func (pw *Watcher) processSyncLost(ctx context.Context) { 397 gotenobservability.LoggerFromContext(ctx).Infof("Notifiying watcher-wide sync lost") 398 atomic.StoreInt32(&pw.inSyncFlag, 0) 399 evt := &WatcherEvent{WatcherEventBase: gotenaccess.NewWatcherEventBaseLostSync(pw.filtersVersion)} 400 pw.sendEvent(ctx, evt) 401 } 402 403 func (pw *Watcher) processSnapshot(ctx context.Context) { 404 gotenobservability.LoggerFromContext(ctx).Infof("Watcher in sync") 405 atomic.StoreInt32(&pw.inSyncFlag, 1) 406 snapshot := make([]*WatcherEventChange, 0) 407 for _, state := range pw.queryWatcherStates { 408 for _, item := range state.cache { 409 snapshot = append(snapshot, NewAddWatcherEventChange(item)) 410 } 411 } 412 evt := &WatcherEvent{WatcherEventBase: gotenaccess.NewWatcherEventBase(true, pw.filtersVersion), Changes: snapshot} 413 pw.sendEvent(ctx, evt) 414 } 415 416 func (pw *Watcher) allInSync() bool { 417 for _, state := range pw.queryWatcherStates { 418 if !state.inSync { 419 return false 420 } 421 } 422 return true 423 } 424 425 func (pw *Watcher) sendEvent(ctx context.Context, evt *WatcherEvent) { 426 select { 427 case <-ctx.Done(): 428 case pw.outputEvtChan <- *evt: 429 } 430 } 431 432 type WatcherEventChange struct { 433 pre, post *service_account.ServiceAccount 434 name *service_account.Name 435 } 436 437 func NewAddWatcherEventChange(resource *service_account.ServiceAccount) *WatcherEventChange { 438 return &WatcherEventChange{ 439 post: resource, 440 name: resource.GetName(), 441 } 442 } 443 444 func NewModifyWatcherEventChange(current, previous *service_account.ServiceAccount) *WatcherEventChange { 445 return &WatcherEventChange{ 446 pre: previous, 447 post: current, 448 name: current.GetName(), 449 } 450 } 451 452 func NewDeleteWatcherEventChange(deleted *service_account.ServiceAccount) *WatcherEventChange { 453 return &WatcherEventChange{ 454 pre: deleted, 455 name: deleted.GetName(), 456 } 457 } 458 459 func (c *WatcherEventChange) GetName() *service_account.Name { 460 return c.name 461 } 462 463 func (c *WatcherEventChange) GetRawName() gotenresource.Name { 464 return c.name 465 } 466 467 func (c *WatcherEventChange) IsAdd() bool { 468 return c.pre == nil && c.post != nil 469 } 470 471 func (c *WatcherEventChange) IsModify() bool { 472 return c.pre != nil && c.post != nil 473 } 474 475 func (c *WatcherEventChange) IsDelete() bool { 476 return c.pre != nil && c.post == nil 477 } 478 479 func (c *WatcherEventChange) GetAdded() *service_account.ServiceAccount { 480 if c.IsAdd() { 481 return c.post 482 } 483 return nil 484 } 485 486 func (c *WatcherEventChange) GetDeleted() *service_account.ServiceAccount { 487 if c.IsDelete() { 488 return c.pre 489 } 490 return nil 491 } 492 493 func (c *WatcherEventChange) GetPrevious() *service_account.ServiceAccount { 494 if c.IsModify() { 495 return c.pre 496 } 497 return nil 498 } 499 500 func (c *WatcherEventChange) GetCurrent() *service_account.ServiceAccount { 501 if c.IsAdd() || c.IsModify() { 502 return c.post 503 } 504 return nil 505 } 506 507 func (c *WatcherEventChange) GetRawAdded() gotenresource.Resource { 508 return c.GetAdded() 509 } 510 511 func (c *WatcherEventChange) GetRawDeleted() gotenresource.Resource { 512 return c.GetDeleted() 513 } 514 515 func (c *WatcherEventChange) GetRawPrevious() gotenresource.Resource { 516 return c.GetPrevious() 517 } 518 519 func (c *WatcherEventChange) GetRawCurrent() gotenresource.Resource { 520 return c.GetCurrent() 521 } 522 523 type WatcherEvent struct { 524 gotenaccess.WatcherEventBase 525 Changes []*WatcherEventChange 526 } 527 528 func (e *WatcherEvent) GetAt(index int) *WatcherEventChange { 529 if e == nil || len(e.Changes) <= index { 530 return nil 531 } 532 return e.Changes[index] 533 } 534 535 func (e *WatcherEvent) GetRawAt(index int) gotenaccess.WatcherEventChange { 536 return e.GetAt(index) 537 } 538 539 func (e *WatcherEvent) Length() int { 540 if e == nil { 541 return 0 542 } 543 return len(e.Changes) 544 } 545 546 func (e *WatcherEvent) AppendChange(change *WatcherEventChange) { 547 e.Changes = append(e.Changes, change) 548 } 549 550 func (e *WatcherEvent) AppendRawChange(change gotenaccess.WatcherEventChange) { 551 e.Changes = append(e.Changes, change.(*WatcherEventChange)) 552 } 553 554 // Merge makes a shallow merge of two events 555 func (e *WatcherEvent) Merge(src *WatcherEvent) { 556 if src == nil { 557 return 558 } 559 if src.LostSync() || src.Resync() { 560 e.WatcherEventBase = src.WatcherEventBase 561 e.Changes = src.Changes 562 return 563 } 564 if !e.WatcherEventBase.Resync() { 565 e.WatcherEventBase = src.WatcherEventBase 566 e.Changes = append(e.Changes, src.Changes...) 567 return 568 } 569 570 // merge non-resync into resync 571 byName := make(map[service_account.Name]*service_account.ServiceAccount, len(src.Changes)+len(e.Changes)) 572 for _, currentChange := range e.Changes { 573 serviceAccount := currentChange.GetCurrent() 574 byName[*serviceAccount.GetName()] = serviceAccount 575 } 576 for _, change := range src.Changes { 577 if change.IsDelete() { 578 delete(byName, *change.GetName()) 579 } else { 580 serviceAccount := change.GetCurrent() 581 byName[*serviceAccount.GetName()] = serviceAccount 582 } 583 } 584 e.Changes = make([]*WatcherEventChange, 0, len(byName)) 585 for _, serviceAccount := range byName { 586 e.Changes = append(e.Changes, NewAddWatcherEventChange(serviceAccount)) 587 } 588 } 589 590 func (qws *queryWatcherState) processSnapshot() []*WatcherEventChange { 591 watcherEventChanges := make([]*WatcherEventChange, 0, len(qws.pendingSnapshot)) 592 prevCache := qws.cache 593 qws.cache = map[service_account.Name]*service_account.ServiceAccount{} 594 595 for _, change := range qws.pendingSnapshot { 596 var currentItem *service_account.ServiceAccount 597 switch item := change.ChangeType.(type) { 598 case *service_account.ServiceAccountChange_Added_: 599 currentItem = item.Added.GetServiceAccount() 600 case *service_account.ServiceAccountChange_Current_: 601 currentItem = item.Current.GetServiceAccount() 602 } 603 name := *currentItem.GetName() 604 qws.cache[name] = currentItem 605 previous, exists := prevCache[name] 606 if !exists { 607 watcherEventChanges = append(watcherEventChanges, NewAddWatcherEventChange(currentItem)) 608 } else { 609 if !proto.Equal(currentItem, previous) { 610 watcherEventChanges = append(watcherEventChanges, NewModifyWatcherEventChange(currentItem, previous)) 611 } 612 delete(prevCache, name) 613 } 614 } 615 // remaining items 616 for _, resource := range prevCache { 617 watcherEventChanges = append(watcherEventChanges, NewDeleteWatcherEventChange(resource)) 618 } 619 qws.pendingSnapshot = nil 620 qws.inSnapshot = false 621 return watcherEventChanges 622 } 623 624 func (qws *queryWatcherState) transform(rawChanges []*service_account.ServiceAccountChange) []*WatcherEventChange { 625 watcherEventChanges := make([]*WatcherEventChange, 0, len(rawChanges)) 626 627 for _, change := range rawChanges { 628 switch item := change.ChangeType.(type) { 629 case *service_account.ServiceAccountChange_Added_: 630 newItem := item.Added.GetServiceAccount() 631 qws.cache[*newItem.GetName()] = newItem 632 watcherEventChanges = append(watcherEventChanges, NewAddWatcherEventChange(newItem)) 633 case *service_account.ServiceAccountChange_Modified_: 634 updatedItem := item.Modified.GetServiceAccount() 635 previousItem := qws.cache[*updatedItem.GetName()] 636 qws.cache[*updatedItem.GetName()] = updatedItem 637 watcherEventChanges = append(watcherEventChanges, NewModifyWatcherEventChange(updatedItem, previousItem)) 638 case *service_account.ServiceAccountChange_Current_: 639 currentItem := item.Current.GetServiceAccount() 640 previousItem := qws.cache[*currentItem.GetName()] 641 qws.cache[*currentItem.GetName()] = currentItem 642 if previousItem != nil { 643 watcherEventChanges = append(watcherEventChanges, NewModifyWatcherEventChange(currentItem, previousItem)) 644 } else { 645 watcherEventChanges = append(watcherEventChanges, NewAddWatcherEventChange(currentItem)) 646 } 647 case *service_account.ServiceAccountChange_Removed_: 648 deletedItem := qws.cache[*item.Removed.Name] 649 delete(qws.cache, *item.Removed.Name) 650 watcherEventChanges = append(watcherEventChanges, NewDeleteWatcherEventChange(deletedItem)) 651 } 652 } 653 return watcherEventChanges 654 } 655 656 func (qws *queryWatcherState) computeSize(pendingChanges []*service_account.ServiceAccountChange) int64 { 657 size := int64(len(qws.cache)) 658 for _, pendingChange := range append(qws.pendingSnapshot, pendingChanges...) { 659 name := *pendingChange.GetServiceAccountName() 660 if pendingChange.IsDelete() { 661 if _, exists := qws.cache[name]; exists { 662 size-- 663 } 664 } else { 665 if _, exists := qws.cache[name]; !exists { 666 size++ 667 } 668 } 669 } 670 return size 671 } 672 673 func init() { 674 gotenaccess.GetRegistry().RegisterWatcherConstructor(service_account.GetDescriptor(), func(cc grpc.ClientConnInterface, params *gotenaccess.WatcherConfigParams, filters ...gotenaccess.WatcherFilterParams) gotenaccess.Watcher { 675 cfg := &WatcherConfig{ 676 WatcherConfigBase: params.CfgBase, 677 WatchType: params.WatchType, 678 View: params.View, 679 ChunkSize: params.ChunkSize, 680 } 681 if params.FieldMask != nil { 682 cfg.FieldMask = params.FieldMask.(*service_account.ServiceAccount_FieldMask) 683 } 684 if params.OrderBy != nil { 685 cfg.OrderBy = params.OrderBy.(*service_account.OrderBy) 686 } 687 typedFilters := make([]*WatcherFilterParams, 0, len(filters)) 688 for _, filter := range filters { 689 typedFilters = append(typedFilters, filter.(*WatcherFilterParams)) 690 } 691 return NewWatcher(service_account_client.NewServiceAccountServiceClient(cc), cfg, typedFilters...) 692 }) 693 gotenaccess.GetRegistry().RegisterWatcherFilterConstructor(service_account.GetDescriptor(), func(filter gotenresource.Filter, parent gotenresource.Name) gotenaccess.WatcherFilterParams { 694 params := &WatcherFilterParams{} 695 if filter != nil { 696 params.Filter = filter.(*service_account.Filter) 697 } 698 if parent != nil { 699 params.Parent = parent.(*service_account.ParentName) 700 } 701 return params 702 }) 703 }