github.com/polarismesh/polaris@v1.17.8/cache/service/service_query.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package service
    19  
    20  import (
    21  	"sort"
    22  	"strings"
    23  
    24  	types "github.com/polarismesh/polaris/cache/api"
    25  	"github.com/polarismesh/polaris/common/model"
    26  	"github.com/polarismesh/polaris/common/utils"
    27  	"github.com/polarismesh/polaris/store"
    28  )
    29  
    30  // forceUpdate 更新配置
    31  func (sc *serviceCache) forceUpdate() error {
    32  	var err error
    33  	if err = sc.Update(); err != nil {
    34  		return err
    35  	}
    36  	if err = sc.instCache.Update(); err != nil {
    37  		return err
    38  	}
    39  	return nil
    40  }
    41  
    42  // GetServicesByFilter 通过filter在缓存中进行服务过滤
    43  func (sc *serviceCache) GetServicesByFilter(serviceFilters *types.ServiceArgs,
    44  	instanceFilters *store.InstanceArgs, offset, limit uint32) (uint32, []*model.EnhancedService, error) {
    45  
    46  	if err := sc.forceUpdate(); err != nil {
    47  		return 0, nil, err
    48  	}
    49  
    50  	var amount uint32
    51  	var err error
    52  	var services []*model.Service
    53  
    54  	// 如果具有名字条件,并且不是模糊查询,直接获取对应命名空间下面的服务,并检查是否匹配所有条件
    55  	if serviceFilters.Name != "" && !serviceFilters.WildName && !serviceFilters.WildNamespace {
    56  		amount, services, err = sc.getServicesFromCacheByName(serviceFilters, instanceFilters, offset, limit)
    57  	} else {
    58  		amount, services, err = sc.getServicesByIteratingCache(serviceFilters, instanceFilters, offset, limit)
    59  	}
    60  	var enhancedServices []*model.EnhancedService
    61  	if amount > 0 {
    62  		enhancedServices = make([]*model.EnhancedService, 0, len(services))
    63  		for _, service := range services {
    64  			count := sc.instCache.GetInstancesCountByServiceID(service.ID)
    65  			enhancedService := &model.EnhancedService{
    66  				Service:              service,
    67  				TotalInstanceCount:   count.TotalInstanceCount,
    68  				HealthyInstanceCount: count.HealthyInstanceCount,
    69  			}
    70  			enhancedServices = append(enhancedServices, enhancedService)
    71  		}
    72  	}
    73  	return amount, enhancedServices, err
    74  }
    75  
    76  func hasInstanceFilter(instanceFilters *store.InstanceArgs) bool {
    77  	if instanceFilters == nil || (len(instanceFilters.Hosts) == 0 && len(instanceFilters.Ports) == 0 &&
    78  		len(instanceFilters.Meta) == 0) {
    79  		return false
    80  	}
    81  	return true
    82  }
    83  
    84  func (sc *serviceCache) matchInstances(instances []*model.Instance, instanceFilters *store.InstanceArgs) bool {
    85  	if len(instances) == 0 {
    86  		return false
    87  	}
    88  	var matchedHost bool
    89  	if len(instanceFilters.Hosts) > 0 {
    90  		var hosts = make(map[string]bool, len(instanceFilters.Hosts))
    91  		for _, host := range instanceFilters.Hosts {
    92  			hosts[host] = true
    93  		}
    94  		for _, instance := range instances {
    95  			if _, ok := hosts[instance.Proto.GetHost().GetValue()]; ok {
    96  				matchedHost = true
    97  				break
    98  			}
    99  		}
   100  	} else {
   101  		matchedHost = true
   102  	}
   103  
   104  	matchedMeta := false
   105  	if len(instanceFilters.Meta) > 0 {
   106  		for _, instance := range instances {
   107  			instanceMetaMap := instance.Metadata()
   108  			instanceMatched := true
   109  			for key, metaPattern := range instanceFilters.Meta {
   110  				if instanceMetaValue, ok := instanceMetaMap[key]; !ok ||
   111  					utils.IsWildNotMatch(instanceMetaValue, metaPattern) {
   112  					instanceMatched = false
   113  					break
   114  				}
   115  			}
   116  			if instanceMatched {
   117  				matchedMeta = true
   118  				break
   119  			}
   120  		}
   121  	} else {
   122  		matchedMeta = true
   123  	}
   124  
   125  	var matchedPort bool
   126  	if len(instanceFilters.Ports) > 0 {
   127  		var ports = make(map[uint32]bool, len(instanceFilters.Ports))
   128  		for _, port := range instanceFilters.Ports {
   129  			ports[port] = true
   130  		}
   131  		for _, instance := range instances {
   132  			if _, ok := ports[instance.Proto.GetPort().GetValue()]; ok {
   133  				matchedPort = true
   134  				break
   135  			}
   136  		}
   137  	} else {
   138  		matchedPort = true
   139  	}
   140  	return matchedHost && matchedPort && matchedMeta
   141  }
   142  
   143  // GetAllNamespaces 返回所有的命名空间
   144  func (sc *serviceCache) GetAllNamespaces() []string {
   145  	var res []string
   146  	sc.names.Range(func(k string, v *utils.SyncMap[string, *model.Service]) bool {
   147  		res = append(res, k)
   148  		return true
   149  	})
   150  	return res
   151  }
   152  
   153  // 通过具体的名字来进行查询服务
   154  func (sc *serviceCache) getServicesFromCacheByName(svcArgs *types.ServiceArgs, instArgs *store.InstanceArgs,
   155  	offset, limit uint32) (uint32, []*model.Service, error) {
   156  	var res []*model.Service
   157  	if svcArgs.Namespace != "" {
   158  		svc := sc.GetServiceByName(svcArgs.Name, svcArgs.Namespace)
   159  		if svc != nil && !svc.IsAlias() && matchService(svc, svcArgs.Filter, svcArgs.Metadata, false, false) &&
   160  			sc.matchInstance(svc, instArgs) {
   161  			res = append(res, svc)
   162  		}
   163  	} else {
   164  		for _, namespace := range sc.GetAllNamespaces() {
   165  			svc := sc.GetServiceByName(svcArgs.Name, namespace)
   166  			if svc != nil && !svc.IsAlias() && matchService(svc, svcArgs.Filter, svcArgs.Metadata, false, false) &&
   167  				sc.matchInstance(svc, instArgs) {
   168  				res = append(res, svc)
   169  			}
   170  		}
   171  	}
   172  	amount, services := sortBeforeTrim(res, offset, limit)
   173  	return amount, services, nil
   174  }
   175  
   176  func sortBeforeTrim(services []*model.Service, offset, limit uint32) (uint32, []*model.Service) {
   177  	// 所有符合条件的服务数量
   178  	amount := uint32(len(services))
   179  	// 判断 offset 和 limit 是否允许返回对应的服务
   180  	if offset >= amount || limit == 0 {
   181  		return amount, nil
   182  	}
   183  	// 将服务按照修改时间和 id 进行排序
   184  	sort.Slice(services, func(i, j int) bool {
   185  		if services[i].Mtime > services[j].Mtime {
   186  			return true
   187  		}
   188  
   189  		if services[i].Mtime < services[j].Mtime {
   190  			return false
   191  		}
   192  
   193  		return strings.Compare(services[i].ID, services[j].ID) < 0
   194  	})
   195  
   196  	endIdx := offset + limit
   197  	if endIdx > amount {
   198  		endIdx = amount
   199  	}
   200  	return amount, services[offset:endIdx]
   201  }
   202  
   203  // matchService 根据查询条件比较一个服务是否符合条件
   204  func matchService(svc *model.Service, svcFilter map[string]string, metaFilter map[string]string,
   205  	isWildName, isWildNamespace bool) bool {
   206  	if !matchServiceFilter(svc, svcFilter, isWildName, isWildNamespace) {
   207  		return false
   208  	}
   209  	return matchMetadata(svc, metaFilter)
   210  }
   211  
   212  // matchServiceFilter 查询一个服务是否满足服务相关字段的条件
   213  func matchServiceFilter(svc *model.Service, svcFilter map[string]string, isWildName, isWildNamespace bool) bool {
   214  	var value string
   215  	var exist bool
   216  	if isWildName {
   217  		if value, exist = svcFilter["name"]; exist {
   218  			if !utils.IsWildMatchIgnoreCase(svc.Name, value) {
   219  				return false
   220  			}
   221  		}
   222  	}
   223  	if isWildNamespace {
   224  		if value, exist = svcFilter["namespace"]; exist {
   225  			if !utils.IsWildMatchIgnoreCase(svc.Namespace, value) {
   226  				return false
   227  			}
   228  		}
   229  	}
   230  
   231  	if value, exist = svcFilter["business"]; exist &&
   232  		!strings.Contains(strings.ToLower(svc.Business), strings.ToLower(value)) {
   233  		return false
   234  	}
   235  	if value, exist = svcFilter["department"]; exist && svc.Department != value {
   236  		return false
   237  	}
   238  	if value, exist = svcFilter["cmdb_mod1"]; exist && svc.CmdbMod1 != value {
   239  		return false
   240  	}
   241  	if value, exist = svcFilter["cmdb_mod2"]; exist && svc.CmdbMod2 != value {
   242  		return false
   243  	}
   244  	if value, exist = svcFilter["cmdb_mod3"]; exist && svc.CmdbMod3 != value {
   245  		return false
   246  	}
   247  	if value, exist = svcFilter["platform_id"]; exist && svc.PlatformID != value {
   248  		return false
   249  	}
   250  	if value, exist = svcFilter["owner"]; exist && !strings.Contains(svc.Owner, value) {
   251  		return false
   252  	}
   253  	return true
   254  }
   255  
   256  // matchMetadata 检查一个服务是否包含有相关的元数据
   257  func matchMetadata(svc *model.Service, metaFilter map[string]string) bool {
   258  	for k, v := range metaFilter {
   259  		value, ok := svc.Meta[k]
   260  		if !ok || value != v {
   261  			return false
   262  		}
   263  	}
   264  	return true
   265  }
   266  
   267  func (sc *serviceCache) matchInstance(svc *model.Service, instArgs *store.InstanceArgs) bool {
   268  	if hasInstanceFilter(instArgs) {
   269  		instances := sc.instCache.GetInstancesByServiceID(svc.ID)
   270  		if !sc.matchInstances(instances, instArgs) {
   271  			return false
   272  		}
   273  	}
   274  	return true
   275  }
   276  
   277  // getServicesByIteratingCache 通过遍历缓存中的服务
   278  func (sc *serviceCache) getServicesByIteratingCache(
   279  	svcArgs *types.ServiceArgs, instArgs *store.InstanceArgs, offset, limit uint32) (uint32, []*model.Service, error) {
   280  	var res []*model.Service
   281  	var process = func(svc *model.Service) {
   282  		// 如果是别名,直接略过
   283  		if svc.IsAlias() {
   284  			return
   285  		}
   286  		if !svcArgs.EmptyCondition {
   287  			if !matchService(svc, svcArgs.Filter, svcArgs.Metadata, svcArgs.WildName, svcArgs.WildNamespace) {
   288  				return
   289  			}
   290  		}
   291  		if !sc.matchInstance(svc, instArgs) {
   292  			return
   293  		}
   294  		res = append(res, svc)
   295  	}
   296  	if len(svcArgs.Namespace) > 0 && !svcArgs.WildNamespace {
   297  		// 从命名空间来找
   298  		spaces, ok := sc.names.Load(svcArgs.Namespace)
   299  		if !ok {
   300  			return 0, nil, nil
   301  		}
   302  		spaces.Range(func(key string, value *model.Service) bool {
   303  			process(value)
   304  			return true
   305  		})
   306  	} else {
   307  		// 直接名字匹配
   308  		_ = sc.IteratorServices(func(key string, svc *model.Service) (bool, error) {
   309  			process(svc)
   310  			return true, nil
   311  		})
   312  	}
   313  	amount, services := sortBeforeTrim(res, offset, limit)
   314  	return amount, services, nil
   315  }