blob: 7fc6535314f3ffe7fb2b8dd47f51b85289942d37 [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mesh
import (
"fmt"
"reflect"
"sync"
)
import (
meshconfig "istio.io/api/mesh/v1alpha1"
"istio.io/pkg/filewatcher"
"istio.io/pkg/log"
)
import (
"github.com/apache/dubbo-go-pixiu/pkg/util/protomarshal"
)
// NetworksHolder is a holder of a mesh networks configuration.
type NetworksHolder interface {
SetNetworks(*meshconfig.MeshNetworks)
Networks() *meshconfig.MeshNetworks
}
// NetworksWatcher watches changes to the mesh networks config.
type NetworksWatcher interface {
NetworksHolder
AddNetworksHandler(func())
}
var _ NetworksWatcher = &internalNetworkWatcher{}
type internalNetworkWatcher struct {
mutex sync.RWMutex
handlers []func()
networks *meshconfig.MeshNetworks
}
// NewFixedNetworksWatcher creates a new NetworksWatcher that always returns the given config.
// It will never fire any events, since the config never changes.
func NewFixedNetworksWatcher(networks *meshconfig.MeshNetworks) NetworksWatcher {
return &internalNetworkWatcher{
networks: networks,
}
}
// NewNetworksWatcher creates a new watcher for changes to the given networks config file.
func NewNetworksWatcher(fileWatcher filewatcher.FileWatcher, filename string) (NetworksWatcher, error) {
meshNetworks, err := ReadMeshNetworks(filename)
if err != nil {
return nil, fmt.Errorf("failed to read mesh networks configuration from %q: %v", filename, err)
}
networksdump, _ := protomarshal.ToJSONWithIndent(meshNetworks, " ")
log.Infof("mesh networks configuration: %s", networksdump)
w := &internalNetworkWatcher{
networks: meshNetworks,
}
// Watch the networks config file for changes and reload if it got modified
addFileWatcher(fileWatcher, filename, func() {
// Reload the config file
meshNetworks, err := ReadMeshNetworks(filename)
if err != nil {
log.Warnf("failed to read mesh networks configuration from %q: %v", filename, err)
return
}
w.SetNetworks(meshNetworks)
})
return w, nil
}
// Networks returns the latest network configuration for the mesh.
func (w *internalNetworkWatcher) Networks() *meshconfig.MeshNetworks {
if w == nil {
return nil
}
w.mutex.RLock()
defer w.mutex.RUnlock()
return w.networks
}
// SetNetworks will use the given value for mesh networks and notify all handlers of the change
func (w *internalNetworkWatcher) SetNetworks(meshNetworks *meshconfig.MeshNetworks) {
var handlers []func()
w.mutex.Lock()
if !reflect.DeepEqual(meshNetworks, w.networks) {
networksdump, _ := protomarshal.ToJSONWithIndent(meshNetworks, " ")
log.Infof("mesh networks configuration updated to: %s", networksdump)
// Store the new config.
w.networks = meshNetworks
handlers = append([]func(){}, w.handlers...)
}
w.mutex.Unlock()
// Notify the handlers of the change.
for _, h := range handlers {
h()
}
}
// AddNetworksHandler registers a callback handler for changes to the mesh network config.
func (w *internalNetworkWatcher) AddNetworksHandler(h func()) {
w.mutex.Lock()
defer w.mutex.Unlock()
// hack: prepend handlers; the last to be added will be run first and block other handlers
w.handlers = append([]func(){h}, w.handlers...)
}