github.com/polarismesh/polaris@v1.17.8/service/service_alias.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 "fmt" 23 24 "github.com/golang/protobuf/ptypes/wrappers" 25 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 26 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 27 "go.uber.org/zap" 28 29 api "github.com/polarismesh/polaris/common/api/v1" 30 "github.com/polarismesh/polaris/common/model" 31 commonstore "github.com/polarismesh/polaris/common/store" 32 commontime "github.com/polarismesh/polaris/common/time" 33 "github.com/polarismesh/polaris/common/utils" 34 "github.com/polarismesh/polaris/store" 35 ) 36 37 var ( 38 // AliasFilterAttributes filer attrs alias 39 AliasFilterAttributes = map[string]bool{ 40 "alias": true, 41 "alias_namespace": true, 42 "namespace": true, 43 "service": true, 44 "owner": true, 45 "offset": true, 46 "limit": true, 47 } 48 ) 49 50 // CreateServiceAlias 创建服务别名 51 func (s *Server) CreateServiceAlias(ctx context.Context, req *apiservice.ServiceAlias) *apiservice.Response { 52 if resp := checkCreateServiceAliasReq(ctx, req); resp != nil { 53 return resp 54 } 55 56 rid := utils.ParseRequestID(ctx) 57 tx, err := s.storage.CreateTransaction() 58 if err != nil { 59 log.Error(err.Error(), utils.ZapRequestID(rid)) 60 return api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req) 61 } 62 defer func() { _ = tx.Commit() }() 63 64 service, response, done := s.checkPointServiceAlias(tx, req, rid) 65 if done { 66 return response 67 } 68 69 // 检查是否存在同名的alias 70 if req.GetAlias().GetValue() != "" { 71 oldAlias, getErr := s.storage.GetService(req.GetAlias().GetValue(), 72 req.GetAliasNamespace().GetValue()) 73 if getErr != nil { 74 log.Error(getErr.Error(), utils.ZapRequestID(rid)) 75 return api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req) 76 } 77 if oldAlias != nil { 78 return api.NewServiceAliasResponse(apimodel.Code_ExistedResource, req) 79 } 80 } 81 82 // 构建别名的信息,这里包括了创建SID 83 input, resp := s.createServiceAliasModel(req, service.ID) 84 if resp != nil { 85 return resp 86 } 87 if err := s.storage.AddService(input); err != nil { 88 log.Error(err.Error(), utils.ZapRequestID(rid)) 89 return api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req) 90 } 91 92 log.Info(fmt.Sprintf("create service alias, service(%s, %s), alias(%s, %s)", 93 req.Service.Value, req.Namespace.Value, input.Name, input.Namespace), utils.ZapRequestID(rid)) 94 out := &apiservice.ServiceAlias{ 95 Service: req.Service, 96 Namespace: req.Namespace, 97 Alias: req.Alias, 98 AliasNamespace: req.AliasNamespace, 99 ServiceToken: &wrappers.StringValue{Value: input.Token}, 100 } 101 if out.GetAlias().GetValue() == "" { 102 out.Alias = utils.NewStringValue(input.Name) 103 } 104 record := &apiservice.Service{Name: out.Alias, Namespace: out.AliasNamespace} 105 s.RecordHistory(ctx, serviceRecordEntry(ctx, record, input, model.OCreate)) 106 return api.NewServiceAliasResponse(apimodel.Code_ExecuteSuccess, out) 107 } 108 109 func (s *Server) checkPointServiceAlias( 110 tx store.Transaction, req *apiservice.ServiceAlias, rid string) (*model.Service, *apiservice.Response, bool) { 111 // 检查指向服务是否存在以及是否为别名 112 service, err := tx.LockService(req.GetService().GetValue(), req.GetNamespace().GetValue()) 113 if err != nil { 114 log.Error(err.Error(), utils.ZapRequestID(rid)) 115 return nil, api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req), true 116 } 117 if service == nil { 118 return nil, api.NewServiceAliasResponse(apimodel.Code_NotFoundService, req), true 119 } 120 // 检查该服务是否已经是一个别名服务,不允许再为别名创建别名 121 if service.IsAlias() { 122 return nil, api.NewServiceAliasResponse(apimodel.Code_NotAllowCreateAliasForAlias, req), true 123 } 124 return service, nil, false 125 } 126 127 // DeleteServiceAlias 删除服务别名 128 // 129 // 需要带上源服务name,namespace,token 130 // 另外一种删除别名的方式,是直接调用删除服务的接口,也是可行的 131 func (s *Server) DeleteServiceAlias(ctx context.Context, req *apiservice.ServiceAlias) *apiservice.Response { 132 if resp := checkDeleteServiceAliasReq(ctx, req); resp != nil { 133 return resp 134 } 135 rid := utils.ParseRequestID(ctx) 136 alias, err := s.storage.GetService(req.GetAlias().GetValue(), 137 req.GetAliasNamespace().GetValue()) 138 if err != nil { 139 log.Error(err.Error(), utils.ZapRequestID(rid)) 140 return api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req) 141 } 142 if alias == nil { 143 return api.NewServiceAliasResponse(apimodel.Code_NotFoundServiceAlias, req) 144 } 145 146 // 直接删除alias 147 if err := s.storage.DeleteServiceAlias(req.GetAlias().GetValue(), 148 req.GetAliasNamespace().GetValue()); err != nil { 149 log.Error(err.Error(), utils.ZapRequestID(rid)) 150 return api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req) 151 } 152 153 return api.NewServiceAliasResponse(apimodel.Code_ExecuteSuccess, req) 154 } 155 156 func checkBatchAlias(req []*apiservice.ServiceAlias) *apiservice.BatchWriteResponse { 157 if len(req) == 0 { 158 return api.NewBatchWriteResponse(apimodel.Code_EmptyRequest) 159 } 160 161 if len(req) > MaxBatchSize { 162 return api.NewBatchWriteResponse(apimodel.Code_BatchSizeOverLimit) 163 } 164 165 return nil 166 } 167 168 // DeleteServiceAliases 删除服务别名列表 169 func (s *Server) DeleteServiceAliases( 170 ctx context.Context, req []*apiservice.ServiceAlias) *apiservice.BatchWriteResponse { 171 if checkError := checkBatchAlias(req); checkError != nil { 172 return checkError 173 } 174 175 responses := api.NewBatchWriteResponse(apimodel.Code_ExecuteSuccess) 176 for _, alias := range req { 177 response := s.DeleteServiceAlias(ctx, alias) 178 api.Collect(responses, response) 179 } 180 181 return api.FormatBatchWriteResponse(responses) 182 } 183 184 // UpdateServiceAlias 修改服务别名 185 func (s *Server) UpdateServiceAlias(ctx context.Context, req *apiservice.ServiceAlias) *apiservice.Response { 186 rid := utils.ParseRequestID(ctx) 187 188 // 检查请求参数 189 if resp := checkReviseServiceAliasReq(ctx, req); resp != nil { 190 return resp 191 } 192 193 // 检查别名负责人 194 // if err := checkResourceOwners(req.GetOwners()); err != nil { 195 // return api.NewServiceAliasResponse(api.InvalidServiceAliasOwners, req) 196 // } 197 198 // 检查服务别名是否存在 199 alias, err := s.storage.GetService(req.GetAlias().GetValue(), req.GetAliasNamespace().GetValue()) 200 if err != nil { 201 log.Error(err.Error(), utils.ZapRequestID(rid)) 202 return api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req) 203 } 204 if alias == nil { 205 return api.NewServiceAliasResponse(apimodel.Code_NotFoundServiceAlias, req) 206 } 207 208 // 检查将要指向的服务是否存在 209 service, err := s.storage.GetService(req.GetService().GetValue(), req.GetNamespace().GetValue()) 210 if err != nil { 211 log.Error(err.Error(), utils.ZapRequestID(rid)) 212 return api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req) 213 } 214 if service == nil { 215 return api.NewServiceAliasResponse(apimodel.Code_NotFoundService, req) 216 } 217 // 检查该服务是否已经是一个别名服务,不允许再为别名创建别名 218 if service.IsAlias() { 219 return api.NewServiceAliasResponse(apimodel.Code_NotAllowCreateAliasForAlias, req) 220 } 221 222 // 判断是否需要修改 223 resp, needUpdate, needUpdateOwner := s.updateServiceAliasAttribute(req, alias, service.ID) 224 if resp != nil { 225 return resp 226 } 227 228 if !needUpdate { 229 log.Info("update service alias data no change, no need update", utils.ZapRequestID(rid), 230 zap.String("service alias", req.String())) 231 return api.NewServiceAliasResponse(apimodel.Code_NoNeedUpdate, req) 232 } 233 234 // 执行存储层操作 235 if err := s.storage.UpdateServiceAlias(alias, needUpdateOwner); err != nil { 236 log.Error(err.Error(), utils.ZapRequestID(rid)) 237 return wrapperServiceAliasResponse(req, err) 238 } 239 240 log.Info(fmt.Sprintf("update service alias, service(%s, %s), alias(%s)", 241 req.GetService().GetValue(), req.GetNamespace().GetValue(), req.GetAlias().GetValue()), utils.ZapRequestID(rid)) 242 243 record := &apiservice.Service{Name: req.Alias, Namespace: req.Namespace} 244 s.RecordHistory(ctx, serviceRecordEntry(ctx, record, alias, model.OUpdate)) 245 246 return api.NewServiceAliasResponse(apimodel.Code_ExecuteSuccess, req) 247 } 248 249 // GetServiceAliases 查找服务别名 250 func (s *Server) GetServiceAliases(ctx context.Context, query map[string]string) *apiservice.BatchQueryResponse { 251 // 先处理offset和limit 252 offset, limit, err := utils.ParseOffsetAndLimit(query) 253 if err != nil { 254 return api.NewBatchQueryResponse(apimodel.Code_InvalidParameter) 255 } 256 257 // 处理剩余的参数 258 filter := make(map[string]string) 259 for key, value := range query { 260 if _, ok := AliasFilterAttributes[key]; !ok { 261 log.Errorf("[Server][Alias][Query] attribute(%s) is not allowed", key) 262 return api.NewBatchQueryResponse(apimodel.Code_InvalidParameter) 263 } 264 filter[key] = value 265 } 266 267 total, aliases, err := s.storage.GetServiceAliases(filter, offset, limit) 268 if err != nil { 269 log.Errorf("[Server][Alias] get aliases err: %s", err.Error()) 270 return api.NewBatchQueryResponse(commonstore.StoreCode2APICode(err)) 271 } 272 273 resp := api.NewBatchQueryResponse(apimodel.Code_ExecuteSuccess) 274 resp.Amount = utils.NewUInt32Value(total) 275 resp.Size = utils.NewUInt32Value(uint32(len(aliases))) 276 resp.Aliases = make([]*apiservice.ServiceAlias, 0, len(aliases)) 277 for _, entry := range aliases { 278 item := &apiservice.ServiceAlias{ 279 Id: utils.NewStringValue(entry.ID), 280 Service: utils.NewStringValue(entry.Service), 281 Namespace: utils.NewStringValue(entry.Namespace), 282 Alias: utils.NewStringValue(entry.Alias), 283 AliasNamespace: utils.NewStringValue(entry.AliasNamespace), 284 Owners: utils.NewStringValue(entry.Owner), 285 Comment: utils.NewStringValue(entry.Comment), 286 Ctime: utils.NewStringValue(commontime.Time2String(entry.CreateTime)), 287 Mtime: utils.NewStringValue(commontime.Time2String(entry.ModifyTime)), 288 } 289 resp.Aliases = append(resp.Aliases, item) 290 } 291 292 return resp 293 } 294 295 // checkCreateServiceAliasReq 检查别名请求 296 func checkCreateServiceAliasReq(ctx context.Context, req *apiservice.ServiceAlias) *apiservice.Response { 297 response, done := preCheckAlias(req) 298 if done { 299 return response 300 } 301 // 检查字段长度是否大于DB中对应字段长 302 err, notOk := CheckDbServiceAliasFieldLen(req) 303 if notOk { 304 return err 305 } 306 return nil 307 } 308 309 func preCheckAlias(req *apiservice.ServiceAlias) (*apiservice.Response, bool) { 310 if req == nil { 311 return api.NewServiceAliasResponse(apimodel.Code_EmptyRequest, req), true 312 } 313 314 if err := checkResourceName(req.GetService()); err != nil { 315 return api.NewServiceAliasResponse(apimodel.Code_InvalidServiceName, req), true 316 } 317 318 if err := checkResourceName(req.GetNamespace()); err != nil { 319 return api.NewServiceAliasResponse(apimodel.Code_InvalidNamespaceName, req), true 320 } 321 322 if err := checkResourceName(req.GetAliasNamespace()); err != nil { 323 return api.NewServiceAliasResponse(apimodel.Code_InvalidNamespaceWithAlias, req), true 324 } 325 326 // 默认类型,需要检查alias是否为空 327 if req.GetType() == apiservice.AliasType_DEFAULT { 328 if err := checkResourceName(req.GetAlias()); err != nil { 329 return api.NewServiceAliasResponse(apimodel.Code_InvalidServiceAlias, req), true 330 } 331 } 332 return nil, false 333 } 334 335 // checkReviseServiceAliasReq 检查删除、修改别名请求 336 func checkReviseServiceAliasReq(ctx context.Context, req *apiservice.ServiceAlias) *apiservice.Response { 337 resp := checkDeleteServiceAliasReq(ctx, req) 338 if resp != nil { 339 return resp 340 } 341 // 检查服务名 342 if err := checkResourceName(req.GetService()); err != nil { 343 return api.NewServiceAliasResponse(apimodel.Code_InvalidServiceName, req) 344 } 345 346 // 检查命名空间 347 if err := checkResourceName(req.GetNamespace()); err != nil { 348 return api.NewServiceAliasResponse(apimodel.Code_InvalidNamespaceName, req) 349 } 350 return nil 351 } 352 353 // checkDeleteServiceAliasReq 检查删除、修改别名请求 354 func checkDeleteServiceAliasReq(ctx context.Context, req *apiservice.ServiceAlias) *apiservice.Response { 355 if req == nil { 356 return api.NewServiceAliasResponse(apimodel.Code_EmptyRequest, req) 357 } 358 359 // 检查服务别名 360 if err := checkResourceName(req.GetAlias()); err != nil { 361 return api.NewServiceAliasResponse(apimodel.Code_InvalidServiceAlias, req) 362 } 363 364 // 检查服务别名命名空间 365 if err := checkResourceName(req.GetAliasNamespace()); err != nil { 366 return api.NewServiceAliasResponse(apimodel.Code_InvalidNamespaceWithAlias, req) 367 } 368 369 // 检查字段长度是否大于DB中对应字段长 370 err, notOk := CheckDbServiceAliasFieldLen(req) 371 if notOk { 372 return err 373 } 374 375 return nil 376 } 377 378 // updateServiceAliasAttribute 修改服务别名属性 379 func (s *Server) updateServiceAliasAttribute(req *apiservice.ServiceAlias, alias *model.Service, serviceID string) ( 380 *apiservice.Response, bool, bool) { 381 var ( 382 needUpdate bool 383 needUpdateOwner bool 384 ) 385 386 // 获取当前指向服务 387 service, err := s.storage.GetServiceByID(alias.Reference) 388 if err != nil { 389 return api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req), needUpdate, needUpdateOwner 390 } 391 392 if service.ID != serviceID { 393 alias.Reference = serviceID 394 needUpdate = true 395 } 396 397 if len(req.GetOwners().GetValue()) > 0 && req.GetOwners().GetValue() != alias.Owner { 398 alias.Owner = req.GetOwners().GetValue() 399 needUpdate = true 400 needUpdateOwner = true 401 } 402 403 if req.GetComment() != nil && req.GetComment().GetValue() != alias.Comment { 404 alias.Comment = req.GetComment().GetValue() 405 needUpdate = true 406 } 407 408 if needUpdate { 409 alias.Revision = utils.NewUUID() 410 } 411 412 return nil, needUpdate, needUpdateOwner 413 } 414 415 // createServiceAliasModel 构建存储结构 416 func (s *Server) createServiceAliasModel(req *apiservice.ServiceAlias, svcId string) ( 417 *model.Service, *apiservice.Response) { 418 out := &model.Service{ 419 ID: utils.NewUUID(), 420 Name: req.GetAlias().GetValue(), 421 Namespace: req.GetAliasNamespace().GetValue(), 422 Reference: svcId, 423 Token: utils.NewUUID(), 424 Owner: req.GetOwners().GetValue(), 425 Comment: req.GetComment().GetValue(), 426 Revision: utils.NewUUID(), 427 } 428 429 // sid类型,则创建SID 430 if req.GetType() == apiservice.AliasType_CL5SID { 431 layoutID, ok := Namespace2SidLayoutID[req.GetAliasNamespace().GetValue()] 432 if !ok { 433 log.Errorf("[Server][Alias] namespace(%s) not allow to create sid alias", 434 req.GetNamespace().GetValue()) 435 return nil, api.NewServiceAliasResponse(apimodel.Code_InvalidNamespaceWithAlias, req) 436 } 437 sid, err := s.storage.GenNextL5Sid(layoutID) 438 if err != nil { 439 log.Errorf("[Server] gen next l5 sid err: %s", err.Error()) 440 return nil, api.NewServiceAliasResponse(commonstore.StoreCode2APICode(err), req) 441 } 442 out.Name = sid 443 } 444 445 return out, nil 446 } 447 448 // wrapperServiceAliasResponse wrapper service alias error 449 func wrapperServiceAliasResponse(alias *apiservice.ServiceAlias, err error) *apiservice.Response { 450 resp := storeError2Response(err) 451 if resp == nil { 452 return nil 453 } 454 455 resp.Alias = alias 456 return resp 457 } 458 459 // CheckDbServiceAliasFieldLen 检查DB中service表对应的入参字段合法性 460 func CheckDbServiceAliasFieldLen(req *apiservice.ServiceAlias) (*apiservice.Response, bool) { 461 if err := utils.CheckDbStrFieldLen(req.GetService(), MaxDbServiceNameLength); err != nil { 462 return api.NewServiceAliasResponse(apimodel.Code_InvalidServiceName, req), true 463 } 464 if err := utils.CheckDbStrFieldLen(req.GetNamespace(), MaxDbServiceNamespaceLength); err != nil { 465 return api.NewServiceAliasResponse(apimodel.Code_InvalidNamespaceName, req), true 466 } 467 if err := utils.CheckDbStrFieldLen(req.GetAlias(), MaxDbServiceNameLength); err != nil { 468 return api.NewServiceAliasResponse(apimodel.Code_InvalidServiceAlias, req), true 469 } 470 if err := utils.CheckDbStrFieldLen(req.GetAliasNamespace(), MaxDbServiceNamespaceLength); err != nil { 471 return api.NewServiceAliasResponse(apimodel.Code_InvalidNamespaceWithAlias, req), true 472 } 473 if err := utils.CheckDbStrFieldLen(req.GetComment(), MaxDbServiceCommentLength); err != nil { 474 return api.NewServiceAliasResponse(apimodel.Code_InvalidServiceAliasComment, req), true 475 } 476 if err := utils.CheckDbStrFieldLen(req.GetOwners(), MaxDbServiceOwnerLength); err != nil { 477 return api.NewServiceAliasResponse(apimodel.Code_InvalidServiceAliasOwners, req), true 478 } 479 return nil, false 480 }