github.com/polarismesh/polaris@v1.17.8/cache/service/instance_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 "encoding/json" 22 "sort" 23 "strconv" 24 "strings" 25 26 "go.uber.org/zap" 27 28 types "github.com/polarismesh/polaris/cache/api" 29 "github.com/polarismesh/polaris/common/model" 30 "github.com/polarismesh/polaris/common/utils" 31 ) 32 33 // InstanceSearchArgs . 34 type InstanceSearchArgs struct { 35 SvcName *string 36 SvcNs *string 37 InstanceID *string 38 Hosts map[string]struct{} 39 Port *uint32 40 Protocol *string 41 Version *string 42 Region *string 43 Zone *string 44 Campus *string 45 Weight *uint32 46 HealthStatus *bool 47 Isolate *bool 48 MetaFilter map[string]string 49 } 50 51 func (args *InstanceSearchArgs) String() string { 52 //nolint: errchkjson 53 data, _ := json.Marshal(args) 54 return string(data) 55 } 56 57 func parseInstanceSearchArgs(filter, metaFilter map[string]string) *InstanceSearchArgs { 58 args := &InstanceSearchArgs{ 59 MetaFilter: metaFilter, 60 } 61 62 if searchSvcName, hasSvc := filter["name"]; hasSvc { 63 args.SvcName = &searchSvcName 64 } 65 if searchNamespace, hasNamespace := filter["namespace"]; hasNamespace { 66 args.SvcNs = &searchNamespace 67 } 68 if id, hasId := filter["id"]; hasId { 69 args.InstanceID = &id 70 } 71 if protocol, hasProtocol := filter["protocol"]; hasProtocol { 72 args.Protocol = &protocol 73 } 74 if version, hasVersion := filter["version"]; hasVersion { 75 args.Version = &version 76 } 77 if region, hasRegion := filter["cmdb_region"]; hasRegion { 78 args.Region = ®ion 79 } 80 if campus, hasIdc := filter["cmdb_idc"]; hasIdc { 81 args.Campus = &campus 82 } 83 if zone, hasZone := filter["cmdb_zone"]; hasZone { 84 args.Zone = &zone 85 } 86 87 if hosts, hasHosts := filter["host"]; hasHosts { 88 hostMap := map[string]struct{}{} 89 hostItems := strings.Split(hosts, ",") 90 for i := range hostItems { 91 hostVal := strings.TrimSpace(hostItems[i]) 92 if len(hostVal) == 0 { 93 continue 94 } 95 hostMap[hostVal] = struct{}{} 96 } 97 args.Hosts = hostMap 98 } 99 100 if portStr, ok := filter["port"]; ok { 101 if v, err := strconv.ParseUint(portStr, 10, 64); err == nil { 102 port := uint32(v) 103 args.Port = &port 104 } 105 } 106 if weightStr, ok := filter["weight"]; ok { 107 if v, err := strconv.ParseUint(weightStr, 10, 64); err == nil { 108 weight := uint32(v) 109 args.Weight = &weight 110 } 111 } 112 if isolateStr, ok := filter["isolate"]; ok { 113 if v, err := strconv.ParseBool(isolateStr); err == nil { 114 isolate := v 115 args.Isolate = &isolate 116 } 117 } 118 if healthStatusStr, ok := filter["health_status"]; ok { 119 if v, err := strconv.ParseBool(healthStatusStr); err == nil { 120 healthStatus := v 121 args.HealthStatus = &healthStatus 122 } 123 } 124 if healthyStr, ok := filter["healthy"]; ok { 125 if v, err := strconv.ParseBool(healthyStr); err == nil { 126 healthStatus := v 127 args.HealthStatus = &healthStatus 128 } 129 } 130 return args 131 } 132 133 // forceQueryUpdate 为了确保读取的数据是最新的,这里需要做一个强制 update 的动作进行数据读取处理 134 func (ic *instanceCache) forceQueryUpdate() error { 135 err, shared := ic.singleUpdate() 136 // shared == true,表示当前已经有正在 update 执行的任务,这个任务不一定能够读取到最新的数据 137 // 为了避免读取到脏数据,在发起一次 singleUpdate 138 if shared { 139 naminglog.Debug("[Server][Instances][Query] force query update second") 140 err, _ = ic.singleUpdate() 141 } 142 return err 143 } 144 145 func (ic *instanceCache) QueryInstances(filter, metaFilter map[string]string, 146 offset, limit uint32) (uint32, []*model.Instance, error) { 147 if err := ic.forceQueryUpdate(); err != nil { 148 return 0, nil, err 149 } 150 var ( 151 tempInstances = make([]*model.Instance, 0, 32) 152 args = parseInstanceSearchArgs(filter, metaFilter) 153 ) 154 naminglog.Info("[Server][Instances][Query] instances filter parameters", zap.String("args", args.String())) 155 156 svcCache, _ := ic.BaseCache.CacheMgr.GetCacher(types.CacheService).(*serviceCache) 157 _ = ic.IteratorInstances(func(key string, value *model.Instance) (bool, error) { 158 svc := svcCache.GetOrLoadServiceByID(value.ServiceID) 159 if svc == nil { 160 return true, nil 161 } 162 if args.SvcName != nil && !utils.IsWildMatch(svc.Name, *args.SvcName) { 163 return true, nil 164 } 165 if args.SvcNs != nil && !utils.IsWildMatch(svc.Namespace, *args.SvcNs) { 166 return true, nil 167 } 168 if args.InstanceID != nil && !utils.IsWildMatch(value.Proto.GetId().GetValue(), *args.InstanceID) { 169 return true, nil 170 } 171 if len(args.Hosts) != 0 { 172 if _, ok := args.Hosts[value.Proto.GetHost().GetValue()]; !ok { 173 return true, nil 174 } 175 } 176 if args.Port != nil && value.Proto.GetPort().GetValue() != *args.Port { 177 return true, nil 178 } 179 if args.Isolate != nil && value.Proto.GetIsolate().GetValue() != *args.Isolate { 180 return true, nil 181 } 182 if args.HealthStatus != nil && value.Proto.GetHealthy().GetValue() != *args.HealthStatus { 183 return true, nil 184 } 185 if args.Weight != nil && value.Proto.GetWeight().GetValue() != *args.Weight { 186 return true, nil 187 } 188 if args.Region != nil && value.Proto.GetLocation().GetRegion().GetValue() != *args.Region { 189 return true, nil 190 } 191 if args.Zone != nil && value.Proto.GetLocation().GetZone().GetValue() != *args.Zone { 192 return true, nil 193 } 194 if args.Campus != nil && value.Proto.GetLocation().GetCampus().GetValue() != *args.Campus { 195 return true, nil 196 } 197 if args.Protocol != nil && value.Proto.GetProtocol().GetValue() != *args.Protocol { 198 return true, nil 199 } 200 if args.Version != nil && value.Proto.GetVersion().GetValue() != *args.Version { 201 return true, nil 202 } 203 if len(metaFilter) > 0 { 204 for k, v := range metaFilter { 205 insV, ok := value.Proto.GetMetadata()[k] 206 if !ok || insV != v { 207 return true, nil 208 } 209 } 210 } 211 tempInstances = append(tempInstances, value) 212 return true, nil 213 }) 214 215 total, ret := ic.doPage(tempInstances, offset, limit) 216 return total, ret, nil 217 } 218 219 func (ic *instanceCache) doPage(ins []*model.Instance, offset, limit uint32) (uint32, []*model.Instance) { 220 total := uint32(len(ins)) 221 if offset > total { 222 return total, []*model.Instance{} 223 } 224 if offset+limit > total { 225 return total, ins[offset:] 226 } 227 228 sort.Slice(ins, func(i, j int) bool { 229 return ins[i].ModifyTime.After(ins[j].ModifyTime) 230 }) 231 232 return total, ins[offset : offset+limit] 233 }