github.com/polarismesh/polaris@v1.17.8/service/instance.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 "context" 22 "errors" 23 "fmt" 24 "time" 25 26 "github.com/gogo/protobuf/jsonpb" 27 "github.com/golang/protobuf/ptypes/wrappers" 28 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 29 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 30 "go.uber.org/zap" 31 "google.golang.org/protobuf/types/known/wrapperspb" 32 33 api "github.com/polarismesh/polaris/common/api/v1" 34 "github.com/polarismesh/polaris/common/eventhub" 35 "github.com/polarismesh/polaris/common/model" 36 commonstore "github.com/polarismesh/polaris/common/store" 37 "github.com/polarismesh/polaris/common/utils" 38 ) 39 40 var ( 41 // InstanceFilterAttributes 查询实例支持的过滤字段 42 InstanceFilterAttributes = map[string]bool{ 43 "id": true, // 实例ID 44 "service": true, // 服务name 45 "namespace": true, // 服务namespace 46 "host": true, 47 "port": true, 48 "keys": true, 49 "values": true, 50 "protocol": true, 51 "version": true, 52 "health_status": true, 53 "healthy": true, // health_status, healthy都有,以healthy为准 54 "isolate": true, 55 "weight": true, 56 "logic_set": true, 57 "cmdb_region": true, 58 "cmdb_zone": true, 59 "cmdb_idc": true, 60 "priority": true, 61 "offset": true, 62 "limit": true, 63 } 64 // InsFilter2toreAttr 查询字段转为存储层的属性值,映射表 65 InsFilter2toreAttr = map[string]string{ 66 "service": "name", 67 "healthy": "health_status", 68 } 69 // NotInsFilterAttr 不属于 instance 表属性的字段 70 NotInsFilterAttr = map[string]bool{ 71 "keys": true, 72 "values": true, 73 } 74 ) 75 76 // CreateInstances 批量创建服务实例 77 func (s *Server) CreateInstances(ctx context.Context, reqs []*apiservice.Instance) *apiservice.BatchWriteResponse { 78 if checkError := checkBatchInstance(reqs); checkError != nil { 79 return checkError 80 } 81 82 return batchOperateInstances(ctx, reqs, s.CreateInstance) 83 } 84 85 // CreateInstance create a single service instance 86 func (s *Server) CreateInstance(ctx context.Context, req *apiservice.Instance) *apiservice.Response { 87 rid := utils.ParseRequestID(ctx) 88 pid := utils.ParsePlatformID(ctx) 89 start := time.Now() 90 instanceID, checkError := checkCreateInstance(req) 91 if checkError != nil { 92 return checkError 93 } 94 // Restricted Instance frequently registered 95 if ok := s.allowInstanceAccess(instanceID); !ok { 96 log.Error("create instance not allowed to access: exceed ratelimit", 97 utils.ZapRequestID(rid), utils.ZapPlatformID(pid), utils.ZapInstanceID(instanceID)) 98 return api.NewInstanceResponse(apimodel.Code_InstanceTooManyRequests, req) 99 } 100 101 // Prevent pollution api.Instance struct, copy and fill token 102 ins := *req 103 ins.ServiceToken = utils.NewStringValue(parseInstanceReqToken(ctx, req)) 104 ins.Id = utils.NewStringValue(instanceID) 105 data, resp := s.createInstance(ctx, req, &ins) 106 if resp != nil { 107 return resp 108 } 109 110 msg := fmt.Sprintf("create instance: id=%v, namespace=%v, service=%v, host=%v, port=%v", 111 ins.GetId().GetValue(), req.GetNamespace().GetValue(), req.GetService().GetValue(), 112 req.GetHost().GetValue(), req.GetPort().GetValue()) 113 log.Info(msg, utils.ZapRequestID(rid), utils.ZapPlatformID(pid), zap.Duration("cost", time.Since(start))) 114 svc := &model.Service{ 115 Name: req.GetService().GetValue(), 116 Namespace: req.GetNamespace().GetValue(), 117 } 118 instanceProto := data.Proto 119 event := &model.InstanceEvent{ 120 Id: instanceID, 121 Namespace: svc.Namespace, 122 Service: svc.Name, 123 Instance: instanceProto, 124 EType: model.EventInstanceOnline, 125 CreateTime: time.Time{}, 126 } 127 event.InjectMetadata(ctx) 128 s.sendDiscoverEvent(*event) 129 s.RecordHistory(ctx, instanceRecordEntry(ctx, req, svc, data, model.OCreate)) 130 out := &apiservice.Instance{ 131 Id: ins.GetId(), 132 Service: &wrappers.StringValue{Value: svc.Name}, 133 Namespace: &wrappers.StringValue{Value: svc.Namespace}, 134 VpcId: instanceProto.GetVpcId(), 135 Host: instanceProto.GetHost(), 136 Port: instanceProto.GetPort(), 137 } 138 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, out) 139 } 140 141 // createInstance store operate 142 func (s *Server) createInstance(ctx context.Context, req *apiservice.Instance, ins *apiservice.Instance) ( 143 *model.Instance, *apiservice.Response) { 144 // create service if absent 145 svcId, errResp := s.createWrapServiceIfAbsent(ctx, req) 146 if errResp != nil { 147 log.Errorf("[Instance] create service if absent fail : %+v, req : %+v", errResp.String(), req) 148 return nil, errResp 149 } 150 if len(svcId) == 0 { 151 log.Errorf("[Instance] create service if absent return service id is empty : %+v", req) 152 return nil, api.NewResponseWithMsg(apimodel.Code_BadRequest, "service id is empty") 153 } 154 155 // fill instance location info 156 s.packCmdb(ins) 157 158 if namingServer.bc == nil || !namingServer.bc.CreateInstanceOpen() { 159 return s.serialCreateInstance(ctx, svcId, req, ins) // 单个同步 160 } 161 return s.asyncCreateInstance(ctx, svcId, req, ins) // 批量异步 162 } 163 164 // asyncCreateInstance 异步新建实例 165 // 底层函数会合并create请求,增加并发创建的吞吐 166 // req 原始请求 167 // ins 包含了req数据与instanceID,serviceToken 168 func (s *Server) asyncCreateInstance( 169 ctx context.Context, svcId string, req *apiservice.Instance, ins *apiservice.Instance) ( 170 *model.Instance, *apiservice.Response) { 171 allowAsyncRegis, _ := ctx.Value(utils.ContextOpenAsyncRegis).(bool) 172 future := s.bc.AsyncCreateInstance(svcId, ins, !allowAsyncRegis) 173 174 if err := future.Wait(); err != nil { 175 if future.Code() == apimodel.Code_ExistedResource { 176 req.Id = utils.NewStringValue(ins.GetId().GetValue()) 177 } 178 return nil, api.NewInstanceResponse(future.Code(), req) 179 } 180 181 return model.CreateInstanceModel(svcId, req), nil 182 } 183 184 // 同步串行创建实例 185 // req为原始的请求体 186 // ins包括了req的内容,并且填充了instanceID与serviceToken 187 func (s *Server) serialCreateInstance( 188 ctx context.Context, svcId string, req *apiservice.Instance, ins *apiservice.Instance) ( 189 *model.Instance, *apiservice.Response) { 190 rid := utils.ParseRequestID(ctx) 191 pid := utils.ParsePlatformID(ctx) 192 193 instance, err := s.storage.GetInstance(ins.GetId().GetValue()) 194 if err != nil { 195 log.Error("[Instance] get instance from store", 196 utils.ZapRequestID(rid), utils.ZapPlatformID(pid), zap.Error(err)) 197 return nil, api.NewInstanceResponse(commonstore.StoreCode2APICode(err), req) 198 } 199 // 如果存在,则替换实例的属性数据,但是需要保留用户设置的隔离状态,以免出现关键状态丢失 200 if instance != nil && ins.Isolate == nil { 201 ins.Isolate = instance.Proto.Isolate 202 } 203 // 直接同步创建服务实例 204 data := model.CreateInstanceModel(svcId, ins) 205 if err := s.storage.AddInstance(data); err != nil { 206 log.Error(err.Error(), utils.ZapRequestID(rid), utils.ZapPlatformID(pid)) 207 return nil, wrapperInstanceStoreResponse(req, err) 208 } 209 210 return data, nil 211 } 212 213 // DeleteInstances 批量删除服务实例 214 func (s *Server) DeleteInstances(ctx context.Context, req []*apiservice.Instance) *apiservice.BatchWriteResponse { 215 if checkError := checkBatchInstance(req); checkError != nil { 216 return checkError 217 } 218 219 return batchOperateInstances(ctx, req, s.DeleteInstance) 220 } 221 222 // DeleteInstance 删除单个服务实例 223 func (s *Server) DeleteInstance(ctx context.Context, req *apiservice.Instance) *apiservice.Response { 224 rid := utils.ParseRequestID(ctx) 225 pid := utils.ParsePlatformID(ctx) 226 227 // 参数检查 228 instanceID, checkError := checkReviseInstance(req) 229 if checkError != nil { 230 return checkError 231 } 232 // 限制instance频繁反注册 233 if ok := s.allowInstanceAccess(instanceID); !ok { 234 log.Error("delete instance is not allow access", utils.ZapRequestID(rid), utils.ZapPlatformID(pid)) 235 return api.NewInstanceResponse(apimodel.Code_InstanceTooManyRequests, req) 236 } 237 238 ins := *req // 防止污染外部的req 239 ins.Id = utils.NewStringValue(instanceID) 240 ins.ServiceToken = utils.NewStringValue(parseInstanceReqToken(ctx, req)) 241 return s.deleteInstance(ctx, req, &ins) 242 } 243 244 // 删除实例的store操作 245 // req 原始请求 246 // ins 填充了instanceID与serviceToken 247 func (s *Server) deleteInstance( 248 ctx context.Context, req *apiservice.Instance, ins *apiservice.Instance) *apiservice.Response { 249 if s.bc == nil || !s.bc.DeleteInstanceOpen() { 250 return s.serialDeleteInstance(ctx, req, ins) 251 } 252 253 return s.asyncDeleteInstance(ctx, req, ins) 254 } 255 256 // 串行删除实例 257 // 返回实例所属的服务和resp 258 func (s *Server) serialDeleteInstance( 259 ctx context.Context, req *apiservice.Instance, ins *apiservice.Instance) *apiservice.Response { 260 start := time.Now() 261 // 检查服务实例是否存在 262 rid := utils.ParseRequestID(ctx) 263 pid := utils.ParsePlatformID(ctx) 264 instance, err := s.storage.GetInstance(ins.GetId().GetValue()) 265 if err != nil { 266 log.Error(err.Error(), utils.ZapRequestID(rid)) 267 return api.NewInstanceResponse(commonstore.StoreCode2APICode(err), req) 268 } 269 if instance == nil { 270 // 实例不存在,则返回成功 271 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, req) 272 } 273 // 鉴权 274 service, resp := s.instanceAuth(ctx, req, instance.ServiceID) 275 if resp != nil { 276 return resp 277 } 278 279 // 存储层操作 280 if err := s.storage.DeleteInstance(instance.ID()); err != nil { 281 log.Error(err.Error(), utils.ZapRequestID(rid), utils.ZapPlatformID(pid)) 282 return wrapperInstanceStoreResponse(req, err) 283 } 284 285 msg := fmt.Sprintf("delete instance: id=%v, namespace=%v, service=%v, host=%v, port=%v", 286 instance.ID(), service.Namespace, service.Name, instance.Host(), instance.Port()) 287 log.Info(msg, utils.ZapRequestID(rid), utils.ZapPlatformID(pid), zap.Duration("cost", time.Since(start))) 288 s.RecordHistory(ctx, instanceRecordEntry(ctx, req, service, instance, model.ODelete)) 289 event := &model.InstanceEvent{ 290 Id: instance.ID(), 291 Namespace: service.Namespace, 292 Service: service.Name, 293 Instance: instance.Proto, 294 EType: model.EventInstanceOffline, 295 CreateTime: time.Time{}, 296 } 297 event.InjectMetadata(ctx) 298 s.sendDiscoverEvent(*event) 299 300 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, req) 301 } 302 303 // 异步删除实例 304 // 返回实例所属的服务和resp 305 func (s *Server) asyncDeleteInstance( 306 ctx context.Context, req *apiservice.Instance, ins *apiservice.Instance) *apiservice.Response { 307 start := time.Now() 308 rid := utils.ParseRequestID(ctx) 309 pid := utils.ParsePlatformID(ctx) 310 allowAsyncRegis, _ := ctx.Value(utils.ContextOpenAsyncRegis).(bool) 311 future := s.bc.AsyncDeleteInstance(ins, !allowAsyncRegis) 312 if err := future.Wait(); err != nil { 313 // 如果发现不存在资源,意味着实例已经被删除,直接返回成功 314 if future.Code() == apimodel.Code_NotFoundResource { 315 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, req) 316 } 317 log.Error(err.Error(), utils.ZapRequestID(rid), utils.ZapPlatformID(pid)) 318 return api.NewInstanceResponse(future.Code(), req) 319 } 320 instance := future.Instance() 321 322 // 打印本地日志与操作记录 323 msg := fmt.Sprintf("delete instance: id=%v, namespace=%v, service=%v, host=%v, port=%v", 324 instance.ID(), instance.Namespace(), instance.Service(), instance.Host(), instance.Port()) 325 log.Info(msg, utils.ZapRequestID(rid), utils.ZapPlatformID(pid), zap.Duration("cost", time.Since(start))) 326 service := &model.Service{Name: instance.Service(), Namespace: instance.Namespace()} 327 s.RecordHistory(ctx, instanceRecordEntry(ctx, req, service, instance, model.ODelete)) 328 event := &model.InstanceEvent{ 329 Id: instance.ID(), 330 Namespace: service.Namespace, 331 Service: service.Name, 332 Instance: instance.Proto, 333 EType: model.EventInstanceOffline, 334 CreateTime: time.Time{}, 335 } 336 event.InjectMetadata(ctx) 337 s.sendDiscoverEvent(*event) 338 339 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, req) 340 } 341 342 // DeleteInstancesByHost 根据host批量删除服务实例 343 func (s *Server) DeleteInstancesByHost( 344 ctx context.Context, req []*apiservice.Instance) *apiservice.BatchWriteResponse { 345 if checkError := checkBatchInstance(req); checkError != nil { 346 return checkError 347 } 348 349 return batchOperateInstances(ctx, req, s.DeleteInstanceByHost) 350 } 351 352 // DeleteInstanceByHost 根据host删除服务实例 353 func (s *Server) DeleteInstanceByHost(ctx context.Context, req *apiservice.Instance) *apiservice.Response { 354 requestID := utils.ParseRequestID(ctx) 355 platformID := utils.ParsePlatformID(ctx) 356 357 // 参数校验 358 if err := checkInstanceByHost(req); err != nil { 359 return err 360 } 361 362 // 获取实例 363 instances, service, err := s.getInstancesMainByService(ctx, req) 364 if err != nil { 365 return err 366 } 367 368 if instances == nil { 369 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, req) 370 } 371 372 ids := make([]interface{}, 0, len(instances)) 373 for _, instance := range instances { 374 ids = append(ids, instance.ID()) 375 } 376 377 if err := s.storage.BatchDeleteInstances(ids); err != nil { 378 log.Error(err.Error(), utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 379 return wrapperInstanceStoreResponse(req, err) 380 } 381 382 for _, instance := range instances { 383 msg := fmt.Sprintf("delete instance: id=%v, namespace=%v, service=%v, host=%v, port=%v", 384 instance.ID(), service.Namespace, service.Name, instance.Host(), instance.Port()) 385 log.Info(msg, utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 386 s.RecordHistory(ctx, instanceRecordEntry(ctx, req, service, instance, model.ODelete)) 387 s.sendDiscoverEvent(model.InstanceEvent{ 388 Id: instance.ID(), 389 Namespace: service.Namespace, 390 Service: service.Name, 391 Instance: instance.Proto, 392 EType: model.EventInstanceOffline, 393 CreateTime: time.Time{}, 394 }) 395 } 396 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, req) 397 } 398 399 // UpdateInstances 批量修改服务实例 400 func (s *Server) UpdateInstances(ctx context.Context, req []*apiservice.Instance) *apiservice.BatchWriteResponse { 401 if checkError := checkBatchInstance(req); checkError != nil { 402 return checkError 403 } 404 405 return batchOperateInstances(ctx, req, s.UpdateInstance) 406 } 407 408 // UpdateInstance 修改单个服务实例 409 func (s *Server) UpdateInstance(ctx context.Context, req *apiservice.Instance) *apiservice.Response { 410 service, instance, preErr := s.execInstancePreStep(ctx, req) 411 if preErr != nil { 412 return preErr 413 } 414 if err := checkMetadata(req.GetMetadata()); err != nil { 415 return api.NewInstanceResponse(apimodel.Code_InvalidMetadata, req) 416 } 417 418 // 修改 419 requestID := utils.ParseRequestID(ctx) 420 platformID := utils.ParsePlatformID(ctx) 421 log.Info(fmt.Sprintf("old instance: %+v", instance), utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 422 423 var eventTypes map[model.InstanceEventType]bool 424 var needUpdate bool 425 // 存储层操作 426 if needUpdate, eventTypes = s.updateInstanceAttribute(req, instance); !needUpdate { 427 log.Info("update instance no data change, no need update", 428 utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID), zap.String("instance", req.String())) 429 return api.NewInstanceResponse(apimodel.Code_NoNeedUpdate, req) 430 } 431 if err := s.storage.UpdateInstance(instance); err != nil { 432 log.Error(err.Error(), utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 433 return wrapperInstanceStoreResponse(req, err) 434 } 435 436 msg := fmt.Sprintf("update instance: id=%v, namespace=%v, service=%v, host=%v, port=%v, healthy = %v", 437 instance.ID(), service.Namespace, service.Name, instance.Host(), 438 instance.Port(), instance.Healthy()) 439 log.Info(msg, utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 440 s.RecordHistory(ctx, instanceRecordEntry(ctx, req, service, instance, model.OUpdate)) 441 442 for eventType := range eventTypes { 443 event := &model.InstanceEvent{ 444 Id: instance.ID(), 445 Namespace: service.Namespace, 446 Service: service.Name, 447 Instance: instance.Proto, 448 EType: eventType, 449 CreateTime: time.Time{}, 450 } 451 event.InjectMetadata(ctx) 452 s.sendDiscoverEvent(*event) 453 } 454 455 for i := range s.instanceChains { 456 s.instanceChains[i].AfterUpdate(ctx, instance) 457 } 458 459 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, req) 460 } 461 462 // UpdateInstancesIsolate 批量修改服务实例隔离状态 463 // @note 必填参数为service+namespace+host 464 func (s *Server) UpdateInstancesIsolate( 465 ctx context.Context, req []*apiservice.Instance) *apiservice.BatchWriteResponse { 466 if checkError := checkBatchInstance(req); checkError != nil { 467 return checkError 468 } 469 470 return batchOperateInstances(ctx, req, s.UpdateInstanceIsolate) 471 } 472 473 // UpdateInstanceIsolate 修改服务实例隔离状态 474 // @note 必填参数为service+namespace+ip 475 func (s *Server) UpdateInstanceIsolate(ctx context.Context, req *apiservice.Instance) *apiservice.Response { 476 requestID := utils.ParseRequestID(ctx) 477 platformID := utils.ParsePlatformID(ctx) 478 479 // 参数校验 480 if err := checkInstanceByHost(req); err != nil { 481 return err 482 } 483 if req.GetIsolate() == nil { 484 return api.NewInstanceResponse(apimodel.Code_InvalidInstanceIsolate, req) 485 } 486 487 // 获取实例 488 instances, service, err := s.getInstancesMainByService(ctx, req) 489 if err != nil { 490 return err 491 } 492 if instances == nil { 493 return api.NewInstanceResponse(apimodel.Code_NotFoundInstance, req) 494 } 495 496 // 判断是否需要更新 497 needUpdate := false 498 for _, instance := range instances { 499 if req.Isolate != nil && instance.Isolate() != req.GetIsolate().GetValue() { 500 needUpdate = true 501 break 502 } 503 } 504 if !needUpdate { 505 return api.NewInstanceResponse(apimodel.Code_NoNeedUpdate, req) 506 } 507 508 isolate := 0 509 if req.GetIsolate().GetValue() { 510 isolate = 1 511 } 512 513 ids := make([]interface{}, 0, len(instances)) 514 for _, instance := range instances { 515 // 方便后续打印操作记录 516 instance.Proto.Isolate = req.GetIsolate() 517 ids = append(ids, instance.ID()) 518 } 519 520 if err := s.storage.BatchSetInstanceIsolate(ids, isolate, utils.NewUUID()); err != nil { 521 log.Error(err.Error(), utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 522 return wrapperInstanceStoreResponse(req, err) 523 } 524 525 for _, instance := range instances { 526 msg := fmt.Sprintf("update instance: id=%v, namespace=%v, service=%v, host=%v, port=%v, isolate=%v", 527 instance.ID(), service.Namespace, service.Name, instance.Host(), instance.Port(), instance.Isolate()) 528 log.Info(msg, utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 529 s.RecordHistory(ctx, instanceRecordEntry(ctx, req, service, instance, model.OUpdateIsolate)) 530 531 // 比对下更新前后的 isolate 状态 532 if req.Isolate != nil && instance.Isolate() != req.Isolate.GetValue() { 533 eventType := model.EventInstanceCloseIsolate 534 if req.Isolate.GetValue() { 535 eventType = model.EventInstanceOpenIsolate 536 } 537 s.sendDiscoverEvent(model.InstanceEvent{ 538 Id: instance.ID(), 539 Namespace: req.Namespace.GetValue(), 540 Service: req.Service.GetValue(), 541 Instance: instance.Proto, 542 EType: eventType, 543 CreateTime: time.Time{}, 544 }) 545 } 546 instance.Proto.Isolate = utils.NewBoolValue(req.GetIsolate().GetValue()) 547 } 548 549 for i := range s.instanceChains { 550 s.instanceChains[i].AfterUpdate(ctx, instances...) 551 } 552 553 return api.NewInstanceResponse(apimodel.Code_ExecuteSuccess, req) 554 } 555 556 /** 557 * @brief 根据ip隔离和删除服务实例的参数检查 558 */ 559 func checkInstanceByHost(req *apiservice.Instance) *apiservice.Response { 560 if req == nil { 561 return api.NewInstanceResponse(apimodel.Code_EmptyRequest, req) 562 } 563 if err := checkResourceName(req.GetService()); err != nil { 564 return api.NewInstanceResponse(apimodel.Code_InvalidServiceName, req) 565 } 566 if err := checkResourceName(req.GetNamespace()); err != nil { 567 return api.NewInstanceResponse(apimodel.Code_InvalidNamespaceName, req) 568 } 569 if err := checkInstanceHost(req.GetHost()); err != nil { 570 return api.NewInstanceResponse(apimodel.Code_InvalidInstanceHost, req) 571 } 572 return nil 573 } 574 575 /** 576 * @brief 根据服务和host获取服务实例 577 */ 578 func (s *Server) getInstancesMainByService(ctx context.Context, req *apiservice.Instance) ( 579 []*model.Instance, *model.Service, *apiservice.Response) { 580 requestID := utils.ParseRequestID(ctx) 581 platformID := utils.ParsePlatformID(ctx) 582 583 // 检查服务 584 // 这里获取的是源服务的token。如果是别名,service=nil 585 service, err := s.storage.GetSourceServiceToken(req.GetService().GetValue(), req.GetNamespace().GetValue()) 586 if err != nil { 587 log.Error(err.Error(), utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 588 return nil, nil, api.NewInstanceResponse(commonstore.StoreCode2APICode(err), req) 589 } 590 if service == nil { 591 return nil, nil, api.NewInstanceResponse(apimodel.Code_NotFoundService, req) 592 } 593 594 // 获取服务实例 595 instances, err := s.storage.GetInstancesMainByService(service.ID, req.GetHost().GetValue()) 596 if err != nil { 597 log.Error(err.Error(), utils.ZapRequestID(requestID), utils.ZapPlatformID(platformID)) 598 return nil, nil, api.NewInstanceResponse(commonstore.StoreCode2APICode(err), req) 599 } 600 return instances, service, nil 601 } 602 603 /** 604 * @brief 修改服务属性 605 */ 606 func (s *Server) updateInstanceAttribute( 607 req *apiservice.Instance, instance *model.Instance) (bool, map[model.InstanceEventType]bool) { 608 // #lizard forgives 609 instance.MallocProto() 610 needUpdate := false 611 insProto := instance.Proto 612 var updateEvents = make(map[model.InstanceEventType]bool) 613 if ok := utils.IsNotEqualMap(req.GetMetadata(), instance.Metadata()); ok { 614 insProto.Metadata = req.GetMetadata() 615 needUpdate = true 616 updateEvents[model.EventInstanceUpdate] = true 617 } 618 619 if ok := instanceLocationNeedUpdate(req.GetLocation(), instance.Proto.GetLocation()); ok { 620 insProto.Location = req.Location 621 needUpdate = true 622 updateEvents[model.EventInstanceUpdate] = true 623 } 624 625 if req.GetProtocol() != nil && req.GetProtocol().GetValue() != instance.Protocol() { 626 insProto.Protocol = req.GetProtocol() 627 needUpdate = true 628 updateEvents[model.EventInstanceUpdate] = true 629 } 630 631 if req.GetVersion() != nil && req.GetVersion().GetValue() != instance.Version() { 632 insProto.Version = req.GetVersion() 633 needUpdate = true 634 updateEvents[model.EventInstanceUpdate] = true 635 } 636 637 if req.GetPriority() != nil && req.GetPriority().GetValue() != instance.Priority() { 638 insProto.Priority = req.GetPriority() 639 needUpdate = true 640 updateEvents[model.EventInstanceUpdate] = true 641 } 642 643 if req.GetWeight() != nil && req.GetWeight().GetValue() != instance.Weight() { 644 insProto.Weight = req.GetWeight() 645 needUpdate = true 646 updateEvents[model.EventInstanceUpdate] = true 647 } 648 649 if req.GetHealthy() != nil && req.GetHealthy().GetValue() != instance.Healthy() { 650 insProto.Healthy = req.GetHealthy() 651 needUpdate = true 652 if req.Healthy.GetValue() { 653 updateEvents[model.EventInstanceTurnHealth] = true 654 } else { 655 updateEvents[model.EventInstanceTurnUnHealth] = true 656 } 657 } 658 659 if req.GetIsolate() != nil && req.GetIsolate().GetValue() != instance.Isolate() { 660 insProto.Isolate = req.GetIsolate() 661 needUpdate = true 662 if req.Isolate.GetValue() { 663 updateEvents[model.EventInstanceOpenIsolate] = true 664 } else { 665 updateEvents[model.EventInstanceCloseIsolate] = true 666 } 667 } 668 669 if req.GetLogicSet() != nil && req.GetLogicSet().GetValue() != instance.LogicSet() { 670 insProto.LogicSet = req.GetLogicSet() 671 needUpdate = true 672 updateEvents[model.EventInstanceUpdate] = true 673 } 674 675 if ok := updateHealthCheck(req, instance); ok { 676 needUpdate = true 677 updateEvents[model.EventInstanceUpdate] = true 678 } 679 680 // 每次更改,都要生成一个新的uuid 681 if needUpdate { 682 insProto.Revision = utils.NewStringValue(utils.NewUUID()) 683 } 684 685 return needUpdate, updateEvents 686 } 687 688 func instanceLocationNeedUpdate(req *apimodel.Location, old *apimodel.Location) bool { 689 if req.GetRegion().GetValue() != old.GetRegion().GetValue() { 690 return true 691 } 692 if req.GetZone().GetValue() != old.GetZone().GetValue() { 693 return true 694 } 695 if req.GetCampus().GetValue() != old.GetCampus().GetValue() { 696 return true 697 } 698 699 return false 700 } 701 702 // 健康检查的更新 703 func updateHealthCheck(req *apiservice.Instance, instance *model.Instance) bool { 704 needUpdate := false 705 insProto := instance.Proto 706 // health Check,healthCheck不能为空,且没有把enable_health_check置为false 707 if req.GetHealthCheck().GetHeartbeat() != nil && 708 (req.GetEnableHealthCheck() == nil || req.GetEnableHealthCheck().GetValue()) { 709 // 如果数据库中实例原有是不打开健康检查, 710 // 那么一旦打开,status需置为false,等待一次心跳成功才能变成true 711 if !instance.EnableHealthCheck() { 712 // 需要重置healthy,则认为有变更 713 insProto.Healthy = utils.NewBoolValue(false) 714 insProto.EnableHealthCheck = utils.NewBoolValue(true) 715 needUpdate = true 716 } 717 718 ttl := req.GetHealthCheck().GetHeartbeat().GetTtl().GetValue() 719 if ttl == 0 || ttl > 60 { 720 ttl = DefaultTLL 721 } 722 if ttl != instance.HealthCheck().GetHeartbeat().GetTtl().GetValue() { 723 // ttl有变更 724 needUpdate = true 725 } 726 if apiservice.HealthCheck_HEARTBEAT != instance.HealthCheck().GetType() { 727 // health check type有变更 728 needUpdate = true 729 } 730 insProto.HealthCheck = req.GetHealthCheck() 731 insProto.HealthCheck.Type = apiservice.HealthCheck_HEARTBEAT 732 if insProto.HealthCheck.Heartbeat.Ttl == nil { 733 insProto.HealthCheck.Heartbeat.Ttl = utils.NewUInt32Value(0) 734 } 735 insProto.HealthCheck.Heartbeat.Ttl.Value = ttl 736 } 737 738 // update的时候,修改了enableHealthCheck的值 739 if req.GetEnableHealthCheck() != nil && !req.GetEnableHealthCheck().GetValue() { 740 if req.GetEnableHealthCheck().GetValue() != instance.EnableHealthCheck() { 741 needUpdate = true 742 } 743 if insProto.GetHealthCheck() != nil { 744 needUpdate = true 745 } 746 747 insProto.EnableHealthCheck = utils.NewBoolValue(false) 748 insProto.HealthCheck = nil 749 } 750 751 return needUpdate 752 } 753 754 // GetInstances 查询服务实例 755 func (s *Server) GetInstances(ctx context.Context, query map[string]string) *apiservice.BatchQueryResponse { 756 // 对数据先进行提前处理一下 757 filters, metaFilter, batchErr := preGetInstances(query) 758 if batchErr != nil { 759 return batchErr 760 } 761 // 分页数据 762 offset, limit, err := utils.ParseOffsetAndLimit(filters) 763 if err != nil { 764 return api.NewBatchQueryResponse(apimodel.Code_InvalidParameter) 765 } 766 767 total, instances, err := s.Cache().Instance().QueryInstances(filters, metaFilter, offset, limit) 768 if err != nil { 769 log.Errorf("[Server][Instances][Query] instances store err: %s", err.Error()) 770 return api.NewBatchQueryResponse(commonstore.StoreCode2APICode(err)) 771 } 772 773 out := api.NewBatchQueryResponse(apimodel.Code_ExecuteSuccess) 774 out.Amount = utils.NewUInt32Value(total) 775 out.Size = utils.NewUInt32Value(uint32(len(instances))) 776 777 apiInstances := make([]*apiservice.Instance, 0, len(instances)) 778 for _, instance := range instances { 779 svc, _ := s.loadServiceByID(instance.ServiceID) 780 if svc == nil { 781 continue 782 } 783 protoIns := copyOSSInstance(instance.Proto) 784 protoIns.Service = wrapperspb.String(svc.Name) 785 protoIns.Namespace = wrapperspb.String(svc.Namespace) 786 protoIns.ServiceToken = wrapperspb.String(svc.Token) 787 s.packCmdb(protoIns) 788 apiInstances = append(apiInstances, protoIns) 789 } 790 out.Instances = apiInstances 791 792 return out 793 } 794 795 var ( 796 ignoreReturnOSSInstanceMetadata = map[string]struct{}{ 797 "version": {}, 798 "protocol": {}, 799 "region": {}, 800 "zone": {}, 801 "campus": {}, 802 } 803 ) 804 805 func copyOSSInstance(instance *apiservice.Instance) *apiservice.Instance { 806 copyIns := &apiservice.Instance{ 807 Id: instance.Id, 808 Service: instance.Service, 809 Namespace: instance.Namespace, 810 VpcId: instance.VpcId, 811 Host: instance.Host, 812 Port: instance.Port, 813 Protocol: instance.Protocol, 814 Version: instance.Version, 815 Priority: instance.Priority, 816 Weight: instance.Weight, 817 EnableHealthCheck: instance.EnableHealthCheck, 818 HealthCheck: instance.HealthCheck, 819 Healthy: instance.Healthy, 820 Isolate: instance.Isolate, 821 Location: instance.Location, 822 LogicSet: instance.LogicSet, 823 Ctime: instance.Ctime, 824 Mtime: instance.Mtime, 825 Revision: instance.Revision, 826 ServiceToken: instance.ServiceToken, 827 } 828 829 copym := map[string]string{} 830 for k, v := range instance.Metadata { 831 if _, ok := ignoreReturnOSSInstanceMetadata[k]; ok { 832 continue 833 } 834 copym[k] = v 835 } 836 837 copyIns.Metadata = copym 838 return copyIns 839 } 840 841 // GetInstanceLabels 获取实例标签列表 842 func (s *Server) GetInstanceLabels(ctx context.Context, query map[string]string) *apiservice.Response { 843 var ( 844 serviceId string 845 namespace = DefaultNamespace 846 ) 847 848 if val, ok := query["namespace"]; ok { 849 namespace = val 850 } 851 852 if service, ok := query["service"]; ok { 853 svc := s.Cache().Service().GetServiceByName(service, namespace) 854 if svc != nil { 855 serviceId = svc.ID 856 } 857 } 858 859 if id, ok := query["service_id"]; ok { 860 serviceId = id 861 } 862 863 if serviceId == "" { 864 resp := api.NewResponse(apimodel.Code_ExecuteSuccess) 865 resp.InstanceLabels = &apiservice.InstanceLabels{} 866 return resp 867 } 868 869 ret := s.Cache().Instance().GetInstanceLabels(serviceId) 870 resp := api.NewResponse(apimodel.Code_ExecuteSuccess) 871 resp.InstanceLabels = ret 872 return resp 873 } 874 875 // GetInstancesCount 查询总的服务实例,不带过滤条件的 876 func (s *Server) GetInstancesCount(ctx context.Context) *apiservice.BatchQueryResponse { 877 count, err := s.storage.GetInstancesCount() 878 if err != nil { 879 log.Errorf("[Server][Instance][Count] storage get err: %s", err.Error()) 880 return api.NewBatchQueryResponse(commonstore.StoreCode2APICode(err)) 881 } 882 883 out := api.NewBatchQueryResponse(apimodel.Code_ExecuteSuccess) 884 out.Amount = utils.NewUInt32Value(count) 885 out.Instances = make([]*apiservice.Instance, 0) 886 return out 887 } 888 889 // update/delete instance前置条件 890 func (s *Server) execInstancePreStep(ctx context.Context, req *apiservice.Instance) ( 891 *model.Service, *model.Instance, *apiservice.Response) { 892 rid := utils.ParseRequestID(ctx) 893 894 // 参数检查 895 instanceID, checkError := checkReviseInstance(req) 896 if checkError != nil { 897 return nil, nil, checkError 898 } 899 900 // 检查服务实例是否存在 901 instance, err := s.storage.GetInstance(instanceID) 902 if err != nil { 903 log.Error("[Instance] get instance from store", utils.ZapRequestID(rid), utils.ZapInstanceID(instanceID), 904 zap.Error(err)) 905 return nil, nil, api.NewInstanceResponse(commonstore.StoreCode2APICode(err), req) 906 } 907 if instance == nil { 908 return nil, nil, api.NewInstanceResponse(apimodel.Code_NotFoundInstance, req) 909 } 910 911 service, resp := s.instanceAuth(ctx, req, instance.ServiceID) 912 if resp != nil { 913 return nil, nil, resp 914 } 915 916 return service, instance, nil 917 } 918 919 // 实例鉴权 920 func (s *Server) instanceAuth(ctx context.Context, req *apiservice.Instance, serviceID string) ( 921 *model.Service, *apiservice.Response) { 922 service, err := s.storage.GetServiceByID(serviceID) 923 if err != nil { 924 log.Error(err.Error(), utils.ZapRequestID(utils.ParseRequestID(ctx))) 925 return nil, api.NewInstanceResponse(commonstore.StoreCode2APICode(err), req) 926 } 927 if service == nil { 928 return nil, api.NewInstanceResponse(apimodel.Code_NotFoundResource, req) 929 } 930 931 return service, nil 932 } 933 934 // 获取api.instance 935 func (s *Server) getInstance(service *apiservice.Service, instance *apiservice.Instance) *apiservice.Instance { 936 out := &apiservice.Instance{ 937 Id: instance.GetId(), 938 Service: service.GetName(), 939 Namespace: service.GetNamespace(), 940 VpcId: instance.GetVpcId(), 941 Host: instance.GetHost(), 942 Port: instance.GetPort(), 943 Protocol: instance.GetProtocol(), 944 Version: instance.GetVersion(), 945 Priority: instance.GetPriority(), 946 Weight: instance.GetWeight(), 947 EnableHealthCheck: instance.GetEnableHealthCheck(), 948 HealthCheck: instance.GetHealthCheck(), 949 Healthy: instance.GetHealthy(), 950 Isolate: instance.GetIsolate(), 951 Location: instance.GetLocation(), 952 Metadata: instance.GetMetadata(), 953 LogicSet: instance.GetLogicSet(), 954 Ctime: instance.GetCtime(), 955 Mtime: instance.GetMtime(), 956 Revision: instance.GetRevision(), 957 } 958 959 s.packCmdb(out) 960 return out 961 } 962 963 // 获取cmdb 964 func (s *Server) packCmdb(instance *apiservice.Instance) { 965 if s.cmdb == nil { 966 return 967 } 968 if instance == nil || !isEmptyLocation(instance.GetLocation()) { 969 return 970 } 971 972 location, err := s.cmdb.GetLocation(instance.GetHost().GetValue()) 973 if err != nil { 974 log.Error("[Instance] pack cmdb info fail", 975 zap.String("namespace", instance.GetNamespace().GetValue()), 976 zap.String("service", instance.GetService().GetValue()), 977 zap.String("host", instance.GetHost().GetValue()), 978 zap.Uint32("port", instance.GetPort().GetValue())) 979 return 980 } 981 if location != nil { 982 instance.Location = location.Proto 983 } 984 } 985 986 func isEmptyLocation(loc *apimodel.Location) bool { 987 return loc == nil || (loc.GetRegion().GetValue() == "" && 988 loc.GetZone().GetValue() == "" && 989 loc.GetCampus().GetValue() == "") 990 } 991 992 func (s *Server) sendDiscoverEvent(event model.InstanceEvent) { 993 if event.Instance != nil { 994 // In order not to cause `panic` in cause multi-corporate data op, do deep copy 995 // event.Instance = proto.Clone(event.Instance).(*apiservice.Instance) 996 } 997 _ = eventhub.Publish(eventhub.InstanceEventTopic, event) 998 } 999 1000 type wrapSvcName interface { 1001 // GetService 获取服务名 1002 GetService() *wrappers.StringValue 1003 // GetNamespace 获取命名空间 1004 GetNamespace() *wrappers.StringValue 1005 } 1006 1007 type rawSvcName interface { 1008 // GetService 获取服务名 1009 GetService() string 1010 // GetNamespace 获取命名空间 1011 GetNamespace() string 1012 } 1013 1014 // createWrapServiceIfAbsent 如果服务不存在,则进行创建,并返回服务的ID信息 1015 func (s *Server) createWrapServiceIfAbsent(ctx context.Context, instance wrapSvcName) (string, *apiservice.Response) { 1016 return s.createServiceIfAbsent(ctx, instance.GetNamespace().GetValue(), instance.GetService().GetValue()) 1017 } 1018 1019 func (s *Server) createServiceIfAbsent( 1020 ctx context.Context, namespace string, svcName string) (string, *apiservice.Response) { 1021 svc, errResp := s.loadService(namespace, svcName) 1022 if errResp != nil { 1023 return "", errResp 1024 } 1025 if svc != nil { 1026 return svc.ID, nil 1027 } 1028 simpleService := &apiservice.Service{ 1029 Name: utils.NewStringValue(svcName), 1030 Namespace: utils.NewStringValue(namespace), 1031 Owners: func() *wrapperspb.StringValue { 1032 owner := utils.ParseOwnerID(ctx) 1033 if owner == "" { 1034 return utils.NewStringValue("Polaris") 1035 } 1036 return utils.NewStringValue(owner) 1037 }(), 1038 } 1039 key := fmt.Sprintf("%s:%s", simpleService.Namespace, simpleService.Name) 1040 ret, err, _ := s.createServiceSingle.Do(key, func() (interface{}, error) { 1041 resp := s.CreateService(ctx, simpleService) 1042 return resp, nil 1043 }) 1044 if err != nil { 1045 return "", api.NewResponseWithMsg(apimodel.Code_ExecuteException, err.Error()) 1046 } 1047 resp := ret.(*apiservice.Response) 1048 retCode := apimodel.Code(resp.GetCode().GetValue()) 1049 if retCode != apimodel.Code_ExecuteSuccess && retCode != apimodel.Code_ExistedResource { 1050 return "", resp 1051 } 1052 svcId := resp.GetService().GetId().GetValue() 1053 return svcId, nil 1054 } 1055 1056 func (s *Server) loadService(namespace string, svcName string) (*model.Service, *apiservice.Response) { 1057 svc := s.caches.Service().GetServiceByName(svcName, namespace) 1058 if svc != nil { 1059 if svc.IsAlias() { 1060 return nil, api.NewResponseWithMsg(apimodel.Code_BadRequest, "service is alias") 1061 } 1062 return svc, nil 1063 } 1064 // 再走数据库查询一遍 1065 svc, err := s.storage.GetService(svcName, namespace) 1066 if err != nil { 1067 return nil, api.NewResponseWithMsg(commonstore.StoreCode2APICode(err), err.Error()) 1068 } 1069 if svc != nil && svc.IsAlias() { 1070 return nil, api.NewResponseWithMsg(apimodel.Code_BadRequest, "service is alias") 1071 } 1072 return svc, nil 1073 } 1074 1075 func (s *Server) loadServiceByID(svcID string) (*model.Service, error) { 1076 svc := s.caches.Service().GetServiceByID(svcID) 1077 if svc != nil { 1078 if svc.IsAlias() { 1079 return nil, errors.New("service is alias") 1080 } 1081 return svc, nil 1082 } 1083 1084 // 再走数据库查询一遍 1085 svc, err := s.storage.GetServiceByID(svcID) 1086 if err != nil { 1087 return nil, err 1088 } 1089 1090 if svc != nil && svc.IsAlias() { 1091 return nil, errors.New("service is alias") 1092 } 1093 1094 return svc, nil 1095 } 1096 1097 /* 1098 * @brief 检查批量请求 1099 */ 1100 func checkBatchInstance(req []*apiservice.Instance) *apiservice.BatchWriteResponse { 1101 if len(req) == 0 { 1102 return api.NewBatchWriteResponse(apimodel.Code_EmptyRequest) 1103 } 1104 1105 if len(req) > MaxBatchSize { 1106 return api.NewBatchWriteResponse(apimodel.Code_BatchSizeOverLimit) 1107 } 1108 1109 return nil 1110 } 1111 1112 /* 1113 * @brief 检查创建服务实例请求参数 1114 */ 1115 func checkCreateInstance(req *apiservice.Instance) (string, *apiservice.Response) { 1116 if req == nil { 1117 return "", api.NewInstanceResponse(apimodel.Code_EmptyRequest, req) 1118 } 1119 1120 if err := checkMetadata(req.GetMetadata()); err != nil { 1121 return "", api.NewInstanceResponse(apimodel.Code_InvalidMetadata, req) 1122 } 1123 1124 // 检查字段长度是否大于DB中对应字段长 1125 err, notOk := CheckDbInstanceFieldLen(req) 1126 if notOk { 1127 return "", err 1128 } 1129 1130 return utils.CheckInstanceTetrad(req) 1131 } 1132 1133 /* 1134 * @brief 检查删除/修改服务实例请求参数 1135 */ 1136 func checkReviseInstance(req *apiservice.Instance) (string, *apiservice.Response) { 1137 if req == nil { 1138 return "", api.NewInstanceResponse(apimodel.Code_EmptyRequest, req) 1139 } 1140 1141 if req.GetId() != nil { 1142 if req.GetId().GetValue() == "" { 1143 return "", api.NewInstanceResponse(apimodel.Code_InvalidInstanceID, req) 1144 } 1145 return req.GetId().GetValue(), nil 1146 } 1147 1148 // 检查字段长度是否大于DB中对应字段长 1149 err, notOk := CheckDbInstanceFieldLen(req) 1150 if notOk { 1151 return "", err 1152 } 1153 1154 return utils.CheckInstanceTetrad(req) 1155 } 1156 1157 /* 1158 * @brief 检查心跳实例请求参数 1159 * 检查是否存在token,以及 id或者四元组 1160 * 注意:心跳上报只允许从client上报,因此token只会存在req中 1161 */ 1162 func checkHeartbeatInstance(req *apiservice.Instance) (string, *apiservice.Response) { 1163 if req == nil { 1164 return "", api.NewInstanceResponse(apimodel.Code_EmptyRequest, req) 1165 } 1166 if req.GetId() != nil { 1167 if req.GetId().GetValue() == "" { 1168 return "", api.NewInstanceResponse(apimodel.Code_InvalidInstanceID, req) 1169 } 1170 return req.GetId().GetValue(), nil 1171 } 1172 return utils.CheckInstanceTetrad(req) 1173 } 1174 1175 // 获取instance请求的token信息 1176 func parseInstanceReqToken(ctx context.Context, req *apiservice.Instance) string { 1177 if reqToken := req.GetServiceToken().GetValue(); reqToken != "" { 1178 return reqToken 1179 } 1180 1181 return utils.ParseToken(ctx) 1182 } 1183 1184 // 实例查询前置处理 1185 func preGetInstances(query map[string]string) (map[string]string, map[string]string, *apiservice.BatchQueryResponse) { 1186 // 不允许全量查询服务实例 1187 if len(query) == 0 { 1188 return nil, nil, api.NewBatchQueryResponse(apimodel.Code_EmptyQueryParameter) 1189 } 1190 1191 var metaFilter map[string]string 1192 metaKey, metaKeyAvail := query["keys"] 1193 metaValue, metaValueAvail := query["values"] 1194 if metaKeyAvail != metaValueAvail { 1195 return nil, nil, api.NewBatchQueryResponseWithMsg( 1196 apimodel.Code_InvalidQueryInsParameter, "instance metadata key and value must be both provided") 1197 } 1198 if metaKeyAvail { 1199 metaFilter = map[string]string{metaKey: metaValue} 1200 } 1201 1202 // 以healthy为准 1203 _, lhs := query["health_status"] 1204 _, rhs := query["healthy"] 1205 if lhs && rhs { 1206 delete(query, "health_status") 1207 } 1208 1209 filters := make(map[string]string) 1210 for key, value := range query { 1211 if _, ok := InstanceFilterAttributes[key]; !ok { 1212 log.Errorf("[Server][Instance][Query] attribute(%s) is not allowed", key) 1213 return nil, metaFilter, api.NewBatchQueryResponseWithMsg( 1214 apimodel.Code_InvalidParameter, key+" is not allowed") 1215 } 1216 1217 if value == "" { 1218 log.Errorf("[Server][Instance][Query] attribute(%s: %s) is not allowed empty", key, value) 1219 return nil, metaFilter, api.NewBatchQueryResponseWithMsg( 1220 apimodel.Code_InvalidParameter, "the value for "+key+" is empty") 1221 } 1222 if attr, ok := InsFilter2toreAttr[key]; ok { 1223 key = attr 1224 } 1225 if !NotInsFilterAttr[key] { 1226 filters[key] = value 1227 } 1228 } 1229 1230 return filters, metaFilter, nil 1231 } 1232 1233 // 批量操作实例 1234 func batchOperateInstances(ctx context.Context, reqs []*apiservice.Instance, 1235 handler func(ctx context.Context, req *apiservice.Instance) *apiservice.Response) *apiservice.BatchWriteResponse { 1236 responses := api.NewBatchWriteResponse(apimodel.Code_ExecuteSuccess) 1237 1238 chs := make([]chan *apiservice.Response, 0, len(reqs)) 1239 for i, instance := range reqs { 1240 chs = append(chs, make(chan *apiservice.Response)) 1241 go func(index int, ins *apiservice.Instance) { 1242 chs[index] <- handler(ctx, ins) 1243 }(i, instance) 1244 } 1245 1246 for _, ch := range chs { 1247 resp := <-ch 1248 api.Collect(responses, resp) 1249 } 1250 1251 return api.FormatBatchWriteResponse(responses) 1252 } 1253 1254 // wrapper instance store response 1255 func wrapperInstanceStoreResponse(instance *apiservice.Instance, err error) *apiservice.Response { 1256 resp := storeError2Response(err) 1257 if resp == nil { 1258 return nil 1259 } 1260 1261 resp.Instance = instance 1262 return resp 1263 } 1264 1265 // 生成instance的记录entry 1266 func instanceRecordEntry(ctx context.Context, req *apiservice.Instance, service *model.Service, ins *model.Instance, 1267 opt model.OperationType) *model.RecordEntry { 1268 if service == nil || ins == nil { 1269 return nil 1270 } 1271 marshaler := jsonpb.Marshaler{} 1272 datail, _ := marshaler.MarshalToString(req) 1273 entry := &model.RecordEntry{ 1274 ResourceType: model.RInstance, 1275 ResourceName: fmt.Sprintf("%s(%s:%d)", service.Name, ins.Host(), ins.Port()), 1276 Namespace: service.Namespace, 1277 OperationType: opt, 1278 Operator: utils.ParseOperator(ctx), 1279 Detail: datail, 1280 HappenTime: time.Now(), 1281 } 1282 return entry 1283 } 1284 1285 // CheckDbInstanceFieldLen 检查DB中service表对应的入参字段合法性 1286 func CheckDbInstanceFieldLen(req *apiservice.Instance) (*apiservice.Response, bool) { 1287 if err := utils.CheckDbStrFieldLen(req.GetService(), MaxDbServiceNameLength); err != nil { 1288 return api.NewInstanceResponse(apimodel.Code_InvalidServiceName, req), true 1289 } 1290 if err := utils.CheckDbStrFieldLen(req.GetNamespace(), MaxDbServiceNamespaceLength); err != nil { 1291 return api.NewInstanceResponse(apimodel.Code_InvalidNamespaceName, req), true 1292 } 1293 if err := utils.CheckDbStrFieldLen(req.GetHost(), MaxDbInsHostLength); err != nil { 1294 return api.NewInstanceResponse(apimodel.Code_InvalidInstanceHost, req), true 1295 } 1296 if err := utils.CheckDbStrFieldLen(req.GetProtocol(), MaxDbInsProtocolLength); err != nil { 1297 return api.NewInstanceResponse(apimodel.Code_InvalidInstanceProtocol, req), true 1298 } 1299 if err := utils.CheckDbStrFieldLen(req.GetVersion(), MaxDbInsVersionLength); err != nil { 1300 return api.NewInstanceResponse(apimodel.Code_InvalidInstanceVersion, req), true 1301 } 1302 if err := utils.CheckDbStrFieldLen(req.GetLogicSet(), MaxDbInsLogicSetLength); err != nil { 1303 return api.NewInstanceResponse(apimodel.Code_InvalidInstanceLogicSet, req), true 1304 } 1305 if err := utils.CheckDbMetaDataFieldLen(req.GetMetadata()); err != nil { 1306 return api.NewInstanceResponse(apimodel.Code_InvalidMetadata, req), true 1307 } 1308 if req.GetPort().GetValue() > 65535 { 1309 return api.NewInstanceResponse(apimodel.Code_InvalidInstancePort, req), true 1310 } 1311 1312 if req.GetWeight().GetValue() > 65535 { 1313 return api.NewInstanceResponse(apimodel.Code_InvalidParameter, req), true 1314 } 1315 return nil, false 1316 }