You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2024/01/03 06:14:32 UTC

(dubbo-kubernetes) branch master updated: feat: cache selector

This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git


The following commit(s) were added to refs/heads/master by this push:
     new f669dba2 feat: cache selector
     new c3ad915b Merge pull request #133 from ev1lQuark/cache-selector
f669dba2 is described below

commit f669dba24dd6a56c9148e8955a2b7d34b3da0d48
Author: wangguan <wg...@gmail.com>
AuthorDate: Tue Jan 2 21:20:07 2024 +0800

    feat: cache selector
---
 pkg/admin/cache/registry/universal/cache.go        | 155 ++++++++++++---------
 .../{selector.go => application_selector.go}       |  27 +++-
 pkg/admin/cache/selector/multi_selector.go         | 124 +++++++++++++++++
 pkg/admin/cache/selector/selector.go               |  37 +++--
 .../selector/{selector.go => service_selector.go}  |  43 ++++--
 5 files changed, 296 insertions(+), 90 deletions(-)

diff --git a/pkg/admin/cache/registry/universal/cache.go b/pkg/admin/cache/registry/universal/cache.go
index 28eb4241..5208fb4f 100644
--- a/pkg/admin/cache/registry/universal/cache.go
+++ b/pkg/admin/cache/registry/universal/cache.go
@@ -194,26 +194,28 @@ func (uc *UniversalCache) GetInstancesWithSelector(namespace string, selector se
 
 	uc.providers.lock.RLock()
 	for application, serviceMap := range uc.providers.data {
-		if targetApplication, ok := selector.ApplicationOption(); ok && targetApplication != application {
+		if !selectByApplication(selector, application) {
 			continue
-		} else {
-			for serviceKey, instanceMap := range serviceMap {
-				for _, dubboModel := range instanceMap {
-					if _, ok := instanceSet[dubboModel.Ip+":"+dubboModel.Port]; ok {
-						continue
-					} else {
-						instanceSet[dubboModel.Ip+":"+dubboModel.Port] = struct{}{}
-						res = append(res, &cache.InstanceModel{
-							Application: &cache.ApplicationModel{Name: application},
-							Workload:    nil,
-							Name:        serviceKey + "#" + dubboModel.Ip + ":" + dubboModel.Port,
-							Ip:          dubboModel.Ip,
-							Port:        dubboModel.Port,
-							Status:      "",
-							Node:        "",
-							Labels:      nil,
-						})
-					}
+		}
+		for serviceKey, instanceMap := range serviceMap {
+			if !selectByServiceKey(selector, serviceKey) {
+				continue
+			}
+			for _, dubboModel := range instanceMap {
+				if _, ok := instanceSet[dubboModel.Ip+":"+dubboModel.Port]; ok {
+					continue
+				} else {
+					instanceSet[dubboModel.Ip+":"+dubboModel.Port] = struct{}{}
+					res = append(res, &cache.InstanceModel{
+						Application: &cache.ApplicationModel{Name: application},
+						Workload:    nil,
+						Name:        serviceKey + "#" + dubboModel.Ip + ":" + dubboModel.Port,
+						Ip:          dubboModel.Ip,
+						Port:        dubboModel.Port,
+						Status:      "",
+						Node:        "",
+						Labels:      nil,
+					})
 				}
 			}
 		}
@@ -222,26 +224,28 @@ func (uc *UniversalCache) GetInstancesWithSelector(namespace string, selector se
 
 	uc.consumers.lock.RLock()
 	for application, serviceMap := range uc.consumers.data {
-		if targetApplication, ok := selector.ApplicationOption(); ok && targetApplication != application {
+		if !selectByApplication(selector, application) {
 			continue
-		} else {
-			for serviceKey, instanceMap := range serviceMap {
-				for _, dubboModel := range instanceMap {
-					if _, ok := instanceSet[dubboModel.Ip+":"+dubboModel.Port]; ok {
-						continue
-					} else {
-						instanceSet[dubboModel.Ip+":"+dubboModel.Port] = struct{}{}
-						res = append(res, &cache.InstanceModel{
-							Application: &cache.ApplicationModel{Name: application},
-							Workload:    nil,
-							Name:        serviceKey + "#" + dubboModel.Ip + ":" + dubboModel.Port,
-							Ip:          dubboModel.Ip,
-							Port:        dubboModel.Port,
-							Status:      "",
-							Node:        "",
-							Labels:      nil,
-						})
-					}
+		}
+		for serviceKey, instanceMap := range serviceMap {
+			if !selectByServiceKey(selector, serviceKey) {
+				continue
+			}
+			for _, dubboModel := range instanceMap {
+				if _, ok := instanceSet[dubboModel.Ip+":"+dubboModel.Port]; ok {
+					continue
+				} else {
+					instanceSet[dubboModel.Ip+":"+dubboModel.Port] = struct{}{}
+					res = append(res, &cache.InstanceModel{
+						Application: &cache.ApplicationModel{Name: application},
+						Workload:    nil,
+						Name:        serviceKey + "#" + dubboModel.Ip + ":" + dubboModel.Port,
+						Ip:          dubboModel.Ip,
+						Port:        dubboModel.Port,
+						Status:      "",
+						Node:        "",
+						Labels:      nil,
+					})
 				}
 			}
 		}
@@ -294,41 +298,46 @@ func (uc *UniversalCache) GetServicesWithSelector(namespace string, selector sel
 
 	uc.providers.lock.RLock()
 	for application, serviceMap := range uc.providers.data {
-		if targetApplication, ok := selector.ApplicationOption(); ok && targetApplication != application {
+		if !selectByApplication(selector, application) {
 			continue
-		} else {
-			for serviceKey := range serviceMap {
-				res = append(res, &cache.ServiceModel{
-					Application: &cache.ApplicationModel{Name: application},
-					Category:    constant.ProviderSide,
-					Name:        util.GetInterface(serviceKey),
-					Labels:      nil,
-					ServiceKey:  serviceKey,
-					Group:       util.GetGroup(serviceKey),
-					Version:     util.GetVersion(serviceKey),
-				})
+		}
+		for serviceKey := range serviceMap {
+			if !selectByServiceKey(selector, serviceKey) {
+				continue
 			}
+			res = append(res, &cache.ServiceModel{
+				Application: &cache.ApplicationModel{Name: application},
+				Category:    constant.ProviderSide,
+				Name:        util.GetInterface(serviceKey),
+				Labels:      nil,
+				ServiceKey:  serviceKey,
+				Group:       util.GetGroup(serviceKey),
+				Version:     util.GetVersion(serviceKey),
+			})
 		}
 	}
 	uc.providers.lock.RUnlock()
 
 	uc.consumers.lock.RLock()
 	for application, serviceMap := range uc.consumers.data {
-		if targetApplication, ok := selector.ApplicationOption(); ok && targetApplication != application {
+		if !selectByApplication(selector, application) {
 			continue
-		} else {
-			for serviceKey := range serviceMap {
-				res = append(res, &cache.ServiceModel{
-					Application: &cache.ApplicationModel{Name: application},
-					Category:    constant.ConsumerSide,
-					Name:        util.GetInterface(serviceKey),
-					Labels:      nil,
-					ServiceKey:  serviceKey,
-					Group:       util.GetGroup(serviceKey),
-					Version:     util.GetVersion(serviceKey),
-				})
+		}
+		for serviceKey := range serviceMap {
+			if !selectByServiceKey(selector, serviceKey) {
+				continue
 			}
+			res = append(res, &cache.ServiceModel{
+				Application: &cache.ApplicationModel{Name: application},
+				Category:    constant.ConsumerSide,
+				Name:        util.GetInterface(serviceKey),
+				Labels:      nil,
+				ServiceKey:  serviceKey,
+				Group:       util.GetGroup(serviceKey),
+				Version:     util.GetVersion(serviceKey),
+			})
 		}
+
 	}
 	uc.consumers.lock.RUnlock()
 
@@ -489,3 +498,25 @@ func (m *DubboModel) ToggleRegistryType(deleteType string) {
 		m.RegistryType = constant.RegistryInstance
 	}
 }
+
+// selectByServiceKey is used to determine whether the serviceKey matches the selector
+func selectByServiceKey(selector selector.Selector, serviceKey string) bool {
+	if serviceNameOptions, ok := selector.ServiceNameOptions(); ok && !serviceNameOptions.Exist(util.GetInterface(serviceKey)) {
+		return false
+	}
+	if serviceGroupOptions, ok := selector.ServiceGroupOptions(); ok && !serviceGroupOptions.Exist(util.GetGroup(serviceKey)) {
+		return false
+	}
+	if serviceVersionOptions, ok := selector.ServiceVersionOptions(); ok && !serviceVersionOptions.Exist(util.GetVersion(serviceKey)) {
+		return false
+	}
+	return true
+}
+
+// selectByApplication is used to determine whether the application matches the selector
+func selectByApplication(selector selector.Selector, application string) bool {
+	if applicationOptions, ok := selector.ApplicationOptions(); ok && !applicationOptions.Exist(application) {
+		return false
+	}
+	return true
+}
diff --git a/pkg/admin/cache/selector/selector.go b/pkg/admin/cache/selector/application_selector.go
similarity index 70%
copy from pkg/admin/cache/selector/selector.go
copy to pkg/admin/cache/selector/application_selector.go
index 61271525..43f580bc 100644
--- a/pkg/admin/cache/selector/selector.go
+++ b/pkg/admin/cache/selector/application_selector.go
@@ -22,15 +22,16 @@ import (
 	"k8s.io/apimachinery/pkg/labels"
 )
 
-type Selector interface {
-	AsLabelsSelector() labels.Selector
-
-	ApplicationOption() (string, bool)
-}
 type ApplicationSelector struct {
 	Name string
 }
 
+func NewApplicationSelector(name string) *ApplicationSelector {
+	return &ApplicationSelector{
+		Name: name,
+	}
+}
+
 func (s *ApplicationSelector) AsLabelsSelector() labels.Selector {
 	selector := labels.Set{
 		constant.ApplicationLabel: s.Name,
@@ -38,6 +39,18 @@ func (s *ApplicationSelector) AsLabelsSelector() labels.Selector {
 	return selector.AsSelector()
 }
 
-func (s *ApplicationSelector) ApplicationOption() (string, bool) {
-	return s.Name, true
+func (s *ApplicationSelector) ApplicationOptions() (Options, bool) {
+	return newOptions(s.Name), true
+}
+
+func (s *ApplicationSelector) ServiceNameOptions() (Options, bool) {
+	return nil, false
+}
+
+func (s *ApplicationSelector) ServiceGroupOptions() (Options, bool) {
+	return nil, false
+}
+
+func (s *ApplicationSelector) ServiceVersionOptions() (Options, bool) {
+	return nil, false
 }
diff --git a/pkg/admin/cache/selector/multi_selector.go b/pkg/admin/cache/selector/multi_selector.go
new file mode 100644
index 00000000..2648461c
--- /dev/null
+++ b/pkg/admin/cache/selector/multi_selector.go
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 selector
+
+import (
+	"github.com/apache/dubbo-kubernetes/pkg/admin/constant"
+	"github.com/apache/dubbo-kubernetes/pkg/core/logger"
+	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/selection"
+)
+
+// MultiSelectors is an implement of Selector to combine multiple selectors, use NewMultiSelector to create it, and use Add to build it
+type MultiSelectors struct {
+	applicationNames []string
+	serviceNames     []string
+	serviceGroups    []string
+	serviceVersions  []string
+}
+
+func NewMultiSelector() *MultiSelectors {
+	return &MultiSelectors{
+		applicationNames: make([]string, 0),
+		serviceNames:     make([]string, 0),
+		serviceGroups:    make([]string, 0),
+		serviceVersions:  make([]string, 0),
+	}
+}
+
+func (s *MultiSelectors) Add(selector Selector) *MultiSelectors {
+	switch selector.(type) {
+	case *ApplicationSelector:
+		s.applicationNames = append(s.applicationNames, selector.(*ApplicationSelector).Name)
+	case *ServiceSelector:
+		s.serviceNames = append(s.serviceNames, selector.(*ServiceSelector).Name)
+		if selector.(*ServiceSelector).Group != "" {
+			s.serviceGroups = append(s.serviceGroups, selector.(*ServiceSelector).Group)
+		}
+		if selector.(*ServiceSelector).Version != "" {
+			s.serviceVersions = append(s.serviceVersions, selector.(*ServiceSelector).Version)
+		}
+	}
+	return s
+}
+
+func (s *MultiSelectors) AsLabelsSelector() labels.Selector {
+	requirements := make([]labels.Requirement, 0)
+
+	if len(s.applicationNames) > 0 {
+		req, err := labels.NewRequirement(constant.ApplicationLabel, selection.In, s.applicationNames)
+		if err != nil {
+			logger.Errorf("failed to create requirement for application selector: %v", err)
+		}
+		requirements = append(requirements, *req)
+	}
+
+	if len(s.serviceNames) > 0 {
+		req, err := labels.NewRequirement(constant.ServiceKeyLabel, selection.In, s.serviceNames)
+		if err != nil {
+			logger.Errorf("failed to create requirement for service selector: %v", err)
+		}
+		requirements = append(requirements, *req)
+	}
+
+	if len(s.serviceGroups) > 0 {
+		req, err := labels.NewRequirement(constant.GroupLabel, selection.In, s.serviceGroups)
+		if err != nil {
+			logger.Errorf("failed to create requirement for group selector: %v", err)
+		}
+		requirements = append(requirements, *req)
+	}
+
+	if len(s.serviceVersions) > 0 {
+		req, err := labels.NewRequirement(constant.VersionLabel, selection.In, s.serviceVersions)
+		if err != nil {
+			logger.Errorf("failed to create requirement for version selector: %v", err)
+		}
+		requirements = append(requirements, *req)
+	}
+
+	return labels.NewSelector().Add(requirements...)
+}
+
+func (s *MultiSelectors) ApplicationOptions() (Options, bool) {
+	if len(s.applicationNames) == 0 {
+		return nil, false
+	}
+	return newOptions(s.applicationNames...), true
+}
+
+func (s *MultiSelectors) ServiceNameOptions() (Options, bool) {
+	if len(s.serviceNames) == 0 {
+		return nil, false
+	}
+	return newOptions(s.serviceNames...), true
+}
+
+func (s *MultiSelectors) ServiceGroupOptions() (Options, bool) {
+	if len(s.serviceGroups) == 0 {
+		return nil, false
+	}
+	return newOptions(s.serviceGroups...), true
+}
+
+func (s *MultiSelectors) ServiceVersionOptions() (Options, bool) {
+	if len(s.serviceVersions) == 0 {
+		return nil, false
+	}
+	return newOptions(s.serviceVersions...), true
+}
diff --git a/pkg/admin/cache/selector/selector.go b/pkg/admin/cache/selector/selector.go
index 61271525..0e48bdaa 100644
--- a/pkg/admin/cache/selector/selector.go
+++ b/pkg/admin/cache/selector/selector.go
@@ -18,26 +18,41 @@
 package selector
 
 import (
-	"github.com/apache/dubbo-kubernetes/pkg/admin/constant"
 	"k8s.io/apimachinery/pkg/labels"
 )
 
+// Selector is an interface for selecting resources from cache
 type Selector interface {
 	AsLabelsSelector() labels.Selector
 
-	ApplicationOption() (string, bool)
+	ApplicationOptions() (Options, bool)
+	ServiceNameOptions() (Options, bool)
+	ServiceGroupOptions() (Options, bool)
+	ServiceVersionOptions() (Options, bool)
 }
-type ApplicationSelector struct {
-	Name string
+
+// Options is an interface to represent possible options of a selector at a certain level(e.g. application, service)
+type Options interface {
+	Len() int
+	Exist(str string) bool
 }
 
-func (s *ApplicationSelector) AsLabelsSelector() labels.Selector {
-	selector := labels.Set{
-		constant.ApplicationLabel: s.Name,
-	}
-	return selector.AsSelector()
+func newOptions(strs ...string) Options {
+	return options(strs)
+}
+
+// options is a slice of string, it implements Options interface
+type options []string
+
+func (o options) Len() int {
+	return len(o)
 }
 
-func (s *ApplicationSelector) ApplicationOption() (string, bool) {
-	return s.Name, true
+func (o options) Exist(str string) bool {
+	for _, s := range o {
+		if s == str {
+			return true
+		}
+	}
+	return false
 }
diff --git a/pkg/admin/cache/selector/selector.go b/pkg/admin/cache/selector/service_selector.go
similarity index 53%
copy from pkg/admin/cache/selector/selector.go
copy to pkg/admin/cache/selector/service_selector.go
index 61271525..fd534f83 100644
--- a/pkg/admin/cache/selector/selector.go
+++ b/pkg/admin/cache/selector/service_selector.go
@@ -22,22 +22,45 @@ import (
 	"k8s.io/apimachinery/pkg/labels"
 )
 
-type Selector interface {
-	AsLabelsSelector() labels.Selector
-
-	ApplicationOption() (string, bool)
+type ServiceSelector struct {
+	Name    string
+	Group   string
+	Version string
 }
-type ApplicationSelector struct {
-	Name string
+
+func NewServiceSelector(name, group, version string) *ServiceSelector {
+	return &ServiceSelector{
+		Name:    name,
+		Group:   group,
+		Version: version,
+	}
 }
 
-func (s *ApplicationSelector) AsLabelsSelector() labels.Selector {
+func (s *ServiceSelector) AsLabelsSelector() labels.Selector {
 	selector := labels.Set{
-		constant.ApplicationLabel: s.Name,
+		constant.ServiceKeyLabel: s.Name,
+	}
+	if s.Group != "" {
+		selector[constant.GroupLabel] = s.Group
+	}
+	if s.Version != "" {
+		selector[constant.VersionLabel] = s.Version
 	}
 	return selector.AsSelector()
 }
 
-func (s *ApplicationSelector) ApplicationOption() (string, bool) {
-	return s.Name, true
+func (s *ServiceSelector) ApplicationOptions() (Options, bool) {
+	return nil, false
+}
+
+func (s *ServiceSelector) ServiceNameOptions() (Options, bool) {
+	return newOptions(s.Name), true
+}
+
+func (s *ServiceSelector) ServiceGroupOptions() (Options, bool) {
+	return newOptions(s.Group), true
+}
+
+func (s *ServiceSelector) ServiceVersionOptions() (Options, bool) {
+	return newOptions(s.Version), true
 }