diff --git a/xds/internal/balancer/outlierdetection/balancer.go b/xds/internal/balancer/outlierdetection/balancer.go deleted file mode 100644 index 4a50578bc92a..000000000000 --- a/xds/internal/balancer/outlierdetection/balancer.go +++ /dev/null @@ -1,121 +0,0 @@ -/* - * - * Copyright 2022 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 outlierdetection implements a balancer that implements -// Outlier Detection. -package outlierdetection - -import ( - "encoding/json" - "fmt" - - "google.golang.org/grpc/balancer" - "google.golang.org/grpc/serviceconfig" -) - -// Name is the name of the outlier detection balancer. -const Name = "outlier_detection_experimental" - -func init() { - balancer.Register(bb{}) -} - -type bb struct{} - -func (bb) Build(cc balancer.ClientConn, bOpts balancer.BuildOptions) balancer.Balancer { - return &outlierDetectionBalancer{} -} - -func (bb) ParseConfig(s json.RawMessage) (serviceconfig.LoadBalancingConfig, error) { - var lbCfg *LBConfig - if err := json.Unmarshal(s, &lbCfg); err != nil { - return nil, fmt.Errorf("xds: unable to unmarshal LBconfig: %s, error: %v", string(s), err) - } - - // Note: in the xds flow, these validations will never fail. The xdsclient - // performs the same validations as here on the xds Outlier Detection - // resource before parsing into the internal struct which gets marshaled - // into JSON before calling this function. A50 defines two separate places - // for these validations to take place, the xdsclient and this ParseConfig - // method. "When parsing a config from JSON, if any of these requirements is - // violated, that should be treated as a parsing error." - A50 - - // "The google.protobuf.Duration fields interval, base_ejection_time, and - // max_ejection_time must obey the restrictions in the - // google.protobuf.Duration documentation and they must have non-negative - // values." - A50 - - // Approximately 290 years is the maximum time that time.Duration (int64) - // can represent. The restrictions on the protobuf.Duration field are to be - // within +-10000 years. Thus, just check for negative values. - if lbCfg.Interval < 0 { - return nil, fmt.Errorf("LBConfig.Interval = %v; must be >= 0", lbCfg.Interval) - } - if lbCfg.BaseEjectionTime < 0 { - return nil, fmt.Errorf("LBConfig.BaseEjectionTime = %v; must be >= 0", lbCfg.BaseEjectionTime) - } - if lbCfg.MaxEjectionTime < 0 { - return nil, fmt.Errorf("LBConfig.MaxEjectionTime = %v; must be >= 0", lbCfg.MaxEjectionTime) - } - - // "The fields max_ejection_percent, - // success_rate_ejection.enforcement_percentage, - // failure_percentage_ejection.threshold, and - // failure_percentage.enforcement_percentage must have values less than or - // equal to 100." - A50 - if lbCfg.MaxEjectionPercent > 100 { - return nil, fmt.Errorf("LBConfig.MaxEjectionPercent = %v; must be <= 100", lbCfg.MaxEjectionPercent) - } - if lbCfg.SuccessRateEjection != nil && lbCfg.SuccessRateEjection.EnforcementPercentage > 100 { - return nil, fmt.Errorf("LBConfig.SuccessRateEjection.EnforcementPercentage = %v; must be <= 100", lbCfg.SuccessRateEjection.EnforcementPercentage) - } - if lbCfg.FailurePercentageEjection != nil && lbCfg.FailurePercentageEjection.Threshold > 100 { - return nil, fmt.Errorf("LBConfig.FailurePercentageEjection.Threshold = %v; must be <= 100", lbCfg.FailurePercentageEjection.Threshold) - } - if lbCfg.FailurePercentageEjection != nil && lbCfg.FailurePercentageEjection.EnforcementPercentage > 100 { - return nil, fmt.Errorf("LBConfig.FailurePercentageEjection.EnforcementPercentage = %v; must be <= 100", lbCfg.FailurePercentageEjection.EnforcementPercentage) - } - return lbCfg, nil -} - -func (bb) Name() string { - return Name -} - -type outlierDetectionBalancer struct { -} - -func (b *outlierDetectionBalancer) UpdateClientConnState(s balancer.ClientConnState) error { - return nil -} - -func (b *outlierDetectionBalancer) ResolverError(err error) { - -} - -func (b *outlierDetectionBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { - -} - -func (b *outlierDetectionBalancer) Close() { - -} - -func (b *outlierDetectionBalancer) ExitIdle() { - -} diff --git a/xds/internal/balancer/outlierdetection/balancer_test.go b/xds/internal/balancer/outlierdetection/balancer_test.go deleted file mode 100644 index 52ee7fdf7ac5..000000000000 --- a/xds/internal/balancer/outlierdetection/balancer_test.go +++ /dev/null @@ -1,185 +0,0 @@ -/* - * - * Copyright 2022 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 outlierdetection - -import ( - "encoding/json" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "google.golang.org/grpc/balancer" - "google.golang.org/grpc/internal/grpctest" - internalserviceconfig "google.golang.org/grpc/internal/serviceconfig" - "google.golang.org/grpc/serviceconfig" - "google.golang.org/grpc/xds/internal/balancer/clusterimpl" -) - -type s struct { - grpctest.Tester -} - -func Test(t *testing.T) { - grpctest.RunSubTests(t, s{}) -} - -// TestParseConfig verifies the ParseConfig() method in the CDS balancer. -func (s) TestParseConfig(t *testing.T) { - bb := balancer.Get(Name) - if bb == nil { - t.Fatalf("balancer.Get(%q) returned nil", Name) - } - parser, ok := bb.(balancer.ConfigParser) - if !ok { - t.Fatalf("balancer %q does not implement the ConfigParser interface", Name) - } - - tests := []struct { - name string - input json.RawMessage - wantCfg serviceconfig.LoadBalancingConfig - wantErr bool - }{ - { - name: "noop-lb-config", - input: json.RawMessage(`{"interval": 9223372036854775807}`), - wantCfg: &LBConfig{Interval: 1<<63 - 1}, - }, - { - name: "good-lb-config", - input: json.RawMessage(`{ - "interval": 10000000000, - "baseEjectionTime": 30000000000, - "maxEjectionTime": 300000000000, - "maxEjectionPercent": 10, - "successRateEjection": { - "stdevFactor": 1900, - "enforcementPercentage": 100, - "minimumHosts": 5, - "requestVolume": 100 - }, - "failurePercentageEjection": { - "threshold": 85, - "enforcementPercentage": 5, - "minimumHosts": 5, - "requestVolume": 50 - } - }`), - wantCfg: &LBConfig{ - Interval: 10 * time.Second, - BaseEjectionTime: 30 * time.Second, - MaxEjectionTime: 300 * time.Second, - MaxEjectionPercent: 10, - SuccessRateEjection: &SuccessRateEjection{ - StdevFactor: 1900, - EnforcementPercentage: 100, - MinimumHosts: 5, - RequestVolume: 100, - }, - FailurePercentageEjection: &FailurePercentageEjection{ - Threshold: 85, - EnforcementPercentage: 5, - MinimumHosts: 5, - RequestVolume: 50, - }, - }, - }, - { - name: "interval-is-negative", - input: json.RawMessage(`{"interval": -10}`), - wantErr: true, - }, - { - name: "base-ejection-time-is-negative", - input: json.RawMessage(`{"baseEjectionTime": -10}`), - wantErr: true, - }, - { - name: "max-ejection-time-is-negative", - input: json.RawMessage(`{"maxEjectionTime": -10}`), - wantErr: true, - }, - { - name: "max-ejection-percent-is-greater-than-100", - input: json.RawMessage(`{"maxEjectionPercent": 150}`), - wantErr: true, - }, - { - name: "enforcing-success-rate-is-greater-than-100", - input: json.RawMessage(`{ - "successRateEjection": { - "enforcingSuccessRate": 100, - }, - }`), - wantErr: true, - }, - { - name: "failure-percentage-threshold-is-greater-than-100", - input: json.RawMessage(`{ - "failurePercentageEjection": { - "threshold": 150, - }, - }`), - wantErr: true, - }, - { - name: "enforcing-failure-percentage-is-greater-than-100", - input: json.RawMessage(`{ - "failurePercentageEjection": { - "enforcingFailurePercentage": 150, - }, - }`), - wantErr: true, - }, - { - name: "child-policy", - input: json.RawMessage(`{ - "childPolicy": [ - { - "xds_cluster_impl_experimental": { - "cluster": "test_cluster" - } - } - ] - }`), - wantCfg: &LBConfig{ - ChildPolicy: &internalserviceconfig.BalancerConfig{ - Name: "xds_cluster_impl_experimental", - Config: &clusterimpl.LBConfig{ - Cluster: "test_cluster", - }, - }, - }, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - gotCfg, gotErr := parser.ParseConfig(test.input) - if (gotErr != nil) != test.wantErr { - t.Fatalf("ParseConfig(%v) = %v, wantErr %v", string(test.input), gotErr, test.wantErr) - } - if test.wantErr { - return - } - if diff := cmp.Diff(gotCfg, test.wantCfg); diff != "" { - t.Fatalf("parseConfig(%v) got unexpected output, diff (-got +want): %v", string(test.input), diff) - } - }) - } -} diff --git a/xds/internal/balancer/outlierdetection/config.go b/xds/internal/balancer/outlierdetection/config.go index 4dc2d5618734..8b0cdcab4065 100644 --- a/xds/internal/balancer/outlierdetection/config.go +++ b/xds/internal/balancer/outlierdetection/config.go @@ -15,6 +15,8 @@ * limitations under the License. */ +// Package outlierdetection implements a balancer that implements +// Outlier Detection. package outlierdetection import (