pkg/ingress/kube/configmap/controller.go (176 lines of code) (raw):

// Copyright (c) 2022 Alibaba Group Holding Ltd. // // 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 configmap import ( "reflect" "sync/atomic" "github.com/alibaba/higress/registry/reconcile" "istio.io/istio/pilot/pkg/model" "istio.io/istio/pkg/cluster" "istio.io/istio/pkg/config" "istio.io/istio/pkg/config/schema/gvr" "istio.io/istio/pkg/config/schema/kind" schemakubeclient "istio.io/istio/pkg/config/schema/kubeclient" kubeclient "istio.io/istio/pkg/kube" "istio.io/istio/pkg/kube/controllers" ktypes "istio.io/istio/pkg/kube/kubetypes" "k8s.io/apimachinery/pkg/types" listersv1 "k8s.io/client-go/listers/core/v1" "sigs.k8s.io/yaml" "github.com/alibaba/higress/pkg/ingress/kube/controller" "github.com/alibaba/higress/pkg/ingress/kube/util" . "github.com/alibaba/higress/pkg/ingress/log" ) type HigressConfigController controller.Controller[listersv1.ConfigMapNamespaceLister] func NewController(client kubeclient.Client, clusterId cluster.ID, namespace string) HigressConfigController { opts := ktypes.InformerOptions{ Namespace: namespace, Cluster: clusterId, } informer := schemakubeclient.GetInformerFilteredFromGVR(client, opts, gvr.ConfigMap) lister := listersv1.NewConfigMapLister(informer.Informer.GetIndexer()).ConfigMaps(namespace) return controller.NewCommonController("higressConfig", lister, informer.Informer, GetConfigmap, clusterId) } func GetConfigmap(lister listersv1.ConfigMapNamespaceLister, namespacedName types.NamespacedName) (controllers.Object, error) { return lister.Get(namespacedName.Name) } type ItemController interface { GetName() string AddOrUpdateHigressConfig(name util.ClusterNamespacedName, old *HigressConfig, new *HigressConfig) error ValidHigressConfig(higressConfig *HigressConfig) error ConstructEnvoyFilters() ([]*config.Config, error) RegisterItemEventHandler(eventHandler ItemEventHandler) RegisterMcpReconciler(reconciler *reconcile.Reconciler) } type ConfigmapMgr struct { Namespace string HigressConfigController HigressConfigController HigressConfigLister listersv1.ConfigMapNamespaceLister higressConfig atomic.Value ItemControllers []ItemController XDSUpdater model.XDSUpdater } func NewConfigmapMgr(XDSUpdater model.XDSUpdater, namespace string, higressConfigController HigressConfigController, higressConfigLister listersv1.ConfigMapNamespaceLister) *ConfigmapMgr { configmapMgr := &ConfigmapMgr{ XDSUpdater: XDSUpdater, Namespace: namespace, HigressConfigController: higressConfigController, HigressConfigLister: higressConfigLister, higressConfig: atomic.Value{}, } configmapMgr.HigressConfigController.AddEventHandler(configmapMgr.AddOrUpdateHigressConfig) configmapMgr.SetHigressConfig(NewDefaultHigressConfig()) tracingController := NewTracingController(namespace) configmapMgr.AddItemControllers(tracingController) gzipController := NewGzipController(namespace) configmapMgr.AddItemControllers(gzipController) globalOptionController := NewGlobalOptionController(namespace) configmapMgr.AddItemControllers(globalOptionController) mcpServerController := NewMcpServerController(namespace) configmapMgr.AddItemControllers(mcpServerController) configmapMgr.initEventHandlers() return configmapMgr } func (c *ConfigmapMgr) SetHigressConfig(higressConfig *HigressConfig) { c.higressConfig.Store(higressConfig) } func (c *ConfigmapMgr) GetHigressConfig() *HigressConfig { value := c.higressConfig.Load() if value != nil { if higressConfig, ok := value.(*HigressConfig); ok { return higressConfig } } return nil } func (c *ConfigmapMgr) SetMcpReconciler(reconciler *reconcile.Reconciler) { for _, itemController := range c.ItemControllers { itemController.RegisterMcpReconciler(reconciler) } } func (c *ConfigmapMgr) AddItemControllers(controllers ...ItemController) { c.ItemControllers = append(c.ItemControllers, controllers...) } func (c *ConfigmapMgr) AddOrUpdateHigressConfig(name util.ClusterNamespacedName) { if name.Namespace != c.Namespace || name.Name != HigressConfigMapName { return } IngressLog.Infof("configmapMgr AddOrUpdateHigressConfig") higressConfigmap, err := c.HigressConfigLister.Get(HigressConfigMapName) if err != nil { IngressLog.Errorf("higress-config configmap is not found, namespace:%s, name:%s", name.Namespace, name.Name) return } if _, ok := higressConfigmap.Data[HigressConfigMapKey]; !ok { return } newHigressConfig := NewDefaultHigressConfig() if err = yaml.Unmarshal([]byte(higressConfigmap.Data[HigressConfigMapKey]), newHigressConfig); err != nil { IngressLog.Errorf("data:%s, convert to higress config error, error: %+v", higressConfigmap.Data[HigressConfigMapKey], err) return } for _, itemController := range c.ItemControllers { if itemErr := itemController.ValidHigressConfig(newHigressConfig); itemErr != nil { IngressLog.Errorf("configmap %s controller valid higress config error, error: %+v", itemController.GetName(), itemErr) return } } oldHigressConfig := c.GetHigressConfig() IngressLog.Infof("configmapMgr oldHigressConfig: %s", GetHigressConfigString(oldHigressConfig)) IngressLog.Infof("configmapMgr newHigressConfig: %s", GetHigressConfigString(newHigressConfig)) result, _ := c.CompareHigressConfig(oldHigressConfig, newHigressConfig) IngressLog.Infof("configmapMgr CompareHigressConfig reuslt is %d", result) if result == ResultNothing { return } if result == ResultDelete { newHigressConfig = NewDefaultHigressConfig() } if result == ResultReplace || result == ResultDelete { // Pass AddOrUpdateHigressConfig to itemControllers for _, itemController := range c.ItemControllers { IngressLog.Infof("configmap %s controller AddOrUpdateHigressConfig", itemController.GetName()) if itemErr := itemController.AddOrUpdateHigressConfig(name, oldHigressConfig, newHigressConfig); itemErr != nil { IngressLog.Errorf("configmap %s controller AddOrUpdateHigressConfig error, error: %+v", itemController.GetName(), itemErr) } } c.SetHigressConfig(newHigressConfig) IngressLog.Infof("configmapMgr higress config AddOrUpdate success, reuslt is %d", result) // Call updateConfig } } func (c *ConfigmapMgr) ConstructEnvoyFilters() ([]*config.Config, error) { configs := make([]*config.Config, 0) for _, itemController := range c.ItemControllers { IngressLog.Infof("controller %s ConstructEnvoyFilters", itemController.GetName()) if itemConfigs, err := itemController.ConstructEnvoyFilters(); err != nil { IngressLog.Errorf("controller %s ConstructEnvoyFilters error, error: %+v", itemController.GetName(), err) } else { configs = append(configs, itemConfigs...) } } return configs, nil } func (c *ConfigmapMgr) CompareHigressConfig(old *HigressConfig, new *HigressConfig) (Result, error) { if old == nil || new == nil { return ResultNothing, nil } if !reflect.DeepEqual(old, new) { return ResultReplace, nil } return ResultNothing, nil } func (c *ConfigmapMgr) initEventHandlers() error { itemEventHandler := func(name string) { c.XDSUpdater.ConfigUpdate(&model.PushRequest{ Full: true, ConfigsUpdated: map[model.ConfigKey]struct{}{{ Kind: kind.EnvoyFilter, Name: name, Namespace: c.Namespace, }: {}}, Reason: model.NewReasonStats(ModelUpdatedReason), }) } for _, itemController := range c.ItemControllers { itemController.RegisterItemEventHandler(itemEventHandler) } return nil }