github.com/polarismesh/polaris@v1.17.8/common/utils/common.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 utils 19 20 import ( 21 "context" 22 "crypto/sha1" 23 "encoding/hex" 24 "errors" 25 "fmt" 26 "io" 27 "regexp" 28 "strconv" 29 "strings" 30 "unicode/utf8" 31 32 "github.com/golang/protobuf/ptypes/wrappers" 33 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 34 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 35 "go.uber.org/zap" 36 "google.golang.org/protobuf/types/known/wrapperspb" 37 38 api "github.com/polarismesh/polaris/common/api/v1" 39 "github.com/polarismesh/polaris/common/log" 40 ) 41 42 // some options config 43 const ( 44 // QueryDefaultOffset default query offset 45 QueryDefaultOffset = 0 46 // QueryDefaultLimit default query limit 47 QueryDefaultLimit = 100 48 // QueryMaxLimit default query max 49 QueryMaxLimit = 100 50 // MaxBatchSize max batch size 51 MaxBatchSize = 100 52 // MaxQuerySize max query size 53 MaxQuerySize = 100 54 55 // MaxMetadataLength metadata max length 56 MaxMetadataLength = 64 57 58 MaxBusinessLength = 64 59 MaxOwnersLength = 1024 60 MaxDepartmentLength = 1024 61 MaxCommentLength = 1024 62 MaxNameLength = 64 63 64 // service表 65 MaxDbServiceNameLength = 128 66 MaxDbServiceNamespaceLength = 64 67 MaxDbServicePortsLength = 8192 68 MaxDbServiceBusinessLength = 128 69 MaxDbServiceDeptLength = 1024 70 MaxDbServiceCMDBLength = 1024 71 MaxDbServiceCommentLength = 1024 72 MaxDbServiceOwnerLength = 1024 73 MaxDbServiceToken = 2048 74 75 // instance表 76 MaxDbInsHostLength = 128 77 MaxDbInsProtocolLength = 32 78 MaxDbInsVersionLength = 32 79 MaxDbInsLogicSetLength = 128 80 81 // circuitbreaker表 82 MaxDbCircuitbreakerName = 32 83 MaxDbCircuitbreakerNamespace = 64 84 MaxDbCircuitbreakerBusiness = 64 85 MaxDbCircuitbreakerDepartment = 1024 86 MaxDbCircuitbreakerComment = 1024 87 MaxDbCircuitbreakerOwner = 1024 88 MaxDbCircuitbreakerVersion = 32 89 ) 90 91 var resourceNameRE = regexp.MustCompile("^[0-9A-Za-z-./:_]+$") 92 93 // CheckResourceName 检查资源Name 94 func CheckResourceName(name *wrappers.StringValue) error { 95 if name == nil { 96 return errors.New(NilErrString) 97 } 98 99 if name.GetValue() == "" { 100 return errors.New(EmptyErrString) 101 } 102 103 if ok := resourceNameRE.MatchString(name.GetValue()); !ok { 104 return errors.New("name contains invalid character") 105 } 106 107 return nil 108 } 109 110 // CheckResourceOwners 检查资源Owners 111 func CheckResourceOwners(owners *wrappers.StringValue) error { 112 if owners == nil { 113 return errors.New(NilErrString) 114 } 115 116 if owners.GetValue() == "" { 117 return errors.New(EmptyErrString) 118 } 119 120 if utf8.RuneCountInString(owners.GetValue()) > MaxOwnersLength { 121 return errors.New("owners too long") 122 } 123 124 return nil 125 } 126 127 // CheckInstanceHost 检查服务实例Host 128 func CheckInstanceHost(host *wrappers.StringValue) error { 129 if host == nil { 130 return errors.New(NilErrString) 131 } 132 133 if host.GetValue() == "" { 134 return errors.New(EmptyErrString) 135 } 136 137 return nil 138 } 139 140 // CheckInstancePort 检查服务实例Port 141 func CheckInstancePort(port *wrappers.UInt32Value) error { 142 if port == nil { 143 return errors.New(NilErrString) 144 } 145 146 return nil 147 } 148 149 // CheckMetadata check metadata 150 // 检查metadata的个数 最大是64个 151 // key/value是否符合要求 152 func CheckMetadata(meta map[string]string) error { 153 if meta == nil { 154 return nil 155 } 156 157 if len(meta) > MaxMetadataLength { 158 return errors.New("metadata is too long") 159 } 160 161 /*regStr := "^[0-9A-Za-z-._*]+$" 162 matchFunc := func(str string) error { 163 if str == "" { 164 return nil 165 } 166 ok, err := regexp.MatchString(regStr, str) 167 if err != nil { 168 log.Errorf("regexp match string(%s) err: %s", str, err.Error()) 169 return err 170 } 171 if !ok { 172 log.Errorf("metadata string(%s) contains invalid character", str) 173 return errors.New("contain invalid character") 174 } 175 return nil 176 } 177 for key, value := range meta { 178 if err := matchFunc(key); err != nil { 179 return err 180 } 181 if err := matchFunc(value); err != nil { 182 return err 183 } 184 }*/ 185 186 return nil 187 } 188 189 // CheckQueryOffset 检查查询参数Offset 190 func CheckQueryOffset(offset []string) (int, error) { 191 if len(offset) == 0 { 192 return 0, nil 193 } 194 195 if len(offset) > 1 { 196 return 0, errors.New("unique") 197 } 198 199 value, err := strconv.Atoi(offset[0]) 200 if err != nil { 201 return 0, err 202 } 203 204 if value < 0 { 205 return 0, errors.New("invalid") 206 } 207 208 return value, nil 209 } 210 211 // CheckQueryLimit 检查查询参数Limit 212 func CheckQueryLimit(limit []string) (int, error) { 213 if len(limit) == 0 { 214 return MaxQuerySize, nil 215 } 216 217 if len(limit) > 1 { 218 return 0, errors.New("unique") 219 } 220 221 value, err := strconv.Atoi(limit[0]) 222 if err != nil { 223 return 0, err 224 } 225 226 if value < 0 { 227 return 0, errors.New("invalid") 228 } 229 230 if value > MaxQuerySize { 231 value = MaxQuerySize 232 } 233 234 return value, nil 235 } 236 237 // CalculateInstanceID 计算实例ID 238 func CalculateInstanceID(namespace string, service string, vpcID string, host string, port uint32) (string, error) { 239 h := sha1.New() 240 var str string 241 // 兼容带有vpcID的instance 242 if vpcID == "" { 243 str = fmt.Sprintf("%s##%s##%s##%d", namespace, service, host, port) 244 } else { 245 str = fmt.Sprintf("%s##%s##%s##%s##%d", namespace, service, vpcID, host, port) 246 } 247 248 if _, err := io.WriteString(h, str); err != nil { 249 return "", err 250 } 251 252 out := hex.EncodeToString(h.Sum(nil)) 253 return out, nil 254 } 255 256 // CalculateRuleID 计算规则ID 257 func CalculateRuleID(name, namespace string) string { 258 return name + "." + namespace 259 } 260 261 // ParseQueryOffset 格式化处理offset参数 262 func ParseQueryOffset(offset string) (uint32, error) { 263 if offset == "" { 264 return QueryDefaultOffset, nil 265 } 266 267 tmp, err := strconv.ParseUint(offset, 10, 32) 268 if err != nil { 269 log.Errorf("[Server][Query] attribute(offset:%s) is invalid, parse err: %s", 270 offset, err.Error()) 271 return 0, err 272 } 273 274 return uint32(tmp), nil 275 } 276 277 // ParseQueryLimit 格式化处理limit参数 278 func ParseQueryLimit(limit string) (uint32, error) { 279 if limit == "" { 280 return QueryDefaultLimit, nil 281 } 282 283 tmp, err := strconv.ParseUint(limit, 10, 32) 284 if err != nil { 285 log.Errorf("[Server][Query] attribute(offset:%s) is invalid, parse err: %s", 286 limit, err.Error()) 287 return 0, err 288 } 289 if tmp > QueryMaxLimit { 290 tmp = QueryMaxLimit 291 } 292 293 return uint32(tmp), nil 294 } 295 296 // ParseOffsetAndLimit 统一格式化处理Offset和limit参数 297 func ParseOffsetAndLimit(query map[string]string) (uint32, uint32, error) { 298 ofs, err := ParseQueryOffset(query["offset"]) 299 if err != nil { 300 return 0, 0, err 301 } 302 delete(query, "offset") 303 304 var lmt uint32 305 lmt, err = ParseQueryLimit(query["limit"]) 306 if err != nil { 307 return 0, 0, err 308 } 309 delete(query, "limit") 310 311 return ofs, lmt, nil 312 } 313 314 // ParseRequestID 从ctx中获取Request-ID 315 func ParseRequestID(ctx context.Context) string { 316 if ctx == nil { 317 return "" 318 } 319 rid, _ := ctx.Value(StringContext("request-id")).(string) 320 return rid 321 } 322 323 // ParseClientAddress 从ctx中获取客户端地址 324 func ParseClientAddress(ctx context.Context) string { 325 if ctx == nil { 326 return "" 327 } 328 rid, _ := ctx.Value(ContextClientAddress).(string) 329 return rid 330 } 331 332 // ParseAuthToken 从ctx中获取token 333 func ParseAuthToken(ctx context.Context) string { 334 if ctx == nil { 335 return "" 336 } 337 338 token, _ := ctx.Value(ContextAuthTokenKey).(string) 339 return token 340 } 341 342 // ParseIsOwner 从ctx中获取token 343 func ParseIsOwner(ctx context.Context) bool { 344 if ctx == nil { 345 return false 346 } 347 348 isOwner, _ := ctx.Value(ContextIsOwnerKey).(bool) 349 return isOwner 350 } 351 352 // ParseUserID 从ctx中解析用户ID 353 func ParseUserID(ctx context.Context) string { 354 if ctx == nil { 355 return "" 356 } 357 358 userID, _ := ctx.Value(ContextUserIDKey).(string) 359 return userID 360 } 361 362 // ParseUserName 从ctx解析用户名称 363 func ParseUserName(ctx context.Context) string { 364 if ctx == nil { 365 return "" 366 } 367 368 userName, _ := ctx.Value(ContextUserNameKey).(string) 369 if userName == "" { 370 return ParseOperator(ctx) 371 } 372 return userName 373 } 374 375 // ParseOwnerID 从ctx解析Owner ID 376 func ParseOwnerID(ctx context.Context) string { 377 if ctx == nil { 378 return "" 379 } 380 381 ownerID, _ := ctx.Value(ContextOwnerIDKey).(string) 382 return ownerID 383 } 384 385 // ParseToken 从ctx中获取token 386 func ParseToken(ctx context.Context) string { 387 if ctx == nil { 388 return "" 389 } 390 391 token, _ := ctx.Value(StringContext("polaris-token")).(string) 392 return token 393 } 394 395 // ParseOperator 从ctx中获取operator 396 func ParseOperator(ctx context.Context) string { 397 defaultOperator := "Polaris" 398 if ctx == nil { 399 return defaultOperator 400 } 401 402 if operator, _ := ctx.Value(ContextOperator).(string); operator != "" { 403 return operator 404 } 405 406 return defaultOperator 407 } 408 409 // ParsePlatformID 从ctx中获取Platform-Id 410 func ParsePlatformID(ctx context.Context) string { 411 if ctx == nil { 412 return "" 413 } 414 pid, _ := ctx.Value(StringContext("platform-id")).(string) 415 return pid 416 } 417 418 // ParsePlatformToken 从ctx中获取Platform-Token 419 func ParsePlatformToken(ctx context.Context) string { 420 if ctx == nil { 421 return "" 422 } 423 pToken, _ := ctx.Value(StringContext("platform-token")).(string) 424 return pToken 425 } 426 427 // ZapRequestID 生成Request-ID的日志描述 428 func ZapRequestID(id string) zap.Field { 429 return zap.String("request-id", id) 430 } 431 432 // RequestID 从ctx中获取Request-ID 433 func RequestID(ctx context.Context) zap.Field { 434 return zap.String("request-id", ParseRequestID(ctx)) 435 } 436 437 // ZapPlatformID 生成Platform-ID的日志描述 438 func ZapPlatformID(id string) zap.Field { 439 return zap.String("platform-id", id) 440 } 441 442 // ZapInstanceID 生成instanceID的日志描述 443 func ZapInstanceID(id string) zap.Field { 444 return zap.String("instance-id", id) 445 } 446 447 // ZapNamespace 生成namespace的日志描述 448 func ZapNamespace(namespace string) zap.Field { 449 return zap.String("namesapce", namespace) 450 } 451 452 // ZapGroup 生成group的日志描述 453 func ZapGroup(group string) zap.Field { 454 return zap.String("group", group) 455 } 456 457 // ZapFileName 生成fileName的日志描述 458 func ZapFileName(fileName string) zap.Field { 459 return zap.String("file-name", fileName) 460 } 461 462 // ZapReleaseName 生成fileName的日志描述 463 func ZapReleaseName(fileName string) zap.Field { 464 return zap.String("release-name", fileName) 465 } 466 467 // CheckDbStrFieldLen 检查name字段是否超过DB中对应字段的最大字符长度限制 468 func CheckDbStrFieldLen(param *wrappers.StringValue, dbLen int) error { 469 return CheckDbRawStrFieldLen(param.GetValue(), dbLen) 470 } 471 472 // CheckDbRawStrFieldLen 检查name字段是否超过DB中对应字段的最大字符长度限制 473 func CheckDbRawStrFieldLen(param string, dbLen int) error { 474 if param != "" && utf8.RuneCountInString(param) > dbLen { 475 errMsg := fmt.Sprintf("length of %s is over %d", param, dbLen) 476 return errors.New(errMsg) 477 } 478 return nil 479 } 480 481 // CheckDbMetaDataFieldLen 检查metadata的K,V是否超过DB中对应字段的最大字符长度限制 482 func CheckDbMetaDataFieldLen(metaData map[string]string) error { 483 for k, v := range metaData { 484 if utf8.RuneCountInString(k) > 128 || utf8.RuneCountInString(v) > 4096 { 485 errMsg := fmt.Sprintf("metadata:length of key(%s) or value(%s) is over size(key:128,value:4096)", 486 k, v) 487 return errors.New(errMsg) 488 } 489 } 490 return nil 491 } 492 493 // CheckInstanceTetrad 根据服务实例四元组计算ID 494 func CheckInstanceTetrad(req *apiservice.Instance) (string, *apiservice.Response) { 495 if err := CheckResourceName(req.GetService()); err != nil { 496 return "", api.NewInstanceResponse(apimodel.Code_InvalidServiceName, req) 497 } 498 499 if err := CheckResourceName(req.GetNamespace()); err != nil { 500 return "", api.NewInstanceResponse(apimodel.Code_InvalidNamespaceName, req) 501 } 502 503 if err := CheckInstanceHost(req.GetHost()); err != nil { 504 return "", api.NewInstanceResponse(apimodel.Code_InvalidInstanceHost, req) 505 } 506 507 if err := CheckInstancePort(req.GetPort()); err != nil { 508 return "", api.NewInstanceResponse(apimodel.Code_InvalidInstancePort, req) 509 } 510 511 var instID = req.GetId().GetValue() 512 if len(instID) == 0 { 513 id, err := CalculateInstanceID( 514 req.GetNamespace().GetValue(), 515 req.GetService().GetValue(), 516 req.GetVpcId().GetValue(), 517 req.GetHost().GetValue(), 518 req.GetPort().GetValue(), 519 ) 520 if err != nil { 521 return "", api.NewInstanceResponse(apimodel.Code_ExecuteException, req) 522 } 523 instID = id 524 } 525 return instID, nil 526 } 527 528 // ConvertStringValuesToSlice 转换StringValues为字符串切片 529 func ConvertStringValuesToSlice(vals []*wrapperspb.StringValue) []string { 530 ret := make([]string, 0, 4) 531 532 for index := range vals { 533 id := vals[index] 534 if strings.TrimSpace(id.GetValue()) == "" { 535 continue 536 } 537 ret = append(ret, id.GetValue()) 538 } 539 540 return ret 541 }