github.com/polarismesh/polaris@v1.17.8/service/routing_config_v1tov2.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 service 19 20 import ( 21 "context" 22 23 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 24 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 25 apitraffic "github.com/polarismesh/specification/source/go/api/v1/traffic_manage" 26 "go.uber.org/zap" 27 28 apiv1 "github.com/polarismesh/polaris/common/api/v1" 29 "github.com/polarismesh/polaris/common/model" 30 commonstore "github.com/polarismesh/polaris/common/store" 31 "github.com/polarismesh/polaris/common/utils" 32 ) 33 34 // createRoutingConfigV1toV2 Compatible with V1 version of the creation routing rules, convert V1 to V2 for storage 35 func (s *Server) createRoutingConfigV1toV2(ctx context.Context, req *apitraffic.Routing) *apiservice.Response { 36 if resp := checkRoutingConfig(req); resp != nil { 37 return resp 38 } 39 40 serviceName := req.GetService().GetValue() 41 namespaceName := req.GetNamespace().GetValue() 42 svc, errResp := s.loadService(namespaceName, serviceName) 43 if errResp != nil { 44 log.Error("[Service][Routing] get read lock for service", zap.String("service", serviceName), 45 zap.String("namespace", namespaceName), utils.RequestID(ctx), zap.Any("err", errResp)) 46 return apiv1.NewRoutingResponse(apimodel.Code(errResp.GetCode().GetValue()), req) 47 } 48 if svc == nil { 49 return apiv1.NewRoutingResponse(apimodel.Code_NotFoundService, req) 50 } 51 if svc.IsAlias() { 52 return apiv1.NewRoutingResponse(apimodel.Code_NotAllowAliasCreateRouting, req) 53 } 54 55 inDatas, outDatas, resp := batchBuildV2Routings(req) 56 if resp != nil { 57 return resp 58 } 59 60 resp = s.saveRoutingV1toV2(ctx, svc.ID, inDatas, outDatas) 61 if resp.GetCode().GetValue() != uint32(apimodel.Code_ExecuteSuccess) { 62 return resp 63 } 64 65 return apiv1.NewRoutingResponse(apimodel.Code_ExecuteSuccess, req) 66 } 67 68 // updateRoutingConfigV1toV2 Compatible with V1 version update routing rules, convert the data of V1 to V2 for storage 69 // Once the V1 rule is converted to V2 rules, the original V1 rules will be removed from storage 70 func (s *Server) updateRoutingConfigV1toV2(ctx context.Context, req *apitraffic.Routing) *apiservice.Response { 71 svc, resp := s.routingConfigCommonCheck(ctx, req) 72 if resp != nil { 73 return resp 74 } 75 76 serviceTx, err := s.storage.CreateTransaction() 77 if err != nil { 78 log.Error(err.Error(), utils.RequestID(ctx)) 79 return apiv1.NewRoutingResponse(commonstore.StoreCode2APICode(err), req) 80 } 81 // Release the lock for the service 82 defer func() { 83 _ = serviceTx.Commit() 84 }() 85 86 // Need to prohibit the concurrent modification of the V1 rules 87 if _, err = serviceTx.LockService(svc.Name, svc.Namespace); err != nil { 88 log.Error("[Service][Routing] get service x-lock", zap.String("service", svc.Name), 89 zap.String("namespace", svc.Namespace), utils.RequestID(ctx), zap.Error(err)) 90 return apiv1.NewRoutingResponse(commonstore.StoreCode2APICode(err), req) 91 } 92 93 conf, err := s.storage.GetRoutingConfigWithService(svc.Name, svc.Namespace) 94 if err != nil { 95 log.Error(err.Error(), utils.RequestID(ctx)) 96 return apiv1.NewRoutingResponse(commonstore.StoreCode2APICode(err), req) 97 } 98 if conf == nil { 99 return apiv1.NewRoutingResponse(apimodel.Code_NotFoundRouting, req) 100 } 101 102 inDatas, outDatas, resp := batchBuildV2Routings(req) 103 if resp != nil { 104 return resp 105 } 106 107 if resp := s.saveRoutingV1toV2(ctx, svc.ID, inDatas, outDatas); resp.GetCode().GetValue() != uint32( 108 apimodel.Code_ExecuteSuccess) { 109 return resp 110 } 111 112 return apiv1.NewRoutingResponse(apimodel.Code_ExecuteSuccess, req) 113 } 114 115 // saveRoutingV1toV2 Convert the V1 rules of the target to V2 rule 116 func (s *Server) saveRoutingV1toV2(ctx context.Context, svcId string, 117 inRules, outRules []*apitraffic.RouteRule) *apiservice.Response { 118 tx, err := s.storage.StartTx() 119 if err != nil { 120 log.Error("[Service][Routing] create routing v2 from v1 open tx", 121 utils.RequestID(ctx), zap.Error(err)) 122 return apiv1.NewResponse(commonstore.StoreCode2APICode(err)) 123 } 124 defer func() { 125 _ = tx.Rollback() 126 }() 127 128 // Need to delete the routing rules of V1 first 129 if err := s.storage.DeleteRoutingConfigTx(tx, svcId); err != nil { 130 log.Error("[Service][Routing] clean routing v1 from store", 131 utils.RequestID(ctx), zap.Error(err)) 132 return apiv1.NewResponse(commonstore.StoreCode2APICode(err)) 133 } 134 135 saveOperation := func(routings []*apitraffic.RouteRule) *apiservice.Response { 136 priorityMax := 0 137 for i := range routings { 138 item := routings[i] 139 if item.Id == "" { 140 item.Id = utils.NewRoutingV2UUID() 141 } 142 item.Revision = utils.NewV2Revision() 143 data := &model.RouterConfig{} 144 if err := data.ParseRouteRuleFromAPI(item); err != nil { 145 return apiv1.NewResponse(apimodel.Code_ExecuteException) 146 } 147 148 data.Valid = true 149 data.Enable = true 150 if priorityMax > 10 { 151 priorityMax = 10 152 } 153 154 data.Priority = uint32(priorityMax) 155 priorityMax++ 156 157 if err := s.storage.CreateRoutingConfigV2Tx(tx, data); err != nil { 158 log.Error("[Routing][V2] create routing v2 from v1 into store", 159 utils.RequestID(ctx), zap.Error(err)) 160 return apiv1.NewResponse(commonstore.StoreCode2APICode(err)) 161 } 162 s.RecordHistory(ctx, routingV2RecordEntry(ctx, item, data, model.OCreate)) 163 } 164 165 return nil 166 } 167 168 if resp := saveOperation(inRules); resp != nil { 169 return resp 170 } 171 if resp := saveOperation(outRules); resp != nil { 172 return resp 173 } 174 175 if err := tx.Commit(); err != nil { 176 log.Error("[Service][Routing] create routing v2 from v1 commit", 177 utils.RequestID(ctx), zap.Error(err)) 178 return apiv1.NewResponse(apimodel.Code_ExecuteException) 179 } 180 181 return apiv1.NewResponse(apimodel.Code_ExecuteSuccess) 182 } 183 184 func batchBuildV2Routings( 185 req *apitraffic.Routing) ([]*apitraffic.RouteRule, []*apitraffic.RouteRule, *apiservice.Response) { 186 inBounds := req.GetInbounds() 187 outBounds := req.GetOutbounds() 188 inRoutings := make([]*apitraffic.RouteRule, 0, len(inBounds)) 189 outRoutings := make([]*apitraffic.RouteRule, 0, len(outBounds)) 190 for i := range inBounds { 191 routing, err := model.BuildV2RoutingFromV1Route(req, inBounds[i]) 192 if err != nil { 193 return nil, nil, apiv1.NewResponse(apimodel.Code_ExecuteException) 194 } 195 routing.Name = req.GetNamespace().GetValue() + "." + req.GetService().GetValue() 196 inRoutings = append(inRoutings, routing) 197 } 198 199 for i := range outBounds { 200 routing, err := model.BuildV2RoutingFromV1Route(req, outBounds[i]) 201 if err != nil { 202 return nil, nil, apiv1.NewResponse(apimodel.Code_ExecuteException) 203 } 204 outRoutings = append(outRoutings, routing) 205 } 206 207 return inRoutings, outRoutings, nil 208 }