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 }