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  }