istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/config/memory/controller.go (about)

     1  // Copyright Istio 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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package memory
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"k8s.io/apimachinery/pkg/types"
    21  
    22  	"istio.io/istio/pilot/pkg/model"
    23  	"istio.io/istio/pkg/config"
    24  	"istio.io/istio/pkg/config/schema/collection"
    25  	"istio.io/istio/pkg/slices"
    26  )
    27  
    28  // Controller is an implementation of ConfigStoreController.
    29  type Controller struct {
    30  	monitor     Monitor
    31  	configStore model.ConfigStore
    32  	hasSynced   func() bool
    33  
    34  	// If meshConfig.DiscoverySelectors are specified, the namespacesFilter tracks the namespaces this controller watches.
    35  	namespacesFilter func(obj interface{}) bool
    36  }
    37  
    38  // NewController return an implementation of ConfigStoreController
    39  // This is a client-side monitor that dispatches events as the changes are being
    40  // made on the client.
    41  func NewController(cs model.ConfigStore) *Controller {
    42  	out := &Controller{
    43  		configStore: cs,
    44  		monitor:     NewMonitor(cs),
    45  	}
    46  	return out
    47  }
    48  
    49  // NewSyncController return an implementation of model.ConfigStoreController which processes events synchronously
    50  func NewSyncController(cs model.ConfigStore) *Controller {
    51  	out := &Controller{
    52  		configStore: cs,
    53  		monitor:     NewSyncMonitor(cs),
    54  	}
    55  
    56  	return out
    57  }
    58  
    59  func (c *Controller) RegisterHasSyncedHandler(cb func() bool) {
    60  	c.hasSynced = cb
    61  }
    62  
    63  func (c *Controller) RegisterEventHandler(kind config.GroupVersionKind, f model.EventHandler) {
    64  	c.monitor.AppendEventHandler(kind, f)
    65  }
    66  
    67  // HasSynced return whether store has synced
    68  // It can be controlled externally (such as by the data source),
    69  // otherwise it'll always consider synced.
    70  func (c *Controller) HasSynced() bool {
    71  	if c.hasSynced != nil {
    72  		return c.hasSynced()
    73  	}
    74  	return true
    75  }
    76  
    77  func (c *Controller) Run(stop <-chan struct{}) {
    78  	c.monitor.Run(stop)
    79  }
    80  
    81  func (c *Controller) Schemas() collection.Schemas {
    82  	return c.configStore.Schemas()
    83  }
    84  
    85  func (c *Controller) Get(kind config.GroupVersionKind, key, namespace string) *config.Config {
    86  	if c.namespacesFilter != nil && !c.namespacesFilter(namespace) {
    87  		return nil
    88  	}
    89  	return c.configStore.Get(kind, key, namespace)
    90  }
    91  
    92  func (c *Controller) Create(config config.Config) (revision string, err error) {
    93  	if revision, err = c.configStore.Create(config); err == nil {
    94  		c.monitor.ScheduleProcessEvent(ConfigEvent{
    95  			config: config,
    96  			event:  model.EventAdd,
    97  		})
    98  	}
    99  	return
   100  }
   101  
   102  func (c *Controller) Update(config config.Config) (newRevision string, err error) {
   103  	oldconfig := c.configStore.Get(config.GroupVersionKind, config.Name, config.Namespace)
   104  	if newRevision, err = c.configStore.Update(config); err == nil {
   105  		c.monitor.ScheduleProcessEvent(ConfigEvent{
   106  			old:    *oldconfig,
   107  			config: config,
   108  			event:  model.EventUpdate,
   109  		})
   110  	}
   111  	return
   112  }
   113  
   114  func (c *Controller) UpdateStatus(config config.Config) (newRevision string, err error) {
   115  	oldconfig := c.configStore.Get(config.GroupVersionKind, config.Name, config.Namespace)
   116  	if newRevision, err = c.configStore.UpdateStatus(config); err == nil {
   117  		c.monitor.ScheduleProcessEvent(ConfigEvent{
   118  			old:    *oldconfig,
   119  			config: config,
   120  			event:  model.EventUpdate,
   121  		})
   122  	}
   123  	return
   124  }
   125  
   126  func (c *Controller) Patch(orig config.Config, patchFn config.PatchFunc) (newRevision string, err error) {
   127  	cfg, typ := patchFn(orig.DeepCopy())
   128  	switch typ {
   129  	case types.MergePatchType:
   130  	case types.JSONPatchType:
   131  	default:
   132  		return "", fmt.Errorf("unsupported merge type: %s", typ)
   133  	}
   134  	if newRevision, err = c.configStore.Patch(cfg, patchFn); err == nil {
   135  		c.monitor.ScheduleProcessEvent(ConfigEvent{
   136  			old:    orig,
   137  			config: cfg,
   138  			event:  model.EventUpdate,
   139  		})
   140  	}
   141  	return
   142  }
   143  
   144  func (c *Controller) Delete(kind config.GroupVersionKind, key, namespace string, resourceVersion *string) error {
   145  	if config := c.Get(kind, key, namespace); config != nil {
   146  		if err := c.configStore.Delete(kind, key, namespace, resourceVersion); err != nil {
   147  			return err
   148  		}
   149  		c.monitor.ScheduleProcessEvent(ConfigEvent{
   150  			config: *config,
   151  			event:  model.EventDelete,
   152  		})
   153  		return nil
   154  	}
   155  	return fmt.Errorf("delete: config %v/%v/%v does not exist", kind, namespace, key)
   156  }
   157  
   158  func (c *Controller) List(kind config.GroupVersionKind, namespace string) []config.Config {
   159  	configs := c.configStore.List(kind, namespace)
   160  	if c.namespacesFilter != nil {
   161  		return slices.Filter(configs, func(config config.Config) bool {
   162  			return c.namespacesFilter(config)
   163  		})
   164  	}
   165  	return configs
   166  }