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 }