github.com/polarismesh/polaris@v1.17.8/common/model/routing.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 model
    19  
    20  import (
    21  	"encoding/json"
    22  	"fmt"
    23  	"sort"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"github.com/golang/protobuf/ptypes"
    29  	apimodel "github.com/polarismesh/specification/source/go/api/v1/model"
    30  	apitraffic "github.com/polarismesh/specification/source/go/api/v1/traffic_manage"
    31  	protoV2 "google.golang.org/protobuf/proto"
    32  	"google.golang.org/protobuf/types/known/anypb"
    33  
    34  	commontime "github.com/polarismesh/polaris/common/time"
    35  	"github.com/polarismesh/polaris/common/utils"
    36  )
    37  
    38  const (
    39  	// V2RuleIDKey v2 版本的规则路由 ID
    40  	V2RuleIDKey = "__routing_v2_id__"
    41  	// V1RuleIDKey v1 版本的路由规则 ID
    42  	V1RuleIDKey = "__routing_v1_id__"
    43  	// V1RuleRouteIndexKey v1 版本 route 规则在自己 route 链中的 index 信息
    44  	V1RuleRouteIndexKey = "__routing_v1_route_index__"
    45  	// V1RuleRouteTypeKey 标识当前 v2 路由规则在 v1 的 inBound 还是 outBound
    46  	V1RuleRouteTypeKey = "__routing_v1_route_type__"
    47  	// V1RuleInRoute inBound 类型
    48  	V1RuleInRoute = "in"
    49  	// V1RuleOutRoute outBound 类型
    50  	V1RuleOutRoute = "out"
    51  )
    52  
    53  var (
    54  	// RuleRoutingTypeUrl 记录 anypb.Any 中关于 RuleRoutingConfig 的 url 信息
    55  	RuleRoutingTypeUrl string
    56  	// MetaRoutingTypeUrl 记录 anypb.Any 中关于 MetadataRoutingConfig 的 url 信息
    57  	MetaRoutingTypeUrl string
    58  )
    59  
    60  func init() {
    61  	ruleAny, _ := ptypes.MarshalAny(&apitraffic.RuleRoutingConfig{})
    62  	metaAny, _ := ptypes.MarshalAny(&apitraffic.MetadataRoutingConfig{})
    63  
    64  	RuleRoutingTypeUrl = ruleAny.GetTypeUrl()
    65  	MetaRoutingTypeUrl = metaAny.GetTypeUrl()
    66  }
    67  
    68  /*
    69   * RoutingConfig 路由配置
    70   */
    71  type RoutingConfig struct {
    72  	ID         string
    73  	InBounds   string
    74  	OutBounds  string
    75  	Revision   string
    76  	Valid      bool
    77  	CreateTime time.Time
    78  	ModifyTime time.Time
    79  }
    80  
    81  // ExtendRoutingConfig 路由配置的扩展结构体
    82  type ExtendRoutingConfig struct {
    83  	ServiceName   string
    84  	NamespaceName string
    85  	Config        *RoutingConfig
    86  }
    87  
    88  // ExtendRouterConfig 路由信息的扩展
    89  type ExtendRouterConfig struct {
    90  	*RouterConfig
    91  	// MetadataRouting 元数据路由配置
    92  	MetadataRouting *apitraffic.MetadataRoutingConfig
    93  	// RuleRouting 规则路由配置
    94  	RuleRouting *apitraffic.RuleRoutingConfig
    95  	// ExtendInfo 额外信息数据
    96  	ExtendInfo map[string]string
    97  }
    98  
    99  // ToApi Turn to API object
   100  func (r *ExtendRouterConfig) ToApi() (*apitraffic.RouteRule, error) {
   101  	var (
   102  		anyValue *anypb.Any
   103  		err      error
   104  	)
   105  
   106  	if r.GetRoutingPolicy() == apitraffic.RoutingPolicy_MetadataPolicy {
   107  		anyValue, err = ptypes.MarshalAny(r.MetadataRouting)
   108  		if err != nil {
   109  			return nil, err
   110  		}
   111  	} else {
   112  		anyValue, err = ptypes.MarshalAny(r.RuleRouting)
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  	}
   117  
   118  	rule := &apitraffic.RouteRule{
   119  		Id:            r.ID,
   120  		Name:          r.Name,
   121  		Namespace:     r.Namespace,
   122  		Enable:        r.Enable,
   123  		RoutingPolicy: r.GetRoutingPolicy(),
   124  		RoutingConfig: anyValue,
   125  		Revision:      r.Revision,
   126  		Ctime:         commontime.Time2String(r.CreateTime),
   127  		Mtime:         commontime.Time2String(r.ModifyTime),
   128  		Etime:         commontime.Time2String(r.EnableTime),
   129  		Priority:      r.Priority,
   130  		Description:   r.Description,
   131  	}
   132  	if r.EnableTime.Year() > 2000 {
   133  		rule.Etime = commontime.Time2String(r.EnableTime)
   134  	} else {
   135  		rule.Etime = ""
   136  	}
   137  	return rule, nil
   138  }
   139  
   140  // RouterConfig Routing rules
   141  type RouterConfig struct {
   142  	// ID The unique id of the rules
   143  	ID string `json:"id"`
   144  	// namespace router config owner namespace
   145  	Namespace string `json:"namespace"`
   146  	// name router config name
   147  	Name string `json:"name"`
   148  	// policy Rules
   149  	Policy string `json:"policy"`
   150  	// config Specific routing rules content
   151  	Config string `json:"config"`
   152  	// enable Whether the routing rules are enabled
   153  	Enable bool `json:"enable"`
   154  	// priority Rules priority
   155  	Priority uint32 `json:"priority"`
   156  	// revision Edition information of routing rules
   157  	Revision string `json:"revision"`
   158  	// Description Simple description of rules
   159  	Description string `json:"description"`
   160  	// valid Whether the routing rules are valid and have not been deleted by logic
   161  	Valid bool `json:"flag"`
   162  	// createtime Rules creation time
   163  	CreateTime time.Time `json:"ctime"`
   164  	// modifytime Rules modify time
   165  	ModifyTime time.Time `json:"mtime"`
   166  	// enabletime The last time the rules enabled
   167  	EnableTime time.Time `json:"etime"`
   168  }
   169  
   170  // GetRoutingPolicy Query routing rules type
   171  func (r *RouterConfig) GetRoutingPolicy() apitraffic.RoutingPolicy {
   172  	v, ok := apitraffic.RoutingPolicy_value[r.Policy]
   173  
   174  	if !ok {
   175  		return apitraffic.RoutingPolicy(-1)
   176  	}
   177  
   178  	return apitraffic.RoutingPolicy(v)
   179  }
   180  
   181  // ToExpendRoutingConfig Converted to an expansion object, serialize the corresponding PB Struct in advance
   182  func (r *RouterConfig) ToExpendRoutingConfig() (*ExtendRouterConfig, error) {
   183  	ret := &ExtendRouterConfig{
   184  		RouterConfig: r,
   185  	}
   186  
   187  	configText := r.Config
   188  	if len(configText) == 0 {
   189  		return ret, nil
   190  	}
   191  	policy := r.GetRoutingPolicy()
   192  	var err error
   193  	if strings.HasPrefix(configText, "{") {
   194  		// process with json
   195  		switch policy {
   196  		case apitraffic.RoutingPolicy_RulePolicy:
   197  			rule := &apitraffic.RuleRoutingConfig{}
   198  			if err = utils.UnmarshalFromJsonString(rule, configText); nil != err {
   199  				return nil, err
   200  			}
   201  			parseSubRouteRule(rule)
   202  			ret.RuleRouting = rule
   203  			break
   204  		case apitraffic.RoutingPolicy_MetadataPolicy:
   205  			rule := &apitraffic.MetadataRoutingConfig{}
   206  			if err = utils.UnmarshalFromJsonString(rule, configText); nil != err {
   207  				return nil, err
   208  			}
   209  			ret.MetadataRouting = rule
   210  			break
   211  		}
   212  		return ret, nil
   213  	}
   214  
   215  	if err := r.parseBinaryAnyMessage(policy, ret); err != nil {
   216  		return nil, err
   217  	}
   218  	return ret, nil
   219  }
   220  
   221  func (r *RouterConfig) parseBinaryAnyMessage(
   222  	policy apitraffic.RoutingPolicy, ret *ExtendRouterConfig) error {
   223  	// parse v1 binary
   224  	switch policy {
   225  	case apitraffic.RoutingPolicy_RulePolicy:
   226  		rule := &apitraffic.RuleRoutingConfig{}
   227  		anyMsg := &anypb.Any{
   228  			TypeUrl: RuleRoutingTypeUrl,
   229  			Value:   []byte(r.Config),
   230  		}
   231  		if err := unmarshalToAny(anyMsg, rule); nil != err {
   232  			return err
   233  		}
   234  		parseSubRouteRule(rule)
   235  		ret.RuleRouting = rule
   236  	case apitraffic.RoutingPolicy_MetadataPolicy:
   237  		rule := &apitraffic.MetadataRoutingConfig{}
   238  		anyMsg := &anypb.Any{
   239  			TypeUrl: MetaRoutingTypeUrl,
   240  			Value:   []byte(r.Config),
   241  		}
   242  		if err := unmarshalToAny(anyMsg, rule); nil != err {
   243  			return err
   244  		}
   245  		ret.MetadataRouting = rule
   246  	}
   247  	return nil
   248  }
   249  
   250  // ParseRouteRuleFromAPI Convert an internal object from the API object
   251  func (r *RouterConfig) ParseRouteRuleFromAPI(routing *apitraffic.RouteRule) error {
   252  	ruleMessage, err := ParseRouteRuleAnyToMessage(routing.RoutingPolicy, routing.RoutingConfig)
   253  	if nil != err {
   254  		return err
   255  	}
   256  
   257  	if r.Config, err = utils.MarshalToJsonString(ruleMessage); nil != err {
   258  		return err
   259  	}
   260  	r.ID = routing.Id
   261  	r.Revision = routing.Revision
   262  	r.Name = routing.Name
   263  	r.Namespace = routing.Namespace
   264  	r.Enable = routing.Enable
   265  	r.Policy = routing.GetRoutingPolicy().String()
   266  	r.Priority = routing.Priority
   267  	r.Description = routing.Description
   268  
   269  	// Priority range range [0, 10]
   270  	if r.Priority > 10 {
   271  		r.Priority = 10
   272  	}
   273  
   274  	return nil
   275  }
   276  
   277  func unmarshalToAny(anyMessage *anypb.Any, message proto.Message) error {
   278  	return anypb.UnmarshalTo(anyMessage, proto.MessageV2(message),
   279  		protoV2.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true})
   280  }
   281  
   282  // ParseRouteRuleAnyToMessage convert the any routing proto to message object
   283  func ParseRouteRuleAnyToMessage(policy apitraffic.RoutingPolicy, anyMessage *anypb.Any) (proto.Message, error) {
   284  	var rule proto.Message
   285  	switch policy {
   286  	case apitraffic.RoutingPolicy_RulePolicy:
   287  		rule = &apitraffic.RuleRoutingConfig{}
   288  		if err := unmarshalToAny(anyMessage, rule); err != nil {
   289  			return nil, err
   290  		}
   291  		ruleRouting := rule.(*apitraffic.RuleRoutingConfig)
   292  		parseSubRouteRule(ruleRouting)
   293  		break
   294  	case apitraffic.RoutingPolicy_MetadataPolicy:
   295  		rule = &apitraffic.MetadataRoutingConfig{}
   296  		if err := unmarshalToAny(anyMessage, rule); err != nil {
   297  			return nil, err
   298  		}
   299  		break
   300  	default:
   301  		break
   302  	}
   303  	return rule, nil
   304  }
   305  
   306  func parseSubRouteRule(ruleRouting *apitraffic.RuleRoutingConfig) {
   307  	if len(ruleRouting.Rules) == 0 {
   308  		subRule := &apitraffic.SubRuleRouting{
   309  			Name:         "",
   310  			Sources:      ruleRouting.GetSources(),
   311  			Destinations: ruleRouting.GetDestinations(),
   312  		}
   313  		ruleRouting.Rules = []*apitraffic.SubRuleRouting{
   314  			subRule,
   315  		}
   316  	} else {
   317  		for i := range ruleRouting.Rules {
   318  			subRule := ruleRouting.Rules[i]
   319  			if len(subRule.Sources) == 0 {
   320  				subRule.Sources = ruleRouting.GetSources()
   321  			}
   322  			if len(subRule.Destinations) == 0 {
   323  				subRule.Destinations = ruleRouting.GetDestinations()
   324  			}
   325  		}
   326  		// Abandon the value of the old field
   327  		ruleRouting.Destinations = nil
   328  		ruleRouting.Sources = nil
   329  	}
   330  }
   331  
   332  const (
   333  	_labelKeyPath     = "$path"
   334  	_labelKeyMethod   = "$method"
   335  	_labelKeyHeader   = "$header"
   336  	_labelKeyQuery    = "$query"
   337  	_labelKeyCallerIP = "$caller_ip"
   338  	_labelKeyCookie   = "$cookie"
   339  
   340  	MatchAll = "*"
   341  )
   342  
   343  // RoutingConfigV1ToAPI Convert the internal data structure to API parameter to pass out
   344  func RoutingConfigV1ToAPI(req *RoutingConfig, service string, namespace string) (*apitraffic.Routing, error) {
   345  	if req == nil {
   346  		return nil, nil
   347  	}
   348  
   349  	out := &apitraffic.Routing{
   350  		Service:   utils.NewStringValue(service),
   351  		Namespace: utils.NewStringValue(namespace),
   352  		Revision:  utils.NewStringValue(req.Revision),
   353  		Ctime:     utils.NewStringValue(commontime.Time2String(req.CreateTime)),
   354  		Mtime:     utils.NewStringValue(commontime.Time2String(req.ModifyTime)),
   355  	}
   356  
   357  	if req.InBounds != "" {
   358  		var inBounds []*apitraffic.Route
   359  		if err := json.Unmarshal([]byte(req.InBounds), &inBounds); err != nil {
   360  			return nil, err
   361  		}
   362  		out.Inbounds = inBounds
   363  	}
   364  	if req.OutBounds != "" {
   365  		var outBounds []*apitraffic.Route
   366  		if err := json.Unmarshal([]byte(req.OutBounds), &outBounds); err != nil {
   367  			return nil, err
   368  		}
   369  		out.Outbounds = outBounds
   370  	}
   371  
   372  	return out, nil
   373  }
   374  
   375  // CompositeRoutingV1AndV2 The routing rules of the V1 version and the rules of the V2 version
   376  func CompositeRoutingV1AndV2(v1rule *apitraffic.Routing, level1, level2,
   377  	level3 []*ExtendRouterConfig) (*apitraffic.Routing, []string) {
   378  	sort.Slice(level1, func(i, j int) bool {
   379  		return CompareRoutingV2(level1[i], level1[j])
   380  	})
   381  
   382  	sort.Slice(level2, func(i, j int) bool {
   383  		return CompareRoutingV2(level2[i], level2[j])
   384  	})
   385  
   386  	sort.Slice(level3, func(i, j int) bool {
   387  		return CompareRoutingV2(level3[i], level3[j])
   388  	})
   389  
   390  	level1inRoutes, level1outRoutes, level1Revisions :=
   391  		BuildV1RoutesFromV2(v1rule.Service.Value, v1rule.Namespace.Value, level1)
   392  	level2inRoutes, level2outRoutes, level2Revisions :=
   393  		BuildV1RoutesFromV2(v1rule.Service.Value, v1rule.Namespace.Value, level2)
   394  	level3inRoutes, level3outRoutes, level3Revisions :=
   395  		BuildV1RoutesFromV2(v1rule.Service.Value, v1rule.Namespace.Value, level3)
   396  
   397  	inBounds := v1rule.GetInbounds()
   398  	outBounds := v1rule.GetOutbounds()
   399  
   400  	// Processing inbounds rules,level1 cache -> v1rules -> level2 cache -> level3 cache
   401  	if len(level1inRoutes) > 0 {
   402  		v1rule.Inbounds = append(level1inRoutes, inBounds...)
   403  	}
   404  	if len(level2inRoutes) > 0 {
   405  		v1rule.Inbounds = append(v1rule.Inbounds, level2inRoutes...)
   406  	}
   407  	if len(level3inRoutes) > 0 {
   408  		v1rule.Inbounds = append(v1rule.Inbounds, level3inRoutes...)
   409  	}
   410  
   411  	// Processing OutBounds rules,level1 cache -> v1rules -> level2 cache -> level3 cache
   412  	if len(level1outRoutes) > 0 {
   413  		v1rule.Outbounds = append(level1outRoutes, outBounds...)
   414  	}
   415  	if len(level2outRoutes) > 0 {
   416  		v1rule.Outbounds = append(v1rule.Outbounds, level2outRoutes...)
   417  	}
   418  	if len(level3outRoutes) > 0 {
   419  		v1rule.Outbounds = append(v1rule.Outbounds, level3outRoutes...)
   420  	}
   421  
   422  	revisions := make([]string, 0, 1+len(level1Revisions)+len(level2Revisions)+len(level3Revisions))
   423  	revisions = append(revisions, v1rule.GetRevision().GetValue())
   424  	if len(level1Revisions) > 0 {
   425  		revisions = append(revisions, level1Revisions...)
   426  	}
   427  	if len(level2Revisions) > 0 {
   428  		revisions = append(revisions, level2Revisions...)
   429  	}
   430  	if len(level3Revisions) > 0 {
   431  		revisions = append(revisions, level3Revisions...)
   432  	}
   433  
   434  	return v1rule, revisions
   435  }
   436  
   437  // BuildV1RoutesFromV2 According to the routing rules of the V2 version, it is adapted to the V1 version
   438  // of the routing rules.
   439  // return inBound outBound revisions
   440  func BuildV1RoutesFromV2(service, namespace string,
   441  	entries []*ExtendRouterConfig) ([]*apitraffic.Route, []*apitraffic.Route, []string) {
   442  	if len(entries) == 0 {
   443  		return []*apitraffic.Route{}, []*apitraffic.Route{}, []string{}
   444  	}
   445  
   446  	revisions := make([]string, 0, len(entries))
   447  	outRoutes := make([]*apitraffic.Route, 0, 8)
   448  	inRoutes := make([]*apitraffic.Route, 0, 8)
   449  	for i := range entries {
   450  		if !entries[i].Enable {
   451  			continue
   452  		}
   453  		outRoutes = append(outRoutes, BuildOutBoundsFromV2(service, namespace, entries[i])...)
   454  		inRoutes = append(inRoutes, BuildInBoundsFromV2(service, namespace, entries[i])...)
   455  		revisions = append(revisions, entries[i].Revision)
   456  	}
   457  
   458  	return inRoutes, outRoutes, revisions
   459  }
   460  
   461  // BuildOutBoundsFromV2 According to the routing rules of the V2 version, it is adapted to the
   462  // outbounds in the routing rule of V1 version
   463  func BuildOutBoundsFromV2(service, namespace string, item *ExtendRouterConfig) []*apitraffic.Route {
   464  	if item.GetRoutingPolicy() != apitraffic.RoutingPolicy_RulePolicy {
   465  		return []*apitraffic.Route{}
   466  	}
   467  
   468  	var find bool
   469  
   470  	matchService := func(source *apitraffic.SourceService) bool {
   471  		if source.Service == service && source.Namespace == namespace {
   472  			return true
   473  		}
   474  		if source.Namespace == namespace && source.Service == MatchAll {
   475  			return true
   476  		}
   477  		if source.Namespace == MatchAll && source.Service == MatchAll {
   478  			return true
   479  		}
   480  		return false
   481  	}
   482  
   483  	routes := make([]*apitraffic.Route, 0, 8)
   484  	for i := range item.RuleRouting.Rules {
   485  		subRule := item.RuleRouting.Rules[i]
   486  		sources := item.RuleRouting.Rules[i].Sources
   487  		v1sources := make([]*apitraffic.Source, 0, len(sources))
   488  		for i := range sources {
   489  			if matchService(sources[i]) {
   490  				find = true
   491  				entry := &apitraffic.Source{
   492  					Service:   utils.NewStringValue(service),
   493  					Namespace: utils.NewStringValue(namespace),
   494  				}
   495  				entry.Metadata = RoutingArguments2Labels(sources[i].GetArguments())
   496  				v1sources = append(v1sources, entry)
   497  			}
   498  		}
   499  
   500  		if !find {
   501  			break
   502  		}
   503  
   504  		destinations := item.RuleRouting.Rules[i].Destinations
   505  		v1destinations := make([]*apitraffic.Destination, 0, len(destinations))
   506  		for i := range destinations {
   507  			name := fmt.Sprintf("%s.%s.%s", item.Name, subRule.Name, destinations[i].Name)
   508  			entry := &apitraffic.Destination{
   509  				Name:      utils.NewStringValue(name),
   510  				Service:   utils.NewStringValue(destinations[i].Service),
   511  				Namespace: utils.NewStringValue(destinations[i].Namespace),
   512  				Priority:  utils.NewUInt32Value(destinations[i].GetPriority()),
   513  				Weight:    utils.NewUInt32Value(destinations[i].GetWeight()),
   514  				Transfer:  utils.NewStringValue(destinations[i].GetTransfer()),
   515  				Isolate:   utils.NewBoolValue(destinations[i].GetIsolate()),
   516  			}
   517  
   518  			v1labels := make(map[string]*apimodel.MatchString)
   519  			v2labels := destinations[i].GetLabels()
   520  			for index := range v2labels {
   521  				v1labels[index] = &apimodel.MatchString{
   522  					Type:      v2labels[index].GetType(),
   523  					Value:     v2labels[index].GetValue(),
   524  					ValueType: v2labels[index].GetValueType(),
   525  				}
   526  			}
   527  
   528  			entry.Metadata = v1labels
   529  			v1destinations = append(v1destinations, entry)
   530  		}
   531  
   532  		routes = append(routes, &apitraffic.Route{
   533  			Sources:      v1sources,
   534  			Destinations: v1destinations,
   535  			ExtendInfo: map[string]string{
   536  				V2RuleIDKey: item.ID,
   537  			},
   538  		})
   539  	}
   540  
   541  	return routes
   542  }
   543  
   544  // BuildInBoundsFromV2 Convert the routing rules of V2 to the inbounds in the routing rule of V1
   545  func BuildInBoundsFromV2(service, namespace string, item *ExtendRouterConfig) []*apitraffic.Route {
   546  	if item.GetRoutingPolicy() != apitraffic.RoutingPolicy_RulePolicy {
   547  		return []*apitraffic.Route{}
   548  	}
   549  
   550  	var find bool
   551  
   552  	matchService := func(destination *apitraffic.DestinationGroup) bool {
   553  		if destination.Service == service && destination.Namespace == namespace {
   554  			return true
   555  		}
   556  		if destination.Namespace == namespace && destination.Service == MatchAll {
   557  			return true
   558  		}
   559  		if destination.Namespace == MatchAll && destination.Service == MatchAll {
   560  			return true
   561  		}
   562  		return false
   563  	}
   564  
   565  	routes := make([]*apitraffic.Route, 0, 8)
   566  
   567  	for i := range item.RuleRouting.Rules {
   568  		subRule := item.RuleRouting.Rules[i]
   569  		destinations := item.RuleRouting.Rules[i].Destinations
   570  		v1destinations := make([]*apitraffic.Destination, 0, len(destinations))
   571  		for i := range destinations {
   572  			if matchService(destinations[i]) {
   573  				find = true
   574  				name := fmt.Sprintf("%s.%s.%s", item.Name, subRule.Name, destinations[i].Name)
   575  				entry := &apitraffic.Destination{
   576  					Name:      utils.NewStringValue(name),
   577  					Service:   utils.NewStringValue(service),
   578  					Namespace: utils.NewStringValue(namespace),
   579  					Priority:  utils.NewUInt32Value(destinations[i].GetPriority()),
   580  					Weight:    utils.NewUInt32Value(destinations[i].GetWeight()),
   581  					Transfer:  utils.NewStringValue(destinations[i].GetTransfer()),
   582  					Isolate:   utils.NewBoolValue(destinations[i].GetIsolate()),
   583  				}
   584  
   585  				v1labels := make(map[string]*apimodel.MatchString)
   586  				v2labels := destinations[i].GetLabels()
   587  				for index := range v2labels {
   588  					v1labels[index] = &apimodel.MatchString{
   589  						Type:      v2labels[index].GetType(),
   590  						Value:     v2labels[index].GetValue(),
   591  						ValueType: v2labels[index].GetValueType(),
   592  					}
   593  				}
   594  
   595  				entry.Metadata = v1labels
   596  				v1destinations = append(v1destinations, entry)
   597  			}
   598  		}
   599  
   600  		if !find {
   601  			break
   602  		}
   603  
   604  		sources := item.RuleRouting.Rules[i].Sources
   605  		v1sources := make([]*apitraffic.Source, 0, len(sources))
   606  		for i := range sources {
   607  			entry := &apitraffic.Source{
   608  				Service:   utils.NewStringValue(sources[i].Service),
   609  				Namespace: utils.NewStringValue(sources[i].Namespace),
   610  			}
   611  
   612  			entry.Metadata = RoutingArguments2Labels(sources[i].GetArguments())
   613  			v1sources = append(v1sources, entry)
   614  		}
   615  
   616  		routes = append(routes, &apitraffic.Route{
   617  			Sources:      v1sources,
   618  			Destinations: v1destinations,
   619  			ExtendInfo: map[string]string{
   620  				V2RuleIDKey: item.ID,
   621  			},
   622  		})
   623  	}
   624  
   625  	return routes
   626  }
   627  
   628  // RoutingLabels2Arguments Adapting the old label model into a list of parameters
   629  func RoutingLabels2Arguments(labels map[string]*apimodel.MatchString) []*apitraffic.SourceMatch {
   630  	if len(labels) == 0 {
   631  		return []*apitraffic.SourceMatch{}
   632  	}
   633  
   634  	arguments := make([]*apitraffic.SourceMatch, 0, 4)
   635  	for index := range labels {
   636  		arguments = append(arguments, &apitraffic.SourceMatch{
   637  			Type: apitraffic.SourceMatch_CUSTOM,
   638  			Key:  index,
   639  			Value: &apimodel.MatchString{
   640  				Type:      labels[index].GetType(),
   641  				Value:     labels[index].GetValue(),
   642  				ValueType: labels[index].GetValueType(),
   643  			},
   644  		})
   645  	}
   646  
   647  	return arguments
   648  }
   649  
   650  // RoutingArguments2Labels Adapt the parameter list to the old label model
   651  func RoutingArguments2Labels(args []*apitraffic.SourceMatch) map[string]*apimodel.MatchString {
   652  	labels := make(map[string]*apimodel.MatchString)
   653  	for i := range args {
   654  		argument := args[i]
   655  		var key string
   656  		switch argument.Type {
   657  		case apitraffic.SourceMatch_CUSTOM:
   658  			key = argument.Key
   659  		case apitraffic.SourceMatch_METHOD:
   660  			key = _labelKeyMethod
   661  		case apitraffic.SourceMatch_HEADER:
   662  			key = _labelKeyHeader + "." + argument.Key
   663  		case apitraffic.SourceMatch_QUERY:
   664  			key = _labelKeyQuery + "." + argument.Key
   665  		case apitraffic.SourceMatch_CALLER_IP:
   666  			key = _labelKeyCallerIP
   667  		case apitraffic.SourceMatch_COOKIE:
   668  			key = _labelKeyCookie + "." + argument.Key
   669  		case apitraffic.SourceMatch_PATH:
   670  			key = _labelKeyPath
   671  		default:
   672  			continue
   673  		}
   674  
   675  		labels[key] = &apimodel.MatchString{
   676  			Type:      argument.GetValue().GetType(),
   677  			Value:     argument.GetValue().GetValue(),
   678  			ValueType: argument.GetValue().GetValueType(),
   679  		}
   680  	}
   681  
   682  	return labels
   683  }
   684  
   685  // BuildV2RoutingFromV1Route Build a V2 version of API data object routing rules
   686  func BuildV2RoutingFromV1Route(req *apitraffic.Routing, route *apitraffic.Route) (*apitraffic.RouteRule, error) {
   687  	var v2Id string
   688  	if extendInfo := route.GetExtendInfo(); len(extendInfo) > 0 {
   689  		v2Id = extendInfo[V2RuleIDKey]
   690  	} else {
   691  		v2Id = utils.NewRoutingV2UUID()
   692  	}
   693  
   694  	rule := convertV1RouteToV2Route(route)
   695  	any, err := ptypes.MarshalAny(rule)
   696  	if err != nil {
   697  		return nil, err
   698  	}
   699  
   700  	routing := &apitraffic.RouteRule{
   701  		Id:            v2Id,
   702  		Name:          "",
   703  		Enable:        false,
   704  		RoutingPolicy: apitraffic.RoutingPolicy_RulePolicy,
   705  		RoutingConfig: any,
   706  		Revision:      utils.NewV2Revision(),
   707  		Priority:      0,
   708  	}
   709  
   710  	return routing, nil
   711  }
   712  
   713  // BuildV2ExtendRouting Build the internal data object routing rules of V2 version
   714  func BuildV2ExtendRouting(req *apitraffic.Routing, route *apitraffic.Route) (*ExtendRouterConfig, error) {
   715  	var v2Id string
   716  	if extendInfo := route.GetExtendInfo(); len(extendInfo) > 0 {
   717  		v2Id = extendInfo[V2RuleIDKey]
   718  	}
   719  	if v2Id == "" {
   720  		v2Id = utils.NewRoutingV2UUID()
   721  	}
   722  
   723  	routing := &ExtendRouterConfig{
   724  		RouterConfig: &RouterConfig{
   725  			ID:       v2Id,
   726  			Name:     v2Id,
   727  			Enable:   true,
   728  			Policy:   apitraffic.RoutingPolicy_RulePolicy.String(),
   729  			Revision: req.GetRevision().GetValue(),
   730  			Priority: 0,
   731  		},
   732  		RuleRouting: convertV1RouteToV2Route(route),
   733  	}
   734  
   735  	return routing, nil
   736  }
   737  
   738  // convertV1RouteToV2Route Turn the routing rules of the V1 version to the routing rules of V2 version
   739  func convertV1RouteToV2Route(route *apitraffic.Route) *apitraffic.RuleRoutingConfig {
   740  	v2sources := make([]*apitraffic.SourceService, 0, len(route.GetSources()))
   741  	v1sources := route.GetSources()
   742  	for i := range v1sources {
   743  		entry := &apitraffic.SourceService{
   744  			Service:   v1sources[i].GetService().GetValue(),
   745  			Namespace: v1sources[i].GetNamespace().GetValue(),
   746  		}
   747  
   748  		entry.Arguments = RoutingLabels2Arguments(v1sources[i].GetMetadata())
   749  		v2sources = append(v2sources, entry)
   750  	}
   751  
   752  	v2destinations := make([]*apitraffic.DestinationGroup, 0, len(route.GetDestinations()))
   753  	v1destinations := route.GetDestinations()
   754  	for i := range v1destinations {
   755  		entry := &apitraffic.DestinationGroup{
   756  			Service:   v1destinations[i].GetService().GetValue(),
   757  			Namespace: v1destinations[i].GetNamespace().GetValue(),
   758  			Priority:  v1destinations[i].GetPriority().GetValue(),
   759  			Weight:    v1destinations[i].GetWeight().GetValue(),
   760  			Transfer:  v1destinations[i].GetTransfer().GetValue(),
   761  			Isolate:   v1destinations[i].GetIsolate().GetValue(),
   762  		}
   763  
   764  		v2labels := make(map[string]*apimodel.MatchString)
   765  		v1labels := v1destinations[i].GetMetadata()
   766  		for index := range v1labels {
   767  			v2labels[index] = &apimodel.MatchString{
   768  				Type:      v1labels[index].GetType(),
   769  				Value:     v1labels[index].GetValue(),
   770  				ValueType: v1labels[index].GetValueType(),
   771  			}
   772  		}
   773  
   774  		entry.Labels = v2labels
   775  		v2destinations = append(v2destinations, entry)
   776  	}
   777  
   778  	return &apitraffic.RuleRoutingConfig{
   779  		Rules: []*apitraffic.SubRuleRouting{
   780  			{
   781  				Sources:      v2sources,
   782  				Destinations: v2destinations,
   783  			},
   784  		},
   785  	}
   786  }
   787  
   788  // CompareRoutingV2 Compare the priority of two routing.
   789  func CompareRoutingV2(a, b *ExtendRouterConfig) bool {
   790  	if a.Priority != b.Priority {
   791  		return a.Priority < b.Priority
   792  	}
   793  	return a.CreateTime.Before(b.CreateTime)
   794  }
   795  
   796  // ConvertRoutingV1ToExtendV2 The routing rules of the V1 version are converted to V2 version for storage
   797  // TODO Reduce duplicate code logic
   798  func ConvertRoutingV1ToExtendV2(svcName, svcNamespace string,
   799  	rule *RoutingConfig) ([]*ExtendRouterConfig, []*ExtendRouterConfig, error) {
   800  	inRet := make([]*ExtendRouterConfig, 0, 4)
   801  	outRet := make([]*ExtendRouterConfig, 0, 4)
   802  
   803  	if rule.InBounds != "" {
   804  		var inBounds []*apitraffic.Route
   805  		if err := json.Unmarshal([]byte(rule.InBounds), &inBounds); err != nil {
   806  			return nil, nil, err
   807  		}
   808  
   809  		priorityMax := 0
   810  
   811  		for i := range inBounds {
   812  			routing, err := BuildV2ExtendRouting(&apitraffic.Routing{
   813  				Namespace: utils.NewStringValue(svcNamespace),
   814  			}, inBounds[i])
   815  			if err != nil {
   816  				return nil, nil, err
   817  			}
   818  			routing.ID = fmt.Sprintf("%sin%d", rule.ID, i)
   819  			routing.Revision = rule.Revision
   820  			routing.Enable = true
   821  			routing.CreateTime = rule.CreateTime
   822  			routing.ModifyTime = rule.ModifyTime
   823  			routing.EnableTime = rule.CreateTime
   824  			routing.ExtendInfo = map[string]string{
   825  				V1RuleIDKey:         rule.ID,
   826  				V1RuleRouteIndexKey: fmt.Sprintf("%d", i),
   827  				V1RuleRouteTypeKey:  V1RuleInRoute,
   828  			}
   829  
   830  			if priorityMax > 10 {
   831  				priorityMax = 10
   832  			}
   833  
   834  			routing.Priority = uint32(priorityMax)
   835  			priorityMax++
   836  
   837  			inRet = append(inRet, routing)
   838  		}
   839  	}
   840  	if rule.OutBounds != "" {
   841  		var outBounds []*apitraffic.Route
   842  		if err := json.Unmarshal([]byte(rule.OutBounds), &outBounds); err != nil {
   843  			return nil, nil, err
   844  		}
   845  
   846  		priorityMax := 0
   847  
   848  		for i := range outBounds {
   849  			routing, err := BuildV2ExtendRouting(&apitraffic.Routing{
   850  				Namespace: utils.NewStringValue(svcNamespace),
   851  			}, outBounds[i])
   852  			if err != nil {
   853  				return nil, nil, err
   854  			}
   855  			routing.ID = fmt.Sprintf("%sout%d", rule.ID, i)
   856  			routing.Revision = rule.Revision
   857  			routing.CreateTime = rule.CreateTime
   858  			routing.ModifyTime = rule.ModifyTime
   859  			routing.EnableTime = rule.CreateTime
   860  			routing.ExtendInfo = map[string]string{
   861  				V1RuleIDKey:         rule.ID,
   862  				V1RuleRouteIndexKey: fmt.Sprintf("%d", i),
   863  				V1RuleRouteTypeKey:  V1RuleOutRoute,
   864  			}
   865  
   866  			if priorityMax > 10 {
   867  				priorityMax = 10
   868  			}
   869  
   870  			routing.Priority = uint32(priorityMax)
   871  			priorityMax++
   872  
   873  			outRet = append(outRet, routing)
   874  		}
   875  	}
   876  
   877  	return inRet, outRet, nil
   878  }