pkg/admin/model/condition_rule.go (241 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package model import ( "net/http" "strings" ) import ( mesh_proto "github.com/apache/dubbo-kubernetes/api/mesh/v1alpha1" "github.com/apache/dubbo-kubernetes/pkg/core/consts" ) type SearchConditionRuleReq struct { Keywords string `json:"keywords"` PageReq } func NewSearchConditionRuleReq() *SearchConditionRuleReq { return &SearchConditionRuleReq{ PageReq: PageReq{PageSize: 15}, } } type ConditionRuleSearchResp struct { CreateTime string `json:"createTime"` Enabled bool `json:"enabled"` RuleName string `json:"ruleName"` Scope string `json:"scope"` } type ConditionRuleResp struct { Conditions []string `json:"conditions"` ConfigVersion string `json:"configVersion"` Enabled bool `json:"enabled"` Key string `json:"key"` Runtime bool `json:"runtime"` Scope string `json:"scope"` } type ServiceArgumentRoute struct { Routes []ServiceArgument `json:"routes"` } type ServiceArgument struct { Conditions []RouteCondition `json:"conditions"` Destinations []Destination `json:"destinations"` Method string `json:"method"` } func (s *ServiceArgument) toFrom() *mesh_proto.ConditionRuleFrom { res := "method=" + s.Method if len(s.Conditions) != 0 { for i := 0; len(s.Conditions) > i; i++ { res += " & " + s.Conditions[i].string() } } return &mesh_proto.ConditionRuleFrom{ Match: res, } } func (s *ServiceArgument) toTo() []*mesh_proto.ConditionRuleTo { res := make([]*mesh_proto.ConditionRuleTo, 0, len(s.Destinations)) for _, destination := range s.Destinations { match := "" for _, condition := range destination.Conditions { if match == "" { match += condition.string() } else { match += " & " + condition.string() } } res = append(res, &mesh_proto.ConditionRuleTo{ Match: match, Weight: destination.Weight, }) } return res } type RouteCondition struct { Index string `json:"index"` Relation string `json:"relation"` Value string `json:"value"` } func (r *RouteCondition) string() string { if r.Relation == consts.Equal { return "arguments[" + r.Index + "]" + consts.Equal + r.Value } else { return "arguments[" + r.Index + "]" + consts.NotEqual + r.Value } } type Destination struct { Conditions []DestinationCondition `json:"conditions"` Weight int32 `json:"weight"` } type DestinationCondition struct { Relation string `json:"relation"` Tag string `json:"tag"` Value string `json:"value"` } func (d *DestinationCondition) string() string { if d.Relation == consts.Equal { return d.Tag + consts.Equal + d.Value } else { return d.Tag + consts.NotEqual + d.Value } } func (s *ServiceArgumentRoute) ToConditionV3x1Condition() []*mesh_proto.ConditionRule { res := make([]*mesh_proto.ConditionRule, 0, len(s.Routes)) for _, route := range s.Routes { res = append(res, &mesh_proto.ConditionRule{ From: route.toFrom(), To: route.toTo(), }) } return res } func ConditionV3x1ToServiceArgumentRoute(mesh []*mesh_proto.ConditionRule) *ServiceArgumentRoute { res := &ServiceArgumentRoute{ Routes: make([]ServiceArgument, 0, len(mesh)), } for i := range mesh { method, _ := mesh[i].IsMatchMethod() cond := ServiceArgument{ Conditions: matchValueToRouteCondition(mesh[i].From.Match), Destinations: make([]Destination, 0, len(mesh[i].To)), Method: method, } for _, to := range mesh[i].To { cond.Destinations = append(cond.Destinations, Destination{ Conditions: matchValueToDestinationCondition(to.Match), Weight: to.Weight, }) } res.Routes = append(res.Routes, cond) } return res } func matchValueToRouteCondition(val string) []RouteCondition { subsets := strings.Split(val, "&") res := make([]RouteCondition, 0, len(subsets)) for _, subset := range subsets { if index := strings.Index(subset, consts.NotEqual); index != -1 { res = append(res, RouteCondition{ Index: strings.Trim(subset[:index], " "), Relation: consts.NotEqual, Value: strings.Trim(subset[index+len(consts.NotEqual):], " "), }) } else if index := strings.Index(subset, consts.Equal); index != -1 { res = append(res, RouteCondition{ Index: strings.Trim(subset[:index], " "), Relation: consts.Equal, Value: strings.Trim(subset[index+len(consts.Equal):], " "), }) } } return res } func matchValueToDestinationCondition(val string) []DestinationCondition { subsets := strings.Split(val, "&") res := make([]DestinationCondition, 0, len(subsets)) for _, subset := range subsets { if index := strings.Index(subset, consts.NotEqual); index != -1 { res = append(res, DestinationCondition{ Tag: strings.Trim(subset[:index], " "), Relation: consts.NotEqual, Value: strings.Trim(subset[index+len(consts.NotEqual):], " "), }) } else if index := strings.Index(subset, consts.Equal); index != -1 { res = append(res, DestinationCondition{ Tag: strings.Trim(subset[:index], " "), Relation: consts.Equal, Value: strings.Trim(subset[index+len(consts.Equal):], " "), }) } } return res } func GenConditionRuleToResp(data *mesh_proto.ConditionRoute) *CommonResp { if data == nil { return &CommonResp{ Code: http.StatusNotFound, Msg: "not found", Data: map[string]string{}, } } if pb := data.ToConditionRouteV3(); pb != nil { return NewSuccessResp(ConditionRuleResp{ Conditions: pb.Conditions, ConfigVersion: pb.ConfigVersion, Enabled: pb.Enabled, Key: pb.Key, Runtime: pb.Runtime, Scope: pb.Scope, }) } else if pb := data.ToConditionRouteV3x1(); pb != nil { res := ConditionRuleV3X1{ Conditions: make([]Condition, 0, len(pb.Conditions)), ConfigVersion: "v3.1", Enabled: pb.Enabled, Force: pb.Force, Key: pb.Key, Runtime: pb.Runtime, Scope: pb.Scope, } for _, condition := range pb.Conditions { resCondition := Condition{ From: ConditionFrom{Match: condition.From.Match}, To: make([]ConditionTo, 0, len(condition.To)), } for _, to := range condition.To { resCondition.To = append(resCondition.To, ConditionTo{ Match: to.Match, Weight: to.Weight, }) } res.Conditions = append(res.Conditions, resCondition) } return NewSuccessResp(res) } else { return &CommonResp{ Code: http.StatusInternalServerError, Msg: "invalid condition rule", Data: data, } } } type ConditionRuleV3X1 struct { Conditions []Condition `json:"conditions"` ConfigVersion string `json:"configVersion"` Enabled bool `json:"enabled"` Force bool `json:"force"` Key string `json:"key"` Runtime bool `json:"runtime"` Scope string `json:"scope"` } type AffinityAware struct { Enabled bool `json:"enabled"` Key string `json:"key"` } type Condition struct { From ConditionFrom `json:"from"` To []ConditionTo `json:"to"` } type ConditionFrom struct { Match string `json:"match"` } type ConditionTo struct { Match string `json:"match"` Weight int32 `json:"weight"` }