Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions cluster-autoscaler/cloudprovider/externalgrpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,7 @@ The `CloudProvider` interface was designed with the assumption that its implemen

### Code Generation

To regenerate the gRPC code:

1. install `protoc` and `protoc-gen-go-grpc`:

```bash
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.31
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3
```

2. import proto dependencies using go modules
```bash
go mod vendor
```

3. generate gRPC client and server code:

```bash
protoc \
-I ./cluster-autoscaler \
-I ./cluster-autoscaler/vendor \
--go_out=. \
--go-grpc_out=. \
./cluster-autoscaler/cloudprovider/externalgrpc/protos/externalgrpc.proto
```
To regenerate the gRPC code, run the `cluster-autoscaler/hack/update-proto.sh` script
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script didn't work for me in naive linux/macOS environments, but let's set that aside, I'll fix as a follow-up

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was lazy and just relied on the local author to unpack a protoc release ... updated with actual OS/arch detection, download, and unpack

It now works from a clean checkout for me on linux and macos ... see if it works for you


### General considerations

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/anypb"

apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
Expand Down Expand Up @@ -123,8 +124,25 @@ func (w *Wrapper) PricingNodePrice(_ context.Context, req *protos.PricingNodePri
return nil, err
}
reqNode := req.GetNode()
reqStartTime := req.GetStartTime()
reqEndTime := req.GetEndTime()

var reqStartTime *metav1.Time
if startTimestamp := req.GetStartTimestamp(); startTimestamp != nil {
// read standard protobuf timestamp if set
reqStartTime = &metav1.Time{Time: startTimestamp.AsTime()}
} else {
// otherwise fallback to reading metav1.Time
reqStartTime = req.GetStartTime()
}

var reqEndTime *metav1.Time
if endTimestamp := req.GetEndTimestamp(); endTimestamp != nil {
// read standard protobuf timestamp if set
reqEndTime = &metav1.Time{Time: endTimestamp.AsTime()}
} else {
// otherwise fallback to reading metav1.Time
reqEndTime = req.GetEndTime()
}

if reqNode == nil || reqStartTime == nil || reqEndTime == nil {
return nil, fmt.Errorf("request fields were nil")
}
Expand All @@ -148,9 +166,38 @@ func (w *Wrapper) PricingPodPrice(_ context.Context, req *protos.PricingPodPrice
}
return nil, err
}
reqPod := req.GetPod()
reqStartTime := req.GetStartTime()
reqEndTime := req.GetEndTime()

var reqPod *apiv1.Pod
if podBytes := req.GetPodBytes(); podBytes != nil {
// decode from opaque bytes into pod if set
pod := &apiv1.Pod{}
if err := pod.Unmarshal(podBytes); err != nil {
return nil, err
}
reqPod = pod
} else {
// otherwise fallback to reading inlined pod
reqPod = req.GetPod()
}

var reqStartTime *metav1.Time
if startTimestamp := req.GetStartTimestamp(); startTimestamp != nil {
// read standard protobuf timestamp if set
reqStartTime = &metav1.Time{Time: startTimestamp.AsTime()}
} else {
// otherwise fallback to reading metav1.Time
reqStartTime = req.GetStartTime()
}

var reqEndTime *metav1.Time
if endTimestamp := req.GetEndTimestamp(); endTimestamp != nil {
// read standard protobuf timestamp if set
reqEndTime = &metav1.Time{Time: endTimestamp.AsTime()}
} else {
// otherwise fallback to reading metav1.Time
reqEndTime = req.GetEndTime()
}

if reqPod == nil || reqStartTime == nil || reqEndTime == nil {
return nil, fmt.Errorf("request fields were nil")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"

apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -162,6 +164,9 @@ func (m *pricingModel) NodePrice(node *apiv1.Node, startTime time.Time, endTime
Node: externalGrpcNode(node),
StartTime: &start,
EndTime: &end,

StartTimestamp: timestamppb.New(startTime),
EndTimestamp: timestamppb.New(endTime),
})
if err != nil {
st, ok := status.FromError(err)
Expand All @@ -182,10 +187,20 @@ func (m *pricingModel) PodPrice(pod *apiv1.Pod, startTime time.Time, endTime tim
klog.V(5).Infof("Performing gRPC call PricingPodPrice for pod %v", pod.Name)
start := metav1.NewTime(startTime)
end := metav1.NewTime(endTime)

podBytes, err := pod.Marshal()
if err != nil {
return 0, err
}

res, err := m.client.PricingPodPrice(ctx, &protos.PricingPodPriceRequest{
Pod: pod,
StartTime: &start,
EndTime: &end,

PodBytes: podBytes,
StartTimestamp: timestamppb.New(startTime),
EndTimestamp: timestamppb.New(endTime),
})
if err != nil {
st, ok := status.FromError(err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/anypb"

apiv1 "k8s.io/api/core/v1"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/externalgrpc/protos"
Expand Down Expand Up @@ -309,15 +310,17 @@ func TestCloudProvider_Pricing(t *testing.T) {
// test correct PodPrice call
m.On(
"PricingPodPrice", mock.Anything, mock.MatchedBy(func(req *protos.PricingPodPriceRequest) bool {
return req.Pod.Name == "pod1"
pod := &apiv1.Pod{}
return pod.Unmarshal(req.PodBytes) == nil && pod.Name == "pod1"
}),
).Return(
&protos.PricingPodPriceResponse{Price: 100},
nil,
)
m.On(
"PricingPodPrice", mock.Anything, mock.MatchedBy(func(req *protos.PricingPodPriceRequest) bool {
return req.Pod.Name == "pod2"
pod := &apiv1.Pod{}
return pod.Unmarshal(req.PodBytes) == nil && pod.Name == "pod2"
}),
).Return(
&protos.PricingPodPriceResponse{Price: 200},
Expand All @@ -341,7 +344,8 @@ func TestCloudProvider_Pricing(t *testing.T) {
// test grpc error for PodPrice
m.On(
"PricingPodPrice", mock.Anything, mock.MatchedBy(func(req *protos.PricingPodPriceRequest) bool {
return req.Pod.Name == "pod3"
pod := &apiv1.Pod{}
return pod.Unmarshal(req.PodBytes) == nil && pod.Name == "pod3"
}),
).Return(
&protos.PricingPodPriceResponse{},
Expand All @@ -357,7 +361,8 @@ func TestCloudProvider_Pricing(t *testing.T) {
// test notImplemented for PodPrice
m.On(
"PricingPodPrice", mock.Anything, mock.MatchedBy(func(req *protos.PricingPodPriceRequest) bool {
return req.Pod.Name == "pod4"
pod := &apiv1.Pod{}
return pod.Unmarshal(req.PodBytes) == nil && pod.Name == "pod4"
}),
).Return(
&protos.PricingPodPriceResponse{},
Expand Down
Loading
Loading