From 27e8681ea6018d9ad6d28e4ecf23e038ade891d8 Mon Sep 17 00:00:00 2001 From: Stephanie Ahart Date: Thu, 22 Jan 2026 13:54:23 -0800 Subject: [PATCH 1/3] fix: Nebius ListInstances pagination --- v1/providers/nebius/instance.go | 41 ++++++++++++++++--------- v1/providers/nebius/integration_test.go | 20 +++++++----- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/v1/providers/nebius/instance.go b/v1/providers/nebius/instance.go index 6593313..75cc246 100644 --- a/v1/providers/nebius/instance.go +++ b/v1/providers/nebius/instance.go @@ -693,22 +693,33 @@ func (c *NebiusClient) ListInstances(ctx context.Context, args v1.ListInstancesA // Collect instances from all projects allNebiusInstances := make([]*compute.Instance, 0) for projectID := range projectToRegion { - response, err := c.sdk.Services().Compute().V1().Instance().List(ctx, &compute.ListInstancesRequest{ - ParentId: projectID, - }) - if err != nil { - c.logger.Error(ctx, fmt.Errorf("failed to list instances in project %s: %w", projectID, err), - v1.LogField("projectID", projectID)) - // Continue to next project instead of failing completely - continue - } + var pageToken string + for { + response, err := c.sdk.Services().Compute().V1().Instance().List(ctx, &compute.ListInstancesRequest{ + ParentId: projectID, + PageSize: 100, + PageToken: pageToken, + }) + if err != nil { + c.logger.Error(ctx, fmt.Errorf("failed to list instances in project %s: %w", projectID, err), + v1.LogField("projectID", projectID)) + // Continue to next project instead of failing completely + break + } + + if response != nil && response.Items != nil { + c.logger.Info(ctx, "found instances in project", + v1.LogField("projectID", projectID), + v1.LogField("region", projectToRegion[projectID]), + v1.LogField("count", len(response.Items)), + v1.LogField("page", pageToken)) + allNebiusInstances = append(allNebiusInstances, response.Items...) + } - if response != nil && response.Items != nil { - c.logger.Info(ctx, "found instances in project", - v1.LogField("projectID", projectID), - v1.LogField("region", projectToRegion[projectID]), - v1.LogField("count", len(response.Items))) - allNebiusInstances = append(allNebiusInstances, response.Items...) + pageToken = response.GetNextPageToken() + if pageToken == "" { + break + } } } diff --git a/v1/providers/nebius/integration_test.go b/v1/providers/nebius/integration_test.go index 1bc86de..af51865 100644 --- a/v1/providers/nebius/integration_test.go +++ b/v1/providers/nebius/integration_test.go @@ -332,16 +332,22 @@ func TestIntegration_InstanceLifecycle(t *testing.T) { t.Log("WARNING: No public IP available, skipping SSH connectivity test") } - // Step 3: List instances (currently not implemented) + // Step 3: List instances and verify the created instance is present t.Log("Listing instances...") instances, err := client.ListInstances(ctx, v1.ListInstancesArgs{}) - // This is expected to fail with current implementation - if err != nil { - t.Logf("ListInstances failed as expected: %v", err) - assert.Contains(t, err.Error(), "implementation pending") - } else { - t.Logf("Found %d instances", len(instances)) + require.NoError(t, err, "ListInstances should succeed") + t.Logf("Found %d instances", len(instances)) + + // Verify the instance we just created is in the list + var foundCreatedInstance bool + for _, inst := range instances { + if v1.CloudProviderInstanceID(inst.CloudID) == instanceCloudID { + foundCreatedInstance = true + t.Logf("✓ Found created instance %s in list", instanceCloudID) + break + } } + assert.True(t, foundCreatedInstance, "Created instance should be found in ListInstances result") // Step 4: Stop instance t.Logf("Stopping instance: %s", instanceCloudID) From 0eb691c9ed8bc5ef06ec7c507745d89ca77b9e3f Mon Sep 17 00:00:00 2001 From: Stephanie Ahart Date: Thu, 22 Jan 2026 14:20:48 -0800 Subject: [PATCH 2/3] Fix lint issue --- Makefile | 2 +- v1/providers/nebius/integration_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9d3b31c..ad1fbb5 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ GOINSTALL=$(GOCMD) install GOSEC=gosec # Third party tools -ARTIFACT_GOLINT=github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8 +ARTIFACT_GOLINT=github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.6.0 ARTIFACT_GOSEC=github.com/securego/gosec/v2/cmd/gosec@v2.22.8 ARTIFACT_GOFUMPT=mvdan.cc/gofumpt@v0.9.2 diff --git a/v1/providers/nebius/integration_test.go b/v1/providers/nebius/integration_test.go index af51865..6283368 100644 --- a/v1/providers/nebius/integration_test.go +++ b/v1/providers/nebius/integration_test.go @@ -341,7 +341,7 @@ func TestIntegration_InstanceLifecycle(t *testing.T) { // Verify the instance we just created is in the list var foundCreatedInstance bool for _, inst := range instances { - if v1.CloudProviderInstanceID(inst.CloudID) == instanceCloudID { + if inst.CloudID == instanceCloudID { foundCreatedInstance = true t.Logf("✓ Found created instance %s in list", instanceCloudID) break From ea2879199d1e3dc56ff7adf0004939f8d8fd3318 Mon Sep 17 00:00:00 2001 From: Stephanie Ahart Date: Thu, 22 Jan 2026 16:05:04 -0800 Subject: [PATCH 3/3] Break early if response is nil --- v1/providers/nebius/instance.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/v1/providers/nebius/instance.go b/v1/providers/nebius/instance.go index 75cc246..15a33cd 100644 --- a/v1/providers/nebius/instance.go +++ b/v1/providers/nebius/instance.go @@ -707,7 +707,12 @@ func (c *NebiusClient) ListInstances(ctx context.Context, args v1.ListInstancesA break } - if response != nil && response.Items != nil { + // If the response is nil, we've reached the end of the list + if response == nil { + break + } + + if len(response.Items) > 0 { c.logger.Info(ctx, "found instances in project", v1.LogField("projectID", projectID), v1.LogField("region", projectToRegion[projectID]),