From b95645100f13f257f436fd3bf2ff5e89d9c78ce6 Mon Sep 17 00:00:00 2001 From: Menghan Li Date: Thu, 29 Oct 2020 10:16:05 -0700 Subject: [PATCH] priority: add policy config parsing (#3936) --- xds/internal/balancer/priority/config.go | 64 +++++++++++ xds/internal/balancer/priority/config_test.go | 107 ++++++++++++++++++ xds/internal/balancer/priority/doc.go | 24 ++++ 3 files changed, 195 insertions(+) create mode 100644 xds/internal/balancer/priority/config.go create mode 100644 xds/internal/balancer/priority/config_test.go create mode 100644 xds/internal/balancer/priority/doc.go diff --git a/xds/internal/balancer/priority/config.go b/xds/internal/balancer/priority/config.go new file mode 100644 index 000000000000..da085908c71d --- /dev/null +++ b/xds/internal/balancer/priority/config.go @@ -0,0 +1,64 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed 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 priority + +import ( + "encoding/json" + "fmt" + + internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" + "google.golang.org/grpc/serviceconfig" +) + +type child struct { + Config *internalserviceconfig.BalancerConfig +} + +type lbConfig struct { + serviceconfig.LoadBalancingConfig + + // Children is a map from the child balancer names to their configs. Child + // names can be found in field Priorities. + Children map[string]*child + // Priorities is a list of child balancer names. They are sorted from + // highest priority to low. The type/config for each child can be found in + // field Children, with the balancer name as the key. + Priorities []string +} + +func parseConfig(c json.RawMessage) (*lbConfig, error) { + var cfg lbConfig + if err := json.Unmarshal(c, &cfg); err != nil { + return nil, err + } + + prioritiesSet := make(map[string]bool) + for _, name := range cfg.Priorities { + if _, ok := cfg.Children[name]; !ok { + return nil, fmt.Errorf("LB policy name %q found in Priorities field (%v) is not found in Children field (%+v)", name, cfg.Priorities, cfg.Children) + } + prioritiesSet[name] = true + } + for name := range cfg.Children { + if _, ok := prioritiesSet[name]; !ok { + return nil, fmt.Errorf("LB policy name %q found in Children field (%v) is not found in Priorities field (%+v)", name, cfg.Children, cfg.Priorities) + } + } + return &cfg, nil +} diff --git a/xds/internal/balancer/priority/config_test.go b/xds/internal/balancer/priority/config_test.go new file mode 100644 index 000000000000..15c4069dd1e7 --- /dev/null +++ b/xds/internal/balancer/priority/config_test.go @@ -0,0 +1,107 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed 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 priority + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/balancer/roundrobin" + internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" +) + +func TestParseConfig(t *testing.T) { + tests := []struct { + name string + js string + want *lbConfig + wantErr bool + }{ + { + name: "child not found", + js: `{ + "priorities": ["child-1", "child-2", "child-3"], + "children": { + "child-1": {"config": [{"round_robin":{}}]}, + "child-3": {"config": [{"round_robin":{}}]} + } +} + `, + wantErr: true, + }, + { + name: "child not used", + js: `{ + "priorities": ["child-1", "child-2"], + "children": { + "child-1": {"config": [{"round_robin":{}}]}, + "child-2": {"config": [{"round_robin":{}}]}, + "child-3": {"config": [{"round_robin":{}}]} + } +} + `, + wantErr: true, + }, + { + name: "good", + js: `{ + "priorities": ["child-1", "child-2", "child-3"], + "children": { + "child-1": {"config": [{"round_robin":{}}]}, + "child-2": {"config": [{"round_robin":{}}]}, + "child-3": {"config": [{"round_robin":{}}]} + } +} + `, + want: &lbConfig{ + Children: map[string]*child{ + "child-1": { + &internalserviceconfig.BalancerConfig{ + Name: roundrobin.Name, + }, + }, + "child-2": { + &internalserviceconfig.BalancerConfig{ + Name: roundrobin.Name, + }, + }, + "child-3": { + &internalserviceconfig.BalancerConfig{ + Name: roundrobin.Name, + }, + }, + }, + Priorities: []string{"child-1", "child-2", "child-3"}, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseConfig([]byte(tt.js)) + if (err != nil) != tt.wantErr { + t.Errorf("parseConfig() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := cmp.Diff(got, tt.want); diff != "" { + t.Errorf("parseConfig() got = %v, want %v, diff: %s", got, tt.want, diff) + } + }) + } +} diff --git a/xds/internal/balancer/priority/doc.go b/xds/internal/balancer/priority/doc.go new file mode 100644 index 000000000000..53bd270cb10e --- /dev/null +++ b/xds/internal/balancer/priority/doc.go @@ -0,0 +1,24 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed 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 priority implements the priority balancer. +// +// This balancer will be kept in internal until we use it in the xds balancers, +// and are confident its functionalities are stable. It will then be exported +// for more users. +package priority