Skip to content

Commit 43fd1fa

Browse files
authored
Merge pull request #5937 from dbonfigli/fix-externalgrpc-unimplemented
fix(cloudprovider/exteranlgrpc): properly handle unimplemented methods
2 parents 55654c3 + 436a8a0 commit 43fd1fa

File tree

7 files changed

+130
-16
lines changed

7 files changed

+130
-16
lines changed

cluster-autoscaler/cloudprovider/externalgrpc/examples/external-grpc-cloud-provider-service/wrapper/wrapper.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"context"
2121
"fmt"
2222

23+
"google.golang.org/grpc/codes"
24+
"google.golang.org/grpc/status"
2325
"google.golang.org/protobuf/types/known/anypb"
2426
apiv1 "k8s.io/api/core/v1"
2527
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -113,6 +115,9 @@ func (w *Wrapper) PricingNodePrice(_ context.Context, req *protos.PricingNodePri
113115

114116
model, err := w.provider.Pricing()
115117
if err != nil {
118+
if err == cloudprovider.ErrNotImplemented {
119+
return nil, status.Error(codes.Unimplemented, err.Error())
120+
}
116121
return nil, err
117122
}
118123
reqNode := req.GetNode()
@@ -136,6 +141,9 @@ func (w *Wrapper) PricingPodPrice(_ context.Context, req *protos.PricingPodPrice
136141

137142
model, err := w.provider.Pricing()
138143
if err != nil {
144+
if err == cloudprovider.ErrNotImplemented {
145+
return nil, status.Error(codes.Unimplemented, err.Error())
146+
}
139147
return nil, err
140148
}
141149
reqPod := req.GetPod()
@@ -326,6 +334,9 @@ func (w *Wrapper) NodeGroupTemplateNodeInfo(_ context.Context, req *protos.NodeG
326334
}
327335
info, err := ng.TemplateNodeInfo()
328336
if err != nil {
337+
if err == cloudprovider.ErrNotImplemented {
338+
return nil, status.Error(codes.Unimplemented, err.Error())
339+
}
329340
return nil, err
330341
}
331342
return &protos.NodeGroupTemplateNodeInfoResponse{
@@ -355,6 +366,9 @@ func (w *Wrapper) NodeGroupGetOptions(_ context.Context, req *protos.NodeGroupAu
355366
}
356367
opts, err := ng.GetOptions(defaults)
357368
if err != nil {
369+
if err == cloudprovider.ErrNotImplemented {
370+
return nil, status.Error(codes.Unimplemented, err.Error())
371+
}
358372
return nil, err
359373
}
360374
if opts == nil {

cluster-autoscaler/cloudprovider/externalgrpc/externalgrpc_cloud_provider.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import (
2727
"time"
2828

2929
"google.golang.org/grpc"
30+
"google.golang.org/grpc/codes"
3031
"google.golang.org/grpc/credentials"
32+
"google.golang.org/grpc/status"
3133
"gopkg.in/yaml.v2"
3234
apiv1 "k8s.io/api/core/v1"
3335
"k8s.io/apimachinery/pkg/api/resource"
@@ -158,6 +160,10 @@ func (m *pricingModel) NodePrice(node *apiv1.Node, startTime time.Time, endTime
158160
EndTime: &end,
159161
})
160162
if err != nil {
163+
st, ok := status.FromError(err)
164+
if ok && st.Code() == codes.Unimplemented {
165+
return 0, cloudprovider.ErrNotImplemented
166+
}
161167
klog.V(1).Infof("Error on gRPC call PricingNodePrice: %v", err)
162168
return 0, err
163169
}
@@ -178,6 +184,10 @@ func (m *pricingModel) PodPrice(pod *apiv1.Pod, startTime time.Time, endTime tim
178184
EndTime: &end,
179185
})
180186
if err != nil {
187+
st, ok := status.FromError(err)
188+
if ok && st.Code() == codes.Unimplemented {
189+
return 0, cloudprovider.ErrNotImplemented
190+
}
181191
klog.V(1).Infof("Error on gRPC call PricingPodPrice: %v", err)
182192
return 0, err
183193
}

cluster-autoscaler/cloudprovider/externalgrpc/externalgrpc_cloud_provider_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ import (
2323

2424
"github.com/stretchr/testify/assert"
2525
"github.com/stretchr/testify/mock"
26+
"google.golang.org/grpc/codes"
27+
"google.golang.org/grpc/status"
2628
"google.golang.org/protobuf/types/known/anypb"
2729
apiv1 "k8s.io/api/core/v1"
30+
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
2831
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/externalgrpc/protos"
2932
)
3033

@@ -286,6 +289,23 @@ func TestCloudProvider_Pricing(t *testing.T) {
286289
_, err = model.NodePrice(apiv1Node3, time.Time{}, time.Time{})
287290
assert.Error(t, err)
288291

292+
// test notImplemented for NodePrice
293+
m.On(
294+
"PricingNodePrice", mock.Anything, mock.MatchedBy(func(req *protos.PricingNodePriceRequest) bool {
295+
return req.Node.Name == "node4"
296+
}),
297+
).Return(
298+
&protos.PricingNodePriceResponse{},
299+
status.Error(codes.Unimplemented, "mock error"),
300+
)
301+
302+
apiv1Node4 := &apiv1.Node{}
303+
apiv1Node4.Name = "node4"
304+
305+
_, err = model.NodePrice(apiv1Node4, time.Time{}, time.Time{})
306+
assert.Error(t, err)
307+
assert.Equal(t, cloudprovider.ErrNotImplemented, err)
308+
289309
// test correct PodPrice call
290310
m.On(
291311
"PricingPodPrice", mock.Anything, mock.MatchedBy(func(req *protos.PricingPodPriceRequest) bool {
@@ -333,6 +353,24 @@ func TestCloudProvider_Pricing(t *testing.T) {
333353

334354
_, err = model.PodPrice(apiv1Pod3, time.Time{}, time.Time{})
335355
assert.Error(t, err)
356+
357+
// test notImplemented for PodPrice
358+
m.On(
359+
"PricingPodPrice", mock.Anything, mock.MatchedBy(func(req *protos.PricingPodPriceRequest) bool {
360+
return req.Pod.Name == "pod4"
361+
}),
362+
).Return(
363+
&protos.PricingPodPriceResponse{},
364+
status.Error(codes.Unimplemented, "mock error"),
365+
)
366+
367+
apiv1Pod4 := &apiv1.Pod{}
368+
apiv1Pod4.Name = "pod4"
369+
370+
_, err = model.PodPrice(apiv1Pod4, time.Time{}, time.Time{})
371+
assert.Error(t, err)
372+
assert.Equal(t, cloudprovider.ErrNotImplemented, err)
373+
336374
}
337375

338376
func TestCloudProvider_GPULabel(t *testing.T) {

cluster-autoscaler/cloudprovider/externalgrpc/externalgrpc_node_group.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"context"
2121
"sync"
2222

23+
"google.golang.org/grpc/codes"
24+
"google.golang.org/grpc/status"
2325
apiv1 "k8s.io/api/core/v1"
2426
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2527
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
@@ -206,6 +208,10 @@ func (n *NodeGroup) TemplateNodeInfo() (*schedulerframework.NodeInfo, error) {
206208
Id: n.id,
207209
})
208210
if err != nil {
211+
st, ok := status.FromError(err)
212+
if ok && st.Code() == codes.Unimplemented {
213+
return nil, cloudprovider.ErrNotImplemented
214+
}
209215
klog.V(1).Infof("Error on gRPC call NodeGroupTemplateNodeInfo: %v", err)
210216
return nil, err
211217
}
@@ -269,6 +275,10 @@ func (n *NodeGroup) GetOptions(defaults config.NodeGroupAutoscalingOptions) (*co
269275
},
270276
})
271277
if err != nil {
278+
st, ok := status.FromError(err)
279+
if ok && st.Code() == codes.Unimplemented {
280+
return nil, cloudprovider.ErrNotImplemented
281+
}
272282
klog.V(1).Infof("Error on gRPC call NodeGroupGetOptions: %v", err)
273283
return nil, err
274284
}

cluster-autoscaler/cloudprovider/externalgrpc/externalgrpc_node_group_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323

2424
"github.com/stretchr/testify/assert"
2525
"github.com/stretchr/testify/mock"
26+
"google.golang.org/grpc/codes"
27+
"google.golang.org/grpc/status"
2628
apiv1 "k8s.io/api/core/v1"
2729
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2830
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
@@ -208,6 +210,27 @@ func TestCloudProvider_TemplateNodeInfo(t *testing.T) {
208210
_, err = ng4.TemplateNodeInfo()
209211
assert.Error(t, err)
210212

213+
// test notImplemented
214+
m.On(
215+
"NodeGroupTemplateNodeInfo", mock.Anything, mock.MatchedBy(func(req *protos.NodeGroupTemplateNodeInfoRequest) bool {
216+
return req.Id == "nodeGroup5"
217+
}),
218+
).Return(
219+
&protos.NodeGroupTemplateNodeInfoResponse{
220+
NodeInfo: nil,
221+
},
222+
status.Error(codes.Unimplemented, "mock error"),
223+
).Once()
224+
225+
ng5 := NodeGroup{
226+
id: "nodeGroup5",
227+
client: client,
228+
}
229+
230+
_, err = ng5.TemplateNodeInfo()
231+
assert.Error(t, err)
232+
assert.Equal(t, cloudprovider.ErrNotImplemented, err)
233+
211234
}
212235

213236
func TestCloudProvider_GetOptions(t *testing.T) {
@@ -289,6 +312,26 @@ func TestCloudProvider_GetOptions(t *testing.T) {
289312
opts, err = ng3.GetOptions(defaultsOpts)
290313
assert.NoError(t, err)
291314
assert.Nil(t, opts)
315+
316+
// test notImplemented
317+
m.On(
318+
"NodeGroupGetOptions", mock.Anything, mock.MatchedBy(func(req *protos.NodeGroupAutoscalingOptionsRequest) bool {
319+
return req.Id == "nodeGroup4"
320+
}),
321+
).Return(
322+
&protos.NodeGroupAutoscalingOptionsResponse{},
323+
status.Error(codes.Unimplemented, "mock error"),
324+
)
325+
326+
ng4 := NodeGroup{
327+
id: "nodeGroup4",
328+
client: client,
329+
}
330+
331+
_, err = ng4.GetOptions(defaultsOpts)
332+
assert.Error(t, err)
333+
assert.Equal(t, cloudprovider.ErrNotImplemented, err)
334+
292335
}
293336

294337
func TestCloudProvider_TargetSize(t *testing.T) {

cluster-autoscaler/cloudprovider/externalgrpc/protos/externalgrpc.proto

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ service CloudProvider {
4141

4242
// PricingNodePrice returns a theoretical minimum price of running a node for
4343
// a given period of time on a perfectly matching machine.
44-
// Implementation optional.
44+
// Implementation optional: if unimplemented return error code 12 (for `Unimplemented`)
4545
rpc PricingNodePrice(PricingNodePriceRequest)
4646
returns (PricingNodePriceResponse) {}
4747

4848
// PricingPodPrice returns a theoretical minimum price of running a pod for a given
4949
// period of time on a perfectly matching machine.
50-
// Implementation optional.
50+
// Implementation optional: if unimplemented return error code 12 (for `Unimplemented`)
5151
rpc PricingPodPrice(PricingPodPriceRequest)
5252
returns (PricingPodPriceResponse) {}
5353

@@ -103,13 +103,13 @@ service CloudProvider {
103103
// NodeGroupTemplateNodeInfo returns a structure of an empty (as if just started) node,
104104
// with all of the labels, capacity and allocatable information. This will be used in
105105
// scale-up simulations to predict what would a new node look like if a node group was expanded.
106-
// Implementation optional.
106+
// Implementation optional: if unimplemented return error code 12 (for `Unimplemented`)
107107
rpc NodeGroupTemplateNodeInfo(NodeGroupTemplateNodeInfoRequest)
108108
returns (NodeGroupTemplateNodeInfoResponse) {}
109109

110110
// GetOptions returns NodeGroupAutoscalingOptions that should be used for this particular
111-
// NodeGroup. Returning a grpc error will result in using default options.
112-
// Implementation optional.
111+
// NodeGroup.
112+
// Implementation optional: if unimplemented return error code 12 (for `Unimplemented`)
113113
rpc NodeGroupGetOptions(NodeGroupAutoscalingOptionsRequest)
114114
returns (NodeGroupAutoscalingOptionsResponse) {}
115115
}
@@ -371,4 +371,3 @@ message NodeGroupAutoscalingOptionsResponse {
371371
// autoscaling options for the requested node.
372372
NodeGroupAutoscalingOptions nodeGroupAutoscalingOptions = 1;
373373
}
374-

cluster-autoscaler/cloudprovider/externalgrpc/protos/externalgrpc_grpc.pb.go

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)