From a354562c112b5989e16e4f6fee982f72c7f2570b Mon Sep 17 00:00:00 2001 From: BenHinthorne Date: Tue, 18 Jun 2024 16:10:20 -0400 Subject: [PATCH] [local] include similar nodegroups in gRPC expander options --- .../expander/grpcplugin/grpc_client.go | 40 ++- .../expander/grpcplugin/grpc_client_test.go | 74 ++++- .../expander/grpcplugin/protos/expander.pb.go | 254 ++++++------------ .../expander/grpcplugin/protos/expander.proto | 1 + .../grpcplugin/protos/expander_grpc.pb.go | 114 ++++++++ 5 files changed, 302 insertions(+), 181 deletions(-) create mode 100644 cluster-autoscaler/expander/grpcplugin/protos/expander_grpc.pb.go diff --git a/cluster-autoscaler/expander/grpcplugin/grpc_client.go b/cluster-autoscaler/expander/grpcplugin/grpc_client.go index 7bcab0c8158d..fc559667df0c 100644 --- a/cluster-autoscaler/expander/grpcplugin/grpc_client.go +++ b/cluster-autoscaler/expander/grpcplugin/grpc_client.go @@ -22,6 +22,7 @@ import ( "time" v1 "k8s.io/api/core/v1" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider" "k8s.io/autoscaler/cluster-autoscaler/expander" "k8s.io/autoscaler/cluster-autoscaler/expander/grpcplugin/protos" "k8s.io/klog/v2" @@ -111,11 +112,20 @@ func populateOptionsForGRPC(expansionOptions []expander.Option) ([]*protos.Optio nodeGroupIDOptionMap := make(map[string]expander.Option) for _, option := range expansionOptions { nodeGroupIDOptionMap[option.NodeGroup.Id()] = option - grpcOptionsSlice = append(grpcOptionsSlice, newOptionMessage(option.NodeGroup.Id(), int32(option.NodeCount), option.Debug, option.Pods)) + similarNodeGroupIds := getSimilarNodeGroupIds(option) + grpcOptionsSlice = append(grpcOptionsSlice, newOptionMessage(option.NodeGroup.Id(), int32(option.NodeCount), option.Debug, option.Pods, similarNodeGroupIds)) } return grpcOptionsSlice, nodeGroupIDOptionMap } +func getSimilarNodeGroupIds(option expander.Option) []string { + var similarNodeGroupIds []string + for _, sng := range option.SimilarNodeGroups { + similarNodeGroupIds = append(similarNodeGroupIds, sng.Id()) + } + return similarNodeGroupIds +} + // populateNodeInfoForGRPC looks at the corresponding v1.Node object per NodeInfo object, and populates the grpcNodeInfoMap with these to pass over grpc func populateNodeInfoForGRPC(nodeInfos map[string]*schedulerframework.NodeInfo) map[string]*v1.Node { grpcNodeInfoMap := make(map[string]*v1.Node) @@ -132,8 +142,9 @@ func transformAndSanitizeOptionsFromGRPC(bestOptionsResponseOptions []*protos.Op klog.Error("GRPC server returned nil Option") continue } - if _, ok := nodeGroupIDOptionMap[option.NodeGroupId]; ok { - options = append(options, nodeGroupIDOptionMap[option.NodeGroupId]) + if expanderOption, ok := nodeGroupIDOptionMap[option.NodeGroupId]; ok { + expanderOption.SimilarNodeGroups = getRetainedSimilarNodegroups(option, expanderOption) + options = append(options, expanderOption) } else { klog.Errorf("GRPC server returned invalid nodeGroup ID: %s", option.NodeGroupId) continue @@ -142,6 +153,25 @@ func transformAndSanitizeOptionsFromGRPC(bestOptionsResponseOptions []*protos.Op return options } -func newOptionMessage(nodeGroupId string, nodeCount int32, debug string, pods []*v1.Pod) *protos.Option { - return &protos.Option{NodeGroupId: nodeGroupId, NodeCount: nodeCount, Debug: debug, Pod: pods} +// Any similar options that were not included in the original grpcExpander request, but were added +// as part of the response, will be ignored +func getRetainedSimilarNodegroups(grpcOption *protos.Option, expanderOption expander.Option) []cloudprovider.NodeGroup { + var retainedSimilarNodeGroups []cloudprovider.NodeGroup + for _, sng := range expanderOption.SimilarNodeGroups { + retained := false + for _, id := range grpcOption.SimilarNodeGroupIds { + if sng.Id() == id { + retained = true + continue + } + } + if retained { + retainedSimilarNodeGroups = append(retainedSimilarNodeGroups, sng) + } + } + return retainedSimilarNodeGroups +} + +func newOptionMessage(nodeGroupId string, nodeCount int32, debug string, pods []*v1.Pod, similarNodeGroupIds []string) *protos.Option { + return &protos.Option{NodeGroupId: nodeGroupId, NodeCount: nodeCount, Debug: debug, Pod: pods, SimilarNodeGroupIds: similarNodeGroupIds} } diff --git a/cluster-autoscaler/expander/grpcplugin/grpc_client_test.go b/cluster-autoscaler/expander/grpcplugin/grpc_client_test.go index cb6882b79fc6..cc187e94b786 100644 --- a/cluster-autoscaler/expander/grpcplugin/grpc_client_test.go +++ b/cluster-autoscaler/expander/grpcplugin/grpc_client_test.go @@ -23,6 +23,7 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider" "k8s.io/autoscaler/cluster-autoscaler/expander/grpcplugin/protos" "k8s.io/autoscaler/cluster-autoscaler/expander/mocks" . "k8s.io/autoscaler/cluster-autoscaler/utils/test" @@ -58,6 +59,11 @@ var ( Debug: "m4.4xlarge", NodeGroup: test.NewTestNodeGroup("my-asg.m4.4xlarge", 10, 1, 1, true, false, "m4.4xlarge", nil, nil), } + eoT2MicroWithSimilar = expander.Option{ + Debug: "t2.micro", + NodeGroup: test.NewTestNodeGroup("my-asg.t2.micro", 10, 1, 1, true, false, "t2.micro", nil, nil), + SimilarNodeGroups: []cloudprovider.NodeGroup{test.NewTestNodeGroup("my-similar-asg.t2.micro", 10, 1, 1, true, false, "t2.micro", nil, nil)}, + } options = []expander.Option{eoT2Micro, eoT2Large, eoT3Large, eoM44XLarge} grpcEoT2Micro = protos.Option{ @@ -84,6 +90,20 @@ var ( Debug: eoM44XLarge.Debug, Pod: eoM44XLarge.Pods, } + grpcEoT2MicroWithSimilar = protos.Option{ + NodeGroupId: eoT2Micro.NodeGroup.Id(), + NodeCount: int32(eoT2Micro.NodeCount), + Debug: eoT2Micro.Debug, + Pod: eoT2Micro.Pods, + SimilarNodeGroupIds: []string{eoT2MicroWithSimilar.SimilarNodeGroups[0].Id()}, + } + grpcEoT2MicroWithSimilarWithExtraOptions = protos.Option{ + NodeGroupId: eoT2Micro.NodeGroup.Id(), + NodeCount: int32(eoT2Micro.NodeCount), + Debug: eoT2Micro.Debug, + Pod: eoT2Micro.Pods, + SimilarNodeGroupIds: []string{eoT2MicroWithSimilar.SimilarNodeGroups[0].Id(), "extra-ng-id"}, + } ) func TestPopulateOptionsForGrpc(t *testing.T) { @@ -116,6 +136,12 @@ func TestPopulateOptionsForGrpc(t *testing.T) { eoM44XLarge.NodeGroup.Id(): eoM44XLarge, }, }, + { + desc: "similar nodegroups are included", + opts: []expander.Option{eoT2MicroWithSimilar}, + expectedOpts: []*protos.Option{&grpcEoT2MicroWithSimilar}, + expectedMap: map[string]expander.Option{eoT2MicroWithSimilar.NodeGroup.Id(): eoT2MicroWithSimilar}, + }, } for _, tc := range testCases { grpcOptionsSlice, nodeGroupIDOptionMap := populateOptionsForGRPC(tc.opts) @@ -146,18 +172,44 @@ func TestPopulateNodeInfoForGRPC(t *testing.T) { } func TestValidTransformAndSanitizeOptionsFromGRPC(t *testing.T) { - responseOptionsSlice := []*protos.Option{&grpcEoT2Micro, &grpcEoT3Large, &grpcEoM44XLarge} - nodeGroupIDOptionMap := map[string]expander.Option{ - eoT2Micro.NodeGroup.Id(): eoT2Micro, - eoT2Large.NodeGroup.Id(): eoT2Large, - eoT3Large.NodeGroup.Id(): eoT3Large, - eoM44XLarge.NodeGroup.Id(): eoM44XLarge, + testCases := []struct { + desc string + responseOptions []*protos.Option + expectedOptions []expander.Option + nodegroupIDOptionaMap map[string]expander.Option + }{ + { + desc: "valid transform and sanitize options", + responseOptions: []*protos.Option{&grpcEoT2Micro, &grpcEoT3Large, &grpcEoM44XLarge}, + nodegroupIDOptionaMap: map[string]expander.Option{ + eoT2Micro.NodeGroup.Id(): eoT2Micro, + eoT2Large.NodeGroup.Id(): eoT2Large, + eoT3Large.NodeGroup.Id(): eoT3Large, + eoM44XLarge.NodeGroup.Id(): eoM44XLarge, + }, + expectedOptions: []expander.Option{eoT2Micro, eoT3Large, eoM44XLarge}, + }, + { + desc: "similar ngs are retained in proto options are retained", + responseOptions: []*protos.Option{&grpcEoT2MicroWithSimilar}, + nodegroupIDOptionaMap: map[string]expander.Option{ + eoT2MicroWithSimilar.NodeGroup.Id(): eoT2MicroWithSimilar, + }, + expectedOptions: []expander.Option{eoT2MicroWithSimilar}, + }, + { + desc: "extra similar ngs added to expander response are ignored", + responseOptions: []*protos.Option{&grpcEoT2MicroWithSimilarWithExtraOptions}, + nodegroupIDOptionaMap: map[string]expander.Option{ + eoT2MicroWithSimilar.NodeGroup.Id(): eoT2MicroWithSimilar, + }, + expectedOptions: []expander.Option{eoT2MicroWithSimilar}, + }, + } + for _, tc := range testCases { + ret := transformAndSanitizeOptionsFromGRPC(tc.responseOptions, tc.nodegroupIDOptionaMap) + assert.Equal(t, tc.expectedOptions, ret) } - - expectedOptions := []expander.Option{eoT2Micro, eoT3Large, eoM44XLarge} - - ret := transformAndSanitizeOptionsFromGRPC(responseOptionsSlice, nodeGroupIDOptionMap) - assert.Equal(t, expectedOptions, ret) } func TestAnInvalidTransformAndSanitizeOptionsFromGRPC(t *testing.T) { diff --git a/cluster-autoscaler/expander/grpcplugin/protos/expander.pb.go b/cluster-autoscaler/expander/grpcplugin/protos/expander.pb.go index 3c071d2f37d7..6c6a022acc75 100644 --- a/cluster-autoscaler/expander/grpcplugin/protos/expander.pb.go +++ b/cluster-autoscaler/expander/grpcplugin/protos/expander.pb.go @@ -17,13 +17,9 @@ limitations under the License. package protos import ( - context "context" reflect "reflect" sync "sync" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" v1 "k8s.io/api/core/v1" @@ -49,7 +45,7 @@ type BestOptionsRequest struct { func (x *BestOptionsRequest) Reset() { *x = BestOptionsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[0] + mi := &file_expander_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -62,7 +58,7 @@ func (x *BestOptionsRequest) String() string { func (*BestOptionsRequest) ProtoMessage() {} func (x *BestOptionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[0] + mi := &file_expander_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -75,7 +71,7 @@ func (x *BestOptionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BestOptionsRequest.ProtoReflect.Descriptor instead. func (*BestOptionsRequest) Descriptor() ([]byte, []int) { - return file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescGZIP(), []int{0} + return file_expander_proto_rawDescGZIP(), []int{0} } func (x *BestOptionsRequest) GetOptions() []*Option { @@ -103,7 +99,7 @@ type BestOptionsResponse struct { func (x *BestOptionsResponse) Reset() { *x = BestOptionsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[1] + mi := &file_expander_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -116,7 +112,7 @@ func (x *BestOptionsResponse) String() string { func (*BestOptionsResponse) ProtoMessage() {} func (x *BestOptionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[1] + mi := &file_expander_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -129,7 +125,7 @@ func (x *BestOptionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BestOptionsResponse.ProtoReflect.Descriptor instead. func (*BestOptionsResponse) Descriptor() ([]byte, []int) { - return file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescGZIP(), []int{1} + return file_expander_proto_rawDescGZIP(), []int{1} } func (x *BestOptionsResponse) GetOptions() []*Option { @@ -145,16 +141,17 @@ type Option struct { unknownFields protoimpl.UnknownFields // only need the ID of node to uniquely identify the nodeGroup, used in the nodeInfo map. - NodeGroupId string `protobuf:"bytes,1,opt,name=nodeGroupId,proto3" json:"nodeGroupId,omitempty"` - NodeCount int32 `protobuf:"varint,2,opt,name=nodeCount,proto3" json:"nodeCount,omitempty"` - Debug string `protobuf:"bytes,3,opt,name=debug,proto3" json:"debug,omitempty"` - Pod []*v1.Pod `protobuf:"bytes,4,rep,name=pod,proto3" json:"pod,omitempty"` + NodeGroupId string `protobuf:"bytes,1,opt,name=nodeGroupId,proto3" json:"nodeGroupId,omitempty"` + NodeCount int32 `protobuf:"varint,2,opt,name=nodeCount,proto3" json:"nodeCount,omitempty"` + Debug string `protobuf:"bytes,3,opt,name=debug,proto3" json:"debug,omitempty"` + Pod []*v1.Pod `protobuf:"bytes,4,rep,name=pod,proto3" json:"pod,omitempty"` + SimilarNodeGroupIds []string `protobuf:"bytes,5,rep,name=similarNodeGroupIds,proto3" json:"similarNodeGroupIds,omitempty"` } func (x *Option) Reset() { *x = Option{} if protoimpl.UnsafeEnabled { - mi := &file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[2] + mi := &file_expander_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -167,7 +164,7 @@ func (x *Option) String() string { func (*Option) ProtoMessage() {} func (x *Option) ProtoReflect() protoreflect.Message { - mi := &file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[2] + mi := &file_expander_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -180,7 +177,7 @@ func (x *Option) ProtoReflect() protoreflect.Message { // Deprecated: Use Option.ProtoReflect.Descriptor instead. func (*Option) Descriptor() ([]byte, []int) { - return file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescGZIP(), []int{2} + return file_expander_proto_rawDescGZIP(), []int{2} } func (x *Option) GetNodeGroupId() string { @@ -211,69 +208,76 @@ func (x *Option) GetPod() []*v1.Pod { return nil } -var File_cluster_autoscaler_expander_grpcplugin_protos_expander_proto protoreflect.FileDescriptor - -var file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDesc = []byte{ - 0x0a, 0x3c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d, 0x61, 0x75, 0x74, 0x6f, 0x73, 0x63, - 0x61, 0x6c, 0x65, 0x72, 0x2f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x72, - 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, - 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, - 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x1a, 0x22, 0x6b, 0x38, 0x73, 0x2e, - 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x67, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdf, - 0x01, 0x0a, 0x12, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x45, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x70, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x2e, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x70, 0x1a, 0x54, 0x0a, 0x0c, 0x4e, 0x6f, - 0x64, 0x65, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6b, 0x38, - 0x73, 0x2e, 0x69, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x43, 0x0a, 0x13, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, +func (x *Option) GetSimilarNodeGroupIds() []string { + if x != nil { + return x.SimilarNodeGroupIds + } + return nil +} + +var File_expander_proto protoreflect.FileDescriptor + +var file_expander_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x0a, 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x1a, 0x22, 0x6b, 0x38, + 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x31, + 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0xdf, 0x01, 0x0a, 0x12, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x89, 0x01, 0x0a, 0x06, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x12, 0x29, 0x0a, 0x03, 0x70, 0x6f, 0x64, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x64, 0x52, 0x03, 0x70, 0x6f, - 0x64, 0x32, 0x5c, 0x0a, 0x08, 0x45, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x50, 0x0a, - 0x0b, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, - 0x2f, 0x5a, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d, 0x61, 0x75, 0x74, 0x6f, 0x73, - 0x63, 0x61, 0x6c, 0x65, 0x72, 0x2f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x2f, 0x67, - 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x45, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x70, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x2e, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x70, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x70, 0x1a, 0x54, 0x0a, 0x0c, + 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x43, 0x0a, 0x13, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xbb, 0x01, 0x0a, 0x06, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x12, 0x29, 0x0a, 0x03, 0x70, 0x6f, 0x64, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x64, 0x52, 0x03, + 0x70, 0x6f, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x4e, 0x6f, + 0x64, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x13, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x49, 0x64, 0x73, 0x32, 0x5c, 0x0a, 0x08, 0x45, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, + 0x72, 0x12, 0x50, 0x0a, 0x0b, 0x42, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x1e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x42, 0x65, + 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x42, 0x65, + 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x42, 0x2f, 0x5a, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2d, 0x61, + 0x75, 0x74, 0x6f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x2f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, + 0x65, 0x72, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescOnce sync.Once - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescData = file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDesc + file_expander_proto_rawDescOnce sync.Once + file_expander_proto_rawDescData = file_expander_proto_rawDesc ) -func file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescGZIP() []byte { - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescOnce.Do(func() { - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescData = protoimpl.X.CompressGZIP(file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescData) +func file_expander_proto_rawDescGZIP() []byte { + file_expander_proto_rawDescOnce.Do(func() { + file_expander_proto_rawDescData = protoimpl.X.CompressGZIP(file_expander_proto_rawDescData) }) - return file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDescData + return file_expander_proto_rawDescData } -var file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_goTypes = []interface{}{ +var file_expander_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_expander_proto_goTypes = []interface{}{ (*BestOptionsRequest)(nil), // 0: grpcplugin.BestOptionsRequest (*BestOptionsResponse)(nil), // 1: grpcplugin.BestOptionsResponse (*Option)(nil), // 2: grpcplugin.Option @@ -281,7 +285,7 @@ var file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_goTypes = (*v1.Pod)(nil), // 4: k8s.io.api.core.v1.Pod (*v1.Node)(nil), // 5: k8s.io.api.core.v1.Node } -var file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_depIdxs = []int32{ +var file_expander_proto_depIdxs = []int32{ 2, // 0: grpcplugin.BestOptionsRequest.options:type_name -> grpcplugin.Option 3, // 1: grpcplugin.BestOptionsRequest.nodeMap:type_name -> grpcplugin.BestOptionsRequest.NodeMapEntry 2, // 2: grpcplugin.BestOptionsResponse.options:type_name -> grpcplugin.Option @@ -296,13 +300,13 @@ var file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_depIdxs = 0, // [0:5] is the sub-list for field type_name } -func init() { file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_init() } -func file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_init() { - if File_cluster_autoscaler_expander_grpcplugin_protos_expander_proto != nil { +func init() { file_expander_proto_init() } +func file_expander_proto_init() { + if File_expander_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_expander_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BestOptionsRequest); i { case 0: return &v.state @@ -314,7 +318,7 @@ func file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_init() { return nil } } - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_expander_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BestOptionsResponse); i { case 0: return &v.state @@ -326,7 +330,7 @@ func file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_init() { return nil } } - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_expander_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Option); i { case 0: return &v.state @@ -343,98 +347,18 @@ func file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDesc, + RawDescriptor: file_expander_proto_rawDesc, NumEnums: 0, NumMessages: 4, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_goTypes, - DependencyIndexes: file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_depIdxs, - MessageInfos: file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_msgTypes, + GoTypes: file_expander_proto_goTypes, + DependencyIndexes: file_expander_proto_depIdxs, + MessageInfos: file_expander_proto_msgTypes, }.Build() - File_cluster_autoscaler_expander_grpcplugin_protos_expander_proto = out.File - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_rawDesc = nil - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_goTypes = nil - file_cluster_autoscaler_expander_grpcplugin_protos_expander_proto_depIdxs = nil -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 - -// ExpanderClient is the client API for Expander service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type ExpanderClient interface { - BestOptions(ctx context.Context, in *BestOptionsRequest, opts ...grpc.CallOption) (*BestOptionsResponse, error) -} - -type expanderClient struct { - cc grpc.ClientConnInterface -} - -func NewExpanderClient(cc grpc.ClientConnInterface) ExpanderClient { - return &expanderClient{cc} -} - -func (c *expanderClient) BestOptions(ctx context.Context, in *BestOptionsRequest, opts ...grpc.CallOption) (*BestOptionsResponse, error) { - out := new(BestOptionsResponse) - err := c.cc.Invoke(ctx, "/grpcplugin.Expander/BestOptions", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ExpanderServer is the server API for Expander service. -type ExpanderServer interface { - BestOptions(context.Context, *BestOptionsRequest) (*BestOptionsResponse, error) -} - -// UnimplementedExpanderServer can be embedded to have forward compatible implementations. -type UnimplementedExpanderServer struct { -} - -func (*UnimplementedExpanderServer) BestOptions(context.Context, *BestOptionsRequest) (*BestOptionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method BestOptions not implemented") -} - -func RegisterExpanderServer(s *grpc.Server, srv ExpanderServer) { - s.RegisterService(&_Expander_serviceDesc, srv) -} - -func _Expander_BestOptions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(BestOptionsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ExpanderServer).BestOptions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpcplugin.Expander/BestOptions", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ExpanderServer).BestOptions(ctx, req.(*BestOptionsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _Expander_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpcplugin.Expander", - HandlerType: (*ExpanderServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "BestOptions", - Handler: _Expander_BestOptions_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "cluster-autoscaler/expander/grpcplugin/protos/expander.proto", + File_expander_proto = out.File + file_expander_proto_rawDesc = nil + file_expander_proto_goTypes = nil + file_expander_proto_depIdxs = nil } diff --git a/cluster-autoscaler/expander/grpcplugin/protos/expander.proto b/cluster-autoscaler/expander/grpcplugin/protos/expander.proto index 5a08e8ff301b..8300ed49695e 100644 --- a/cluster-autoscaler/expander/grpcplugin/protos/expander.proto +++ b/cluster-autoscaler/expander/grpcplugin/protos/expander.proto @@ -27,4 +27,5 @@ message Option { int32 nodeCount = 2; string debug = 3; repeated k8s.io.api.core.v1.Pod pod = 4; + repeated string similarNodeGroupIds = 5; } diff --git a/cluster-autoscaler/expander/grpcplugin/protos/expander_grpc.pb.go b/cluster-autoscaler/expander/grpcplugin/protos/expander_grpc.pb.go new file mode 100644 index 000000000000..59b276756ea9 --- /dev/null +++ b/cluster-autoscaler/expander/grpcplugin/protos/expander_grpc.pb.go @@ -0,0 +1,114 @@ +/* +Copyright 2021 The Kubernetes 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 protos + +import ( + context "context" + + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// ExpanderClient is the client API for Expander service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ExpanderClient interface { + BestOptions(ctx context.Context, in *BestOptionsRequest, opts ...grpc.CallOption) (*BestOptionsResponse, error) +} + +type expanderClient struct { + cc grpc.ClientConnInterface +} + +func NewExpanderClient(cc grpc.ClientConnInterface) ExpanderClient { + return &expanderClient{cc} +} + +func (c *expanderClient) BestOptions(ctx context.Context, in *BestOptionsRequest, opts ...grpc.CallOption) (*BestOptionsResponse, error) { + out := new(BestOptionsResponse) + err := c.cc.Invoke(ctx, "/grpcplugin.Expander/BestOptions", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ExpanderServer is the server API for Expander service. +// All implementations should embed UnimplementedExpanderServer +// for forward compatibility +type ExpanderServer interface { + BestOptions(context.Context, *BestOptionsRequest) (*BestOptionsResponse, error) +} + +// UnimplementedExpanderServer should be embedded to have forward compatible implementations. +type UnimplementedExpanderServer struct { +} + +func (UnimplementedExpanderServer) BestOptions(context.Context, *BestOptionsRequest) (*BestOptionsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method BestOptions not implemented") +} + +// UnsafeExpanderServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ExpanderServer will +// result in compilation errors. +type UnsafeExpanderServer interface { + mustEmbedUnimplementedExpanderServer() +} + +func RegisterExpanderServer(s grpc.ServiceRegistrar, srv ExpanderServer) { + s.RegisterService(&Expander_ServiceDesc, srv) +} + +func _Expander_BestOptions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BestOptionsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ExpanderServer).BestOptions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpcplugin.Expander/BestOptions", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ExpanderServer).BestOptions(ctx, req.(*BestOptionsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Expander_ServiceDesc is the grpc.ServiceDesc for Expander service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Expander_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "grpcplugin.Expander", + HandlerType: (*ExpanderServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "BestOptions", + Handler: _Expander_BestOptions_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "expander.proto", +}