config.go raw

   1  /*
   2   *
   3   * Copyright 2024 gRPC authors.
   4   *
   5   * Licensed under the Apache License, Version 2.0 (the "License");
   6   * you may not use this file except in compliance with the License.
   7   * You may obtain a copy of the License at
   8   *
   9   *     http://www.apache.org/licenses/LICENSE-2.0
  10   *
  11   * Unless required by applicable law or agreed to in writing, software
  12   * distributed under the License is distributed on an "AS IS" BASIS,
  13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14   * See the License for the specific language governing permissions and
  15   * limitations under the License.
  16   *
  17   */
  18  
  19  package gracefulswitch
  20  
  21  import (
  22  	"encoding/json"
  23  	"fmt"
  24  
  25  	"google.golang.org/grpc/balancer"
  26  	"google.golang.org/grpc/serviceconfig"
  27  )
  28  
  29  type lbConfig struct {
  30  	serviceconfig.LoadBalancingConfig
  31  
  32  	childBuilder balancer.Builder
  33  	childConfig  serviceconfig.LoadBalancingConfig
  34  }
  35  
  36  // ChildName returns the name of the child balancer of the gracefulswitch
  37  // Balancer.
  38  func ChildName(l serviceconfig.LoadBalancingConfig) string {
  39  	return l.(*lbConfig).childBuilder.Name()
  40  }
  41  
  42  // ParseConfig parses a child config list and returns a LB config for the
  43  // gracefulswitch Balancer.
  44  //
  45  // cfg is expected to be a json.RawMessage containing a JSON array of LB policy
  46  // names + configs as the format of the "loadBalancingConfig" field in
  47  // ServiceConfig.  It returns a type that should be passed to
  48  // UpdateClientConnState in the BalancerConfig field.
  49  func ParseConfig(cfg json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
  50  	var lbCfg []map[string]json.RawMessage
  51  	if err := json.Unmarshal(cfg, &lbCfg); err != nil {
  52  		return nil, err
  53  	}
  54  	for i, e := range lbCfg {
  55  		if len(e) != 1 {
  56  			return nil, fmt.Errorf("expected a JSON struct with one entry; received entry %v at index %d", e, i)
  57  		}
  58  
  59  		var name string
  60  		var jsonCfg json.RawMessage
  61  		for name, jsonCfg = range e {
  62  		}
  63  
  64  		builder := balancer.Get(name)
  65  		if builder == nil {
  66  			// Skip unregistered balancer names.
  67  			continue
  68  		}
  69  
  70  		parser, ok := builder.(balancer.ConfigParser)
  71  		if !ok {
  72  			// This is a valid child with no config.
  73  			return &lbConfig{childBuilder: builder}, nil
  74  		}
  75  
  76  		cfg, err := parser.ParseConfig(jsonCfg)
  77  		if err != nil {
  78  			return nil, fmt.Errorf("error parsing config for policy %q: %v", name, err)
  79  		}
  80  		return &lbConfig{childBuilder: builder, childConfig: cfg}, nil
  81  	}
  82  
  83  	return nil, fmt.Errorf("no supported policies found in config: %v", string(cfg))
  84  }
  85