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 }