Skip to content

Commit 9e8e584

Browse files
committed
Return generated instance names from autoscaling GCE client
When there are multiple `createInstances` requests sent in a sequence, the next request must be aware of the instance names used by the previous request. Without this change sending a sequence of create instances requests would result in the instance name duplication error.
1 parent 30b4fcc commit 9e8e584

File tree

4 files changed

+37
-10
lines changed

4 files changed

+37
-10
lines changed

cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ type AutoscalingGceClient interface {
138138
// modifying resources
139139
ResizeMig(GceRef, int64) error
140140
DeleteInstances(migRef GceRef, instances []GceRef) error
141-
CreateInstances(GceRef, string, int64, []string) error
141+
CreateInstances(GceRef, string, int64, []string) ([]string, error)
142142

143143
// WaitForOperation can be used to poll GCE operations until completion/timeout using WAIT calls.
144144
// Calling this is normally not needed when interacting with the client, other methods should call it internally.
@@ -296,24 +296,26 @@ func (client *autoscalingGceClientV1) ResizeMig(migRef GceRef, size int64) error
296296
return client.WaitForOperation(op.Name, op.OperationType, migRef.Project, migRef.Zone)
297297
}
298298

299-
func (client *autoscalingGceClientV1) CreateInstances(migRef GceRef, baseName string, delta int64, existingInstanceProviderIds []string) error {
299+
func (client *autoscalingGceClientV1) CreateInstances(migRef GceRef, baseName string, delta int64, existingInstanceProviderIds []string) ([]string, error) {
300300
registerRequest("instance_group_managers", "create_instances")
301301
ctx, cancel := context.WithTimeout(context.Background(), client.operationPerCallTimeout)
302302
defer cancel()
303303
req := gce.InstanceGroupManagersCreateInstancesRequest{}
304304
instanceNames := instanceIdsToNamesMap(existingInstanceProviderIds)
305305
req.Instances = make([]*gce.PerInstanceConfig, 0, delta)
306-
for i := int64(0); i < delta; i++ {
306+
names := make([]string, delta)
307+
for i := range delta {
307308
newInstanceName := generateInstanceName(baseName, instanceNames)
308309
instanceNames[newInstanceName] = true
310+
names[i] = newInstanceName
309311
req.Instances = append(req.Instances, &gce.PerInstanceConfig{Name: newInstanceName})
310312
}
311313

312314
op, err := client.gceService.InstanceGroupManagers.CreateInstances(migRef.Project, migRef.Zone, migRef.Name, &req).Context(ctx).Do()
313315
if err != nil {
314-
return err
316+
return nil, err
315317
}
316-
return client.WaitForOperation(op.Name, op.OperationType, migRef.Project, migRef.Zone)
318+
return names, client.WaitForOperation(op.Name, op.OperationType, migRef.Project, migRef.Zone)
317319
}
318320

319321
func instanceIdsToNamesMap(instanceProviderIds []string) map[string]bool {

cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client_test.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"net/http"
2424
"os"
2525
"regexp"
26+
"strings"
2627
"testing"
2728
"time"
2829

@@ -34,6 +35,7 @@ import (
3435
"github.com/google/go-cmp/cmp/cmpopts"
3536
"github.com/stretchr/testify/assert"
3637
"github.com/stretchr/testify/mock"
38+
"github.com/stretchr/testify/require"
3739
gce_api "google.golang.org/api/compute/v1"
3840
)
3941

@@ -693,7 +695,8 @@ func TestAutoscalingClientTimeouts(t *testing.T) {
693695
}{
694696
"CreateInstances_ContextTimeout": {
695697
clientFunc: func(client *autoscalingGceClientV1) error {
696-
return client.CreateInstances(GceRef{}, "", 0, nil)
698+
_, err := client.CreateInstances(GceRef{}, "", 0, nil)
699+
return err
697700
},
698701
operationPerCallTimeout: &instantTimeout,
699702
},
@@ -760,7 +763,8 @@ func TestAutoscalingClientTimeouts(t *testing.T) {
760763
},
761764
"CreateInstances_HttpClientTimeout": {
762765
clientFunc: func(client *autoscalingGceClientV1) error {
763-
return client.CreateInstances(GceRef{}, "", 0, nil)
766+
_, err := client.CreateInstances(GceRef{}, "", 0, nil)
767+
return err
764768
},
765769
httpTimeout: instantTimeout,
766770
},
@@ -892,6 +896,26 @@ func TestAutoscalingClientTimeouts(t *testing.T) {
892896
}
893897
}
894898

899+
func TestCreateInstances(t *testing.T) {
900+
server := test_util.NewHttpServerMock()
901+
defer server.Close()
902+
b, err := json.Marshal(gce_api.Operation{
903+
Name: "operation-2505728466148-216f5197",
904+
})
905+
assert.NoError(t, err)
906+
server.On("handle", "/projects/project1/zones/us-central1-b/instanceGroupManagers/igm1/createInstances").Return(string(b)).Times(1)
907+
server.On("handle", "/projects/project1/zones/us-central1-b/operations/operation-2505728466148-216f5197/wait").Return(operationDoneResponse).Once()
908+
client := newTestAutoscalingGceClientWithTimeout(t, "project", server.URL, "", time.Second)
909+
migRef := GceRef{Project: "project1", Zone: "us-central1-b", Name: "igm1"}
910+
names, err := client.CreateInstances(migRef, migRef.Name, 10, nil)
911+
assert.NoError(t, err)
912+
assert.Len(t, names, 10, "Expected 10 instance names in result")
913+
for _, name := range names {
914+
prefixed := strings.HasPrefix(name, migRef.Name+"-")
915+
require.Truef(t, prefixed, "Expected node name \"%v\" to be prefixed with \"%v\"", name, migRef.Name)
916+
}
917+
}
918+
895919
func TestFetchAllInstances(t *testing.T) {
896920
igm1 := "projects/893226960234/zones/zones/instanceGroupManagers/test-igm1-grp"
897921
igm2 := "projects/893226960234/zones/zones/instanceGroupManagers/test-igm2-grp"

cluster-autoscaler/cloudprovider/gce/gce_manager.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ func (m *gceManagerImpl) CreateInstances(mig Mig, delta int64) error {
333333
return fmt.Errorf("can't upscale %s: failed to collect BaseInstanceName: %w", mig.GceRef(), err)
334334
}
335335
m.cache.InvalidateMigTargetSize(mig.GceRef())
336-
return m.GceService.CreateInstances(mig.GceRef(), baseName, delta, instancesNames)
336+
_, err = m.GceService.CreateInstances(mig.GceRef(), baseName, delta, instancesNames)
337+
return err
337338
}
338339

339340
func (m *gceManagerImpl) forceRefresh() error {

cluster-autoscaler/cloudprovider/gce/mig_info_provider_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ func (client *mockAutoscalingGceClient) DeleteInstances(_ GceRef, _ []GceRef) er
192192
return nil
193193
}
194194

195-
func (client *mockAutoscalingGceClient) CreateInstances(_ GceRef, _ string, _ int64, _ []string) error {
196-
return nil
195+
func (client *mockAutoscalingGceClient) CreateInstances(_ GceRef, _ string, _ int64, _ []string) ([]string, error) {
196+
return nil, nil
197197
}
198198

199199
func (client *mockAutoscalingGceClient) WaitForOperation(_, _, _, _ string) error {

0 commit comments

Comments
 (0)