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  }