github.com/polarismesh/polaris@v1.17.8/test/integrate/http/circuitbreaker_config.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 http 19 20 import ( 21 "bytes" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "io" 26 27 "github.com/golang/protobuf/jsonpb" 28 apifault "github.com/polarismesh/specification/source/go/api/v1/fault_tolerance" 29 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 30 31 api "github.com/polarismesh/polaris/common/api/v1" 32 ) 33 34 // JSONFromCircuitBreakers marshals a slice of circuit breakers to JSON. 熔断规则数组转JSON 35 func JSONFromCircuitBreakers(circuitBreakers []*apifault.CircuitBreaker) (*bytes.Buffer, error) { 36 m := jsonpb.Marshaler{Indent: " "} 37 38 buffer := bytes.NewBuffer([]byte{}) 39 40 buffer.Write([]byte("[")) 41 for index, circuitBreaker := range circuitBreakers { 42 if index > 0 { 43 buffer.Write([]byte(",\n")) 44 } 45 err := m.Marshal(buffer, circuitBreaker) 46 if err != nil { 47 return nil, err 48 } 49 } 50 51 buffer.Write([]byte("]")) 52 return buffer, nil 53 } 54 55 // JSONFromConfigReleases marshals a slice of config releases to JSON. 配置发布规则数组转JSON 56 func JSONFromConfigReleases(configReleases []*apiservice.ConfigRelease) (*bytes.Buffer, error) { 57 m := jsonpb.Marshaler{Indent: " "} 58 59 buffer := bytes.NewBuffer([]byte{}) 60 61 buffer.Write([]byte("[")) 62 for index, configRelease := range configReleases { 63 if index > 0 { 64 buffer.Write([]byte(",\n")) 65 } 66 err := m.Marshal(buffer, configRelease) 67 if err != nil { 68 return nil, err 69 } 70 } 71 72 buffer.Write([]byte("]")) 73 return buffer, nil 74 } 75 76 // CreateCircuitBreakers creates a slice of circuit breakers from JSON. 创建熔断规则 77 func (c *Client) CreateCircuitBreakers(circuitBreakers []*apifault.CircuitBreaker) (*apiservice.BatchWriteResponse, error) { 78 fmt.Printf("\ncreate circuit breakers\n") 79 80 url := fmt.Sprintf("http://%v/naming/%v/circuitbreakers", c.Address, c.Version) 81 82 body, err := JSONFromCircuitBreakers(circuitBreakers) 83 if err != nil { 84 fmt.Printf("%v\n", err) 85 return nil, err 86 } 87 88 response, err := c.SendRequest("POST", url, body) 89 if err != nil { 90 fmt.Printf("%v\n", err) 91 return nil, err 92 } 93 94 ret, err := GetBatchWriteResponse(response) 95 if err != nil { 96 fmt.Printf("%v\n", err) 97 return ret, err 98 } 99 100 return checkCreateCircuitBreakersResponse(ret, circuitBreakers) 101 } 102 103 // CreateCircuitBreakerVersions creates a slice of circuit breakers from JSON. 创建熔断规则版本 104 func (c *Client) CreateCircuitBreakerVersions(circuitBreakers []*apifault.CircuitBreaker) (*apiservice.BatchWriteResponse, error) { 105 fmt.Printf("\ncreate circuit breaker versions\n") 106 107 url := fmt.Sprintf("http://%v/naming/%v/circuitbreakers/version", c.Address, c.Version) 108 body, err := JSONFromCircuitBreakers(circuitBreakers) 109 if err != nil { 110 fmt.Printf("%v\n", err) 111 return nil, err 112 } 113 114 response, err := c.SendRequest("POST", url, body) 115 if err != nil { 116 fmt.Printf("%v\n", err) 117 return nil, err 118 } 119 120 ret, err := GetBatchWriteResponse(response) 121 if err != nil { 122 fmt.Printf("%v\n", err) 123 return ret, err 124 } 125 126 return checkCreateCircuitBreakersResponse(ret, circuitBreakers) 127 } 128 129 // UpdateCircuitBreakers 更新熔断规则 130 func (c *Client) UpdateCircuitBreakers(circuitBreakers []*apifault.CircuitBreaker) error { 131 fmt.Printf("\nupdate circuit breakers\n") 132 133 url := fmt.Sprintf("http://%v/naming/%v/circuitbreakers", c.Address, c.Version) 134 135 body, err := JSONFromCircuitBreakers(circuitBreakers) 136 if err != nil { 137 fmt.Printf("%v\n", err) 138 return err 139 } 140 141 response, err := c.SendRequest("PUT", url, body) 142 if err != nil { 143 fmt.Printf("%v\n", err) 144 return err 145 } 146 147 _, err = GetBatchWriteResponse(response) 148 if err != nil { 149 if err == io.EOF { 150 return nil 151 } 152 153 fmt.Printf("%v\n", err) 154 return err 155 } 156 return nil 157 } 158 159 /** 160 * @brief 删除熔断规则 161 */ 162 func (c *Client) DeleteCircuitBreakers(circuitBreakers []*apifault.CircuitBreaker) error { 163 fmt.Printf("\ndelete circuit breakers\n") 164 165 url := fmt.Sprintf("http://%v/naming/%v/circuitbreakers/delete", c.Address, c.Version) 166 167 body, err := JSONFromCircuitBreakers(circuitBreakers) 168 if err != nil { 169 fmt.Printf("%v\n", err) 170 return err 171 } 172 173 response, err := c.SendRequest("POST", url, body) 174 if err != nil { 175 fmt.Printf("%v\n", err) 176 return err 177 } 178 179 _, err = GetBatchWriteResponse(response) 180 if err != nil { 181 if err == io.EOF { 182 return nil 183 } 184 185 fmt.Printf("%v\n", err) 186 return err 187 } 188 return nil 189 } 190 191 /** 192 * @brief 发布熔断规则 193 */ 194 func (c *Client) ReleaseCircuitBreakers(configReleases []*apiservice.ConfigRelease) error { 195 fmt.Printf("\nrelease circuit breakers\n") 196 197 url := fmt.Sprintf("http://%v/naming/%v/circuitbreakers/release", c.Address, c.Version) 198 199 body, err := JSONFromConfigReleases(configReleases) 200 if err != nil { 201 fmt.Printf("%v\n", err) 202 return err 203 } 204 205 response, err := c.SendRequest("POST", url, body) 206 if err != nil { 207 fmt.Printf("%v\n", err) 208 return err 209 } 210 211 _, err = GetBatchWriteResponse(response) 212 if err != nil { 213 if err == io.EOF { 214 return nil 215 } 216 217 fmt.Printf("%v\n", err) 218 return err 219 } 220 return nil 221 } 222 223 /** 224 * @brief 解绑熔断规则 225 */ 226 func (c *Client) UnbindCircuitBreakers(configReleases []*apiservice.ConfigRelease) error { 227 fmt.Printf("\nunbind circuit breakers\n") 228 229 url := fmt.Sprintf("http://%v/naming/%v/circuitbreakers/unbind", c.Address, c.Version) 230 231 body, err := JSONFromConfigReleases(configReleases) 232 if err != nil { 233 fmt.Printf("%v\n", err) 234 return err 235 } 236 237 response, err := c.SendRequest("POST", url, body) 238 if err != nil { 239 fmt.Printf("%v\n", err) 240 return err 241 } 242 243 _, err = GetBatchWriteResponse(response) 244 if err != nil { 245 if err == io.EOF { 246 return nil 247 } 248 249 fmt.Printf("%v\n", err) 250 return err 251 } 252 return nil 253 } 254 255 /** 256 * @brief 根据id和version查询熔断规则 257 */ 258 func (c *Client) GetCircuitBreaker(masterCircuitBreaker, circuitBreaker *apifault.CircuitBreaker) error { 259 fmt.Printf("\nget circuit breaker by id and version\n") 260 261 url := fmt.Sprintf("http://%v/naming/%v/circuitbreaker", c.Address, c.Version) 262 263 params := map[string][]interface{}{ 264 "id": {circuitBreaker.GetId().GetValue()}, 265 "version": {circuitBreaker.GetVersion().GetValue()}, 266 } 267 268 url = c.CompleteURL(url, params) 269 response, err := c.SendRequest("GET", url, nil) 270 if err != nil { 271 return err 272 } 273 274 ret, err := GetBatchQueryResponse(response) 275 if err != nil { 276 fmt.Printf("%v\n", err) 277 return err 278 } 279 280 if ret.GetCode() == nil || ret.GetCode().GetValue() != api.ExecuteSuccess { 281 return errors.New("invalid batch code") 282 } 283 284 size := 1 285 286 if ret.GetAmount() == nil || ret.GetAmount().GetValue() != uint32(size) { 287 return errors.New("invalid batch amount") 288 } 289 290 if ret.GetSize() == nil || ret.GetSize().GetValue() != uint32(size) { 291 return errors.New("invalid batch size") 292 } 293 294 item := ret.GetConfigWithServices() 295 if item == nil || len(item) != size { 296 return errors.New("invalid batch circuit breakers") 297 } 298 299 if item[0].GetCircuitBreaker() == nil { 300 return errors.New("invalid circuit breakers") 301 } 302 303 if result, err := compareCircuitBreaker(circuitBreaker, masterCircuitBreaker, item[0].GetCircuitBreaker()); !result { 304 return err 305 } 306 307 return nil 308 } 309 310 /** 311 * @brief 查询熔断规则的已发布规则及服务 312 */ 313 func (c *Client) GetCircuitBreakersRelease(circuitBreaker *apifault.CircuitBreaker, correctService *apiservice.Service) error { 314 fmt.Printf("\nget circuit breaker release\n") 315 316 url := fmt.Sprintf("http://%v/naming/%v/circuitbreakers/release", c.Address, c.Version) 317 318 params := map[string][]interface{}{ 319 "id": {circuitBreaker.GetId().GetValue()}, 320 } 321 322 url = c.CompleteURL(url, params) 323 response, err := c.SendRequest("GET", url, nil) 324 if err != nil { 325 return err 326 } 327 328 ret, err := GetBatchQueryResponse(response) 329 if err != nil { 330 fmt.Printf("%v\n", err) 331 return err 332 } 333 334 if ret.GetCode() == nil || ret.GetCode().GetValue() != api.ExecuteSuccess { 335 return errors.New("invalid batch code") 336 } 337 338 size := 1 339 340 if ret.GetAmount() == nil || ret.GetAmount().GetValue() != uint32(size) { 341 return fmt.Errorf("invalid batch amount, expect : %d, actual : %d", size, ret.GetAmount().GetValue()) 342 } 343 344 if ret.GetSize() == nil || ret.GetSize().GetValue() != uint32(size) { 345 return errors.New("invalid batch size") 346 } 347 348 configWithServices := ret.GetConfigWithServices() 349 if configWithServices == nil || len(configWithServices) != size { 350 return errors.New("invalid batch circuit breakers") 351 } 352 353 if configWithServices[0].GetCircuitBreaker() == nil { 354 return errors.New("invalid circuit breakers") 355 } 356 357 rule := configWithServices[0].GetCircuitBreaker() 358 359 if circuitBreaker.GetId().GetValue() != rule.GetId().GetValue() || 360 circuitBreaker.GetVersion().GetValue() != rule.GetVersion().GetValue() { 361 return errors.New("error circuit breaker id or version") 362 } 363 364 if configWithServices[0].GetServices() == nil || configWithServices[0].GetServices()[0] == nil { 365 return errors.New("invalid services") 366 } 367 368 service := configWithServices[0].GetServices()[0] 369 serviceName := service.GetName().GetValue() 370 namespaceName := service.GetNamespace().GetValue() 371 372 if serviceName != correctService.GetName().GetValue() || 373 namespaceName != correctService.GetNamespace().GetValue() { 374 return errors.New("invalid service name or namespace") 375 } 376 377 return nil 378 } 379 380 /** 381 * @brief 查询熔断规则所有版本 382 */ 383 func (c *Client) GetCircuitBreakerVersions(circuitBreaker *apifault.CircuitBreaker) error { 384 fmt.Printf("\nget circuit breaker versions\n") 385 386 url := fmt.Sprintf("http://%v/naming/%v/circuitbreaker/versions", c.Address, c.Version) 387 388 params := map[string][]interface{}{ 389 "id": {circuitBreaker.GetId().GetValue()}, 390 } 391 392 url = c.CompleteURL(url, params) 393 response, err := c.SendRequest("GET", url, nil) 394 if err != nil { 395 return err 396 } 397 398 ret, err := GetBatchQueryResponse(response) 399 if err != nil { 400 fmt.Printf("%v\n", err) 401 return err 402 } 403 404 if ret.GetCode() == nil || ret.GetCode().GetValue() != api.ExecuteSuccess { 405 return errors.New("invalid batch code") 406 } 407 408 size := 2 409 410 if ret.GetAmount() == nil || ret.GetAmount().GetValue() != uint32(size) { 411 return errors.New("invalid batch amount") 412 } 413 414 if ret.GetSize() == nil || ret.GetSize().GetValue() != uint32(size) { 415 return errors.New("invalid batch size") 416 } 417 418 configWithServices := ret.GetConfigWithServices() 419 if configWithServices == nil || len(configWithServices) != size { 420 return errors.New("invalid batch circuit breakers") 421 } 422 423 versions := make([]string, 0, size) 424 for _, item := range configWithServices { 425 cb := item.GetCircuitBreaker() 426 if cb.GetId().GetValue() != circuitBreaker.GetId().GetValue() { 427 return errors.New("invalid circuit breaker id") 428 } 429 versions = append(versions, cb.GetVersion().GetValue()) 430 } 431 432 correctVersions := map[string]bool{ 433 circuitBreaker.GetVersion().GetValue(): true, 434 "master": true, 435 } 436 437 for _, version := range versions { 438 if _, ok := correctVersions[version]; !ok { 439 return errors.New("invalid circuit breaker version") 440 } 441 } 442 443 return nil 444 } 445 446 /** 447 * @brief 查询服务绑定的熔断规则 448 */ 449 func (c *Client) GetCircuitBreakerByService(service *apiservice.Service, masterCircuitBreaker, 450 circuitBreaker *apifault.CircuitBreaker) error { 451 fmt.Printf("\nget circuit breaker by service\n") 452 453 url := fmt.Sprintf("http://%v/naming/%v/service/circuitbreaker", c.Address, c.Version) 454 455 params := map[string][]interface{}{ 456 "service": {service.GetName().GetValue()}, 457 "namespace": {service.GetNamespace().GetValue()}, 458 } 459 460 url = c.CompleteURL(url, params) 461 response, err := c.SendRequest("GET", url, nil) 462 if err != nil { 463 return err 464 } 465 466 ret, err := GetBatchQueryResponse(response) 467 if err != nil { 468 fmt.Printf("%v\n", err) 469 return err 470 } 471 472 if ret.GetCode() == nil || ret.GetCode().GetValue() != api.ExecuteSuccess { 473 return errors.New("invalid batch code") 474 } 475 476 size := 1 477 478 if ret.GetAmount() == nil || ret.GetAmount().GetValue() != uint32(size) { 479 return errors.New("invalid batch amount") 480 } 481 482 if ret.GetSize() == nil || ret.GetSize().GetValue() != uint32(size) { 483 return errors.New("invalid batch size") 484 } 485 486 configWithServices := ret.GetConfigWithServices() 487 if configWithServices == nil || len(configWithServices) != size { 488 return errors.New("invalid batch circuit breakers") 489 } 490 491 rule := configWithServices[0].GetCircuitBreaker() 492 if rule == nil { 493 return errors.New("invalid circuit breaker") 494 } 495 496 if result, err := compareCircuitBreaker(circuitBreaker, masterCircuitBreaker, rule); !result { 497 return err 498 } 499 500 return nil 501 } 502 503 /** 504 * @brief 检查创建熔断规则的回复 505 */ 506 func checkCreateCircuitBreakersResponse(ret *apiservice.BatchWriteResponse, circuitBreakers []*apifault.CircuitBreaker) ( 507 *apiservice.BatchWriteResponse, error) { 508 switch { 509 case ret.GetCode().GetValue() != api.ExecuteSuccess: 510 return nil, errors.New("invalid batch code") 511 case ret.GetSize().GetValue() != uint32(len(circuitBreakers)): 512 return nil, errors.New("invalid batch size") 513 case len(ret.GetResponses()) != len(circuitBreakers): 514 return nil, errors.New("invalid batch response") 515 } 516 517 for index, item := range ret.GetResponses() { 518 if item.GetCode().GetValue() != api.ExecuteSuccess { 519 return nil, errors.New("invalid code") 520 } 521 circuitBreaker := item.GetCircuitBreaker() 522 if circuitBreaker == nil { 523 return nil, errors.New("empty circuit breaker") 524 } 525 526 if result, err := compareCircuitBreaker(circuitBreakers[index], circuitBreakers[index], circuitBreaker); !result { 527 return nil, err 528 } else { 529 return ret, nil 530 } 531 } 532 return ret, nil 533 } 534 535 /** 536 * @brief 比较circuit breaker是否相等 537 */ 538 func compareCircuitBreaker(correctItem, correctMaster *apifault.CircuitBreaker, item *apifault.CircuitBreaker) (bool, error) { 539 switch { 540 case item.GetId() == nil || item.GetId().GetValue() == "": 541 return false, errors.New("error id") 542 case item.GetVersion() == nil || item.GetVersion().GetValue() == "": 543 return false, errors.New("error version") 544 case correctMaster.GetName().GetValue() != item.GetName().GetValue(): 545 return false, errors.New("error name") 546 case correctMaster.GetNamespace().GetValue() != item.GetNamespace().GetValue(): 547 return false, errors.New("error namespace") 548 case correctMaster.GetOwners().GetValue() != item.GetOwners().GetValue(): 549 return false, errors.New("error owners") 550 case correctMaster.GetComment().GetValue() != item.GetComment().GetValue(): 551 return false, errors.New("error comment") 552 case correctMaster.GetBusiness().GetValue() != item.GetBusiness().GetValue(): 553 return false, errors.New("error business") 554 case correctMaster.GetDepartment().GetValue() != item.GetDepartment().GetValue(): 555 return false, errors.New("error department") 556 default: 557 break 558 } 559 560 correctInbounds, err := json.Marshal(correctItem.GetInbounds()) 561 if err != nil { 562 panic(err) 563 } 564 inbounds, err := json.Marshal(item.GetInbounds()) 565 if err != nil { 566 panic(err) 567 } 568 if string(correctInbounds) != string(inbounds) { 569 return false, errors.New("error inbounds") 570 } 571 572 correctOutbounds, err := json.Marshal(correctItem.GetOutbounds()) 573 if err != nil { 574 panic(err) 575 } 576 outbounds, err := json.Marshal(item.GetOutbounds()) 577 if err != nil { 578 panic(err) 579 } 580 if string(correctOutbounds) != string(outbounds) { 581 return false, errors.New("error inbounds") 582 } 583 return true, nil 584 }