istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/mesh/networks_watcher.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 mesh
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"sync"
    21  
    22  	meshconfig "istio.io/api/mesh/v1alpha1"
    23  	"istio.io/istio/pkg/filewatcher"
    24  	"istio.io/istio/pkg/log"
    25  	"istio.io/istio/pkg/slices"
    26  	"istio.io/istio/pkg/util/protomarshal"
    27  )
    28  
    29  // NetworksHolder is a holder of a mesh networks configuration.
    30  type NetworksHolder interface {
    31  	SetNetworks(*meshconfig.MeshNetworks)
    32  	Networks() *meshconfig.MeshNetworks
    33  	PrevNetworks() *meshconfig.MeshNetworks
    34  }
    35  
    36  // WatcherHandlerRegistration will be returned to caller to remove the handler later.
    37  type WatcherHandlerRegistration struct {
    38  	handler func()
    39  }
    40  
    41  // NetworksWatcher watches changes to the mesh networks config.
    42  type NetworksWatcher interface {
    43  	NetworksHolder
    44  
    45  	// AddNetworksHandler registers a callback handler for changes to the networks config.
    46  	AddNetworksHandler(func()) *WatcherHandlerRegistration
    47  
    48  	// DeleteNetworksHandler unregisters a callback handler when remote cluster is removed.
    49  	DeleteNetworksHandler(registration *WatcherHandlerRegistration)
    50  }
    51  
    52  var _ NetworksWatcher = &internalNetworkWatcher{}
    53  
    54  type internalNetworkWatcher struct {
    55  	mutex        sync.RWMutex
    56  	handlers     []*WatcherHandlerRegistration
    57  	networks     *meshconfig.MeshNetworks
    58  	prevNetworks *meshconfig.MeshNetworks
    59  }
    60  
    61  // NewFixedNetworksWatcher creates a new NetworksWatcher that always returns the given config.
    62  // It will never fire any events, since the config never changes.
    63  func NewFixedNetworksWatcher(networks *meshconfig.MeshNetworks) NetworksWatcher {
    64  	return &internalNetworkWatcher{
    65  		networks: networks,
    66  	}
    67  }
    68  
    69  // NewNetworksWatcher creates a new watcher for changes to the given networks config file.
    70  func NewNetworksWatcher(fileWatcher filewatcher.FileWatcher, filename string) (NetworksWatcher, error) {
    71  	meshNetworks, err := ReadMeshNetworks(filename)
    72  	if err != nil {
    73  		return nil, fmt.Errorf("failed to read mesh networks configuration from %q: %v", filename, err)
    74  	}
    75  
    76  	networksdump, _ := protomarshal.ToJSONWithIndent(meshNetworks, "   ")
    77  	log.Infof("mesh networks configuration: %s", networksdump)
    78  
    79  	w := &internalNetworkWatcher{
    80  		networks: meshNetworks,
    81  	}
    82  
    83  	// Watch the networks config file for changes and reload if it got modified
    84  	addFileWatcher(fileWatcher, filename, func() {
    85  		// Reload the config file
    86  		meshNetworks, err := ReadMeshNetworks(filename)
    87  		if err != nil {
    88  			log.Warnf("failed to read mesh networks configuration from %q: %v", filename, err)
    89  			return
    90  		}
    91  		w.SetNetworks(meshNetworks)
    92  	})
    93  	return w, nil
    94  }
    95  
    96  // Networks returns the latest network configuration for the mesh.
    97  func (w *internalNetworkWatcher) Networks() *meshconfig.MeshNetworks {
    98  	if w == nil {
    99  		return nil
   100  	}
   101  	w.mutex.RLock()
   102  	defer w.mutex.RUnlock()
   103  	return w.networks
   104  }
   105  
   106  // PrevNetworks returns the previous network configuration for the mesh.
   107  func (w *internalNetworkWatcher) PrevNetworks() *meshconfig.MeshNetworks {
   108  	if w == nil {
   109  		return nil
   110  	}
   111  	w.mutex.RLock()
   112  	defer w.mutex.RUnlock()
   113  	return w.prevNetworks
   114  }
   115  
   116  // SetNetworks will use the given value for mesh networks and notify all handlers of the change
   117  func (w *internalNetworkWatcher) SetNetworks(meshNetworks *meshconfig.MeshNetworks) {
   118  	var handlers []*WatcherHandlerRegistration
   119  
   120  	w.mutex.Lock()
   121  	if !reflect.DeepEqual(meshNetworks, w.networks) {
   122  		networksdump, _ := protomarshal.ToJSONWithIndent(meshNetworks, "    ")
   123  		log.Infof("mesh networks configuration updated to: %s", networksdump)
   124  
   125  		// Store the new config.
   126  		w.prevNetworks = w.networks
   127  		w.networks = meshNetworks
   128  		handlers = append([]*WatcherHandlerRegistration{}, w.handlers...)
   129  	}
   130  	w.mutex.Unlock()
   131  
   132  	// Notify the handlers of the change.
   133  	for _, h := range handlers {
   134  		h.handler()
   135  	}
   136  }
   137  
   138  // AddNetworksHandler registers a callback handler for changes to the mesh network config.
   139  func (w *internalNetworkWatcher) AddNetworksHandler(h func()) *WatcherHandlerRegistration {
   140  	w.mutex.Lock()
   141  	defer w.mutex.Unlock()
   142  	handler := &WatcherHandlerRegistration{
   143  		handler: h,
   144  	}
   145  	w.handlers = append(w.handlers, handler)
   146  	return handler
   147  }
   148  
   149  // DeleteNetworksHandler deregister a callback handler for changes to the mesh network config.
   150  func (w *internalNetworkWatcher) DeleteNetworksHandler(registration *WatcherHandlerRegistration) {
   151  	if registration == nil {
   152  		return
   153  	}
   154  	w.mutex.Lock()
   155  	defer w.mutex.Unlock()
   156  	if len(w.handlers) == 0 {
   157  		return
   158  	}
   159  
   160  	w.handlers = slices.FilterInPlace(w.handlers, func(handler *WatcherHandlerRegistration) bool {
   161  		return handler != registration
   162  	})
   163  }