From 3c27bac2e73bd29d95ef903020cec1a91d2c22b2 Mon Sep 17 00:00:00 2001
From: Oscar Hermoso <oscarhermoso852@gmail.com>
Date: Sat, 12 Oct 2024 11:58:00 +0800
Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B9=20sweepers,=20but=20now=20they're?=
 =?UTF-8?q?=20working?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/test.yml                    |  6 ++
 CONTRIBUTING.md                               |  6 ++
 internal/provider/load_balancer_resource.go   |  7 +-
 .../provider/load_balancer_resource_test.go   |  4 +-
 internal/provider/server_resource.go          |  5 +-
 internal/provider/server_resource_test.go     | 14 ++--
 internal/provider/ssh_key_resource.go         |  5 +-
 internal/provider/ssh_key_resource_test.go    | 83 +++++++++++++++++--
 internal/provider/sweeper_test.go             | 11 +++
 9 files changed, 123 insertions(+), 18 deletions(-)
 create mode 100644 internal/provider/sweeper_test.go

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1b336e1..6d23266 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -44,6 +44,12 @@ jobs:
         env:
           TF_ACC: '1'
           BINARYLANE_API_TOKEN: ${{ secrets.BINARYLANE_API_TOKEN }}
+      - name: Run sweepers
+        if: failure()
+        run: go test -v  ./internal/provider/... -sweep=all
+        env:
+          TF_ACC: '1'
+          BINARYLANE_API_TOKEN: ${{ secrets.BINARYLANE_API_TOKEN }}
   # unit:
   #   name: Unit Tests
   #   runs-on: ubuntu-latest
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5828523..69ddcfa 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -41,6 +41,12 @@ eval export $(cat .env)
 go test -v ./internal/provider/...
 ```
 
+To run Sweepers:
+
+```sh
+go test -v  ./internal/provider/... -sweep=all
+```
+
 ### Update modules
 
 ```sh
diff --git a/internal/provider/load_balancer_resource.go b/internal/provider/load_balancer_resource.go
index 1898617..ef9f88b 100644
--- a/internal/provider/load_balancer_resource.go
+++ b/internal/provider/load_balancer_resource.go
@@ -129,11 +129,12 @@ func (r *loadBalancerResource) Create(ctx context.Context, req resource.CreateRe
 	tflog.Info(ctx, fmt.Sprintf("Creating Load Balancer: name=%s", data.Name.ValueString()))
 
 	const maxRetries = 3
-	var lbResp binarylane.PostLoadBalancersResponse
+	var lbResp *binarylane.PostLoadBalancersResponse
 
 retryLoop:
 	for i := 0; i < maxRetries; i++ {
-		lbResp, err := r.bc.client.PostLoadBalancersWithResponse(ctx, body)
+		var err error
+		lbResp, err = r.bc.client.PostLoadBalancersWithResponse(ctx, body)
 		if err != nil {
 			tflog.Info(ctx, fmt.Sprintf("Attempted to create new load balancer: request=%+v", body))
 			resp.Diagnostics.AddError(
@@ -174,6 +175,8 @@ retryLoop:
 		return
 	}
 
+	data.Id = types.Int64Value(*lbResp.JSON200.LoadBalancer.Id)
+
 	// Save data into Terraform state
 	resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
 
diff --git a/internal/provider/load_balancer_resource_test.go b/internal/provider/load_balancer_resource_test.go
index a557c1e..798973e 100644
--- a/internal/provider/load_balancer_resource_test.go
+++ b/internal/provider/load_balancer_resource_test.go
@@ -140,8 +140,8 @@ func init() {
 						if err != nil {
 							return fmt.Errorf("Error deleting load balancer %d for test sweep: %w", *lb.Id, err)
 						}
-						if lbResp.StatusCode() != http.StatusOK {
-							return fmt.Errorf("Unexpected status deleting load balancer %d in test sweep: %s", *lb.Id, lbResp.Body)
+						if lbResp.StatusCode() != http.StatusNoContent {
+							return fmt.Errorf("Unexpected status %d deleting load balancer %d in test sweep: %s", lbResp.StatusCode(), *lb.Id, lbResp.Body)
 						}
 						log.Println("Deleted load balancer during test sweep:", *lb.Id)
 					}
diff --git a/internal/provider/server_resource.go b/internal/provider/server_resource.go
index c125068..9bbd898 100644
--- a/internal/provider/server_resource.go
+++ b/internal/provider/server_resource.go
@@ -259,11 +259,12 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
 	}
 
 	const maxRetries = 3
-	var serverResp binarylane.PostServersResponse
+	var serverResp *binarylane.PostServersResponse
 
 retryLoop:
 	for i := 0; i < maxRetries; i++ {
-		serverResp, err := r.bc.client.PostServersWithResponse(ctx, body)
+		var err error
+		serverResp, err = r.bc.client.PostServersWithResponse(ctx, body)
 		if err != nil {
 			resp.Diagnostics.AddError(
 				fmt.Sprintf("Error creating server: name=%s", data.Name.ValueString()),
diff --git a/internal/provider/server_resource_test.go b/internal/provider/server_resource_test.go
index eaaf695..7a80f3e 100644
--- a/internal/provider/server_resource_test.go
+++ b/internal/provider/server_resource_test.go
@@ -119,8 +119,7 @@ echo "Hello World" > /var/tmp/output.txt
 
 func init() {
 	resource.AddTestSweepers("server", &resource.Sweeper{
-		Name:         "server",
-		Dependencies: []string{},
+		Name: "server",
 		F: func(_ string) error {
 			endpoint := os.Getenv("BINARYLANE_API_ENDPOINT")
 			if endpoint == "" {
@@ -161,12 +160,17 @@ func init() {
 				servers := *serverResp.JSON200.Servers
 				for _, s := range servers {
 					if strings.HasPrefix(*s.Name, "tf-test-") {
-						serverResp, err := client.DeleteLoadBalancersLoadBalancerIdWithResponse(ctx, *s.Id)
+						reason := "Terraform deletion"
+						params := binarylane.DeleteServersServerIdParams{
+							Reason: &reason,
+						}
+
+						serverResp, err := client.DeleteServersServerIdWithResponse(ctx, *s.Id, &params)
 						if err != nil {
 							return fmt.Errorf("Error deleting server %d during test sweep: %w", *s.Id, err)
 						}
-						if serverResp.StatusCode() != http.StatusOK {
-							return fmt.Errorf("Unexpected status deleting server %d in test sweep: %s", *s.Id, serverResp.Body)
+						if serverResp.StatusCode() != http.StatusNoContent {
+							return fmt.Errorf("Unexpected status %d deleting server %d in test sweep: %s", serverResp.StatusCode(), *s.Id, serverResp.Body)
 						}
 						log.Println("Deleted server during test sweep:", *s.Id)
 					}
diff --git a/internal/provider/ssh_key_resource.go b/internal/provider/ssh_key_resource.go
index 5030dad..d849163 100644
--- a/internal/provider/ssh_key_resource.go
+++ b/internal/provider/ssh_key_resource.go
@@ -106,11 +106,12 @@ func (r *sshKeyResource) Create(ctx context.Context, req resource.CreateRequest,
 
 	// Create API call logic
 	const maxRetries = 3
-	var sshResp binarylane.PostAccountKeysResponse
+	var sshResp *binarylane.PostAccountKeysResponse
 
 retryLoop:
 	for i := 0; i < maxRetries; i++ {
-		sshResp, err := r.bc.client.PostAccountKeysWithResponse(ctx, binarylane.SshKeyRequest{
+		var err error
+		sshResp, err = r.bc.client.PostAccountKeysWithResponse(ctx, binarylane.SshKeyRequest{
 			Name:      data.Name.ValueString(),
 			Default:   data.Default.ValueBoolPointer(),
 			PublicKey: data.PublicKey.ValueString(),
diff --git a/internal/provider/ssh_key_resource_test.go b/internal/provider/ssh_key_resource_test.go
index 0e04f50..d6d348c 100644
--- a/internal/provider/ssh_key_resource_test.go
+++ b/internal/provider/ssh_key_resource_test.go
@@ -1,9 +1,15 @@
 package provider
 
 import (
+	"context"
 	"crypto/ed25519"
 	"encoding/base64"
 	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"strings"
+	"terraform-provider-binarylane/internal/binarylane"
 	"testing"
 
 	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
@@ -20,7 +26,7 @@ func TestSshKeyResource(t *testing.T) {
 			{
 				Config: providerConfig + `
 resource "binarylane_ssh_key" "test" {
-	name       = "tf_ssh_key_resource_test"
+	name       = "tf-test-key-resource-test"
 	public_key = "` + publicKey + `"
 }
 
@@ -32,13 +38,13 @@ data "binarylane_ssh_key" "test" {
 `,
 				Check: resource.ComposeAggregateTestCheckFunc(
 					// Verify resource values
-					resource.TestCheckResourceAttr("binarylane_ssh_key.test", "name", "tf_ssh_key_resource_test"),
+					resource.TestCheckResourceAttr("binarylane_ssh_key.test", "name", "tf-test-key-resource-test"),
 					resource.TestCheckResourceAttr("binarylane_ssh_key.test", "public_key", publicKey),
 					resource.TestCheckResourceAttr("binarylane_ssh_key.test", "default", "false"),
 					resource.TestCheckResourceAttrSet("binarylane_ssh_key.test", "id"),
 
 					// Verify data source values
-					resource.TestCheckResourceAttr("data.binarylane_ssh_key.test", "name", "tf_ssh_key_resource_test"),
+					resource.TestCheckResourceAttr("data.binarylane_ssh_key.test", "name", "tf-test-key-resource-test"),
 					resource.TestCheckResourceAttrSet("data.binarylane_ssh_key.test", "public_key"), // Ideally would check this is identical, but whitespace is not preserved
 					resource.TestCheckResourceAttr("data.binarylane_ssh_key.test", "default", "false"),
 					resource.TestCheckResourceAttrSet("data.binarylane_ssh_key.test", "id"),
@@ -62,14 +68,14 @@ data "binarylane_ssh_key" "test" {
 			// 			{
 			// 				Config: providerConfig + `
 			// resource "binarylane_ssh_key" "test" {
-			// 	name       = "tf_ssh_key_resource_test"
+			// 	name       = "tf-test-key-resource-test"
 			// 	public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJCsuosklP0T4fJcQDgkeVh7dQu+eV+vev1CfwdUkj7h test@company.internal"
 			// 	default    = true
 			// }
 			// 			`,
 			// 				Check: resource.ComposeAggregateTestCheckFunc(
 			// 					// Verify resource values
-			// 					resource.TestCheckResourceAttr("binarylane_ssh_key.test", "name", "tf_ssh_key_resource_test"),
+			// 					resource.TestCheckResourceAttr("binarylane_ssh_key.test", "name", "tf-test-key-resource-test"),
 			// 					resource.TestCheckResourceAttr("data.binarylane_ssh_key.test", "default", "true"),
 			// 				),
 			// 			},
@@ -106,3 +112,70 @@ func ImportByFingerprint(state *terraform.State) (fingerprint string, err error)
 
 	return rawState["fingerprint"], nil
 }
+
+func init() {
+	resource.AddTestSweepers("ssh_key", &resource.Sweeper{
+		Name: "ssh_key",
+		F: func(_ string) error {
+			endpoint := os.Getenv("BINARYLANE_API_ENDPOINT")
+			if endpoint == "" {
+				endpoint = "https://api.binarylane.com.au/v2"
+			}
+			token := os.Getenv("BINARYLANE_API_TOKEN")
+
+			client, err := binarylane.NewClientWithAuth(
+				endpoint,
+				token,
+			)
+
+			if err != nil {
+				return fmt.Errorf("Error creating Binary Lane API client: %w", err)
+			}
+
+			ctx := context.Background()
+
+			var page int32 = 1
+			perPage := int32(200)
+			nextPage := true
+
+			for nextPage {
+				params := binarylane.GetAccountKeysParams{
+					Page:    &page,
+					PerPage: &perPage,
+				}
+
+				keyResp, err := client.GetAccountKeysWithResponse(ctx, &params)
+				if err != nil {
+					return fmt.Errorf("Error getting SSH keys for test sweep: %w", err)
+				}
+
+				if keyResp.StatusCode() != http.StatusOK {
+					return fmt.Errorf("Unexpected status code getting SSH keys for test sweep: %s", keyResp.Body)
+				}
+
+				keys := keyResp.JSON200.SshKeys
+				for _, k := range keys {
+					if strings.HasPrefix(*k.Name, "tf-test-") {
+
+						keyResp, err := client.DeleteAccountKeysKeyIdWithResponse(ctx, int(*k.Id))
+						if err != nil {
+							return fmt.Errorf("Error deleting SSH key %d for test sweep: %w", *k.Id, err)
+						}
+						if keyResp.StatusCode() != http.StatusNoContent {
+							return fmt.Errorf("Unexpected status %d deleting SSH key %d for test sweep: %s", keyResp.StatusCode(), *k.Id, keyResp.Body)
+						}
+						log.Println("Deleted SSH key for test sweep:", *k.Id)
+					}
+				}
+				if keyResp.JSON200.Links == nil || keyResp.JSON200.Links.Pages == nil || keyResp.JSON200.Links.Pages.Next == nil {
+					nextPage = false
+					break
+				}
+
+				page++
+			}
+
+			return nil
+		},
+	})
+}
diff --git a/internal/provider/sweeper_test.go b/internal/provider/sweeper_test.go
new file mode 100644
index 0000000..fc7c71d
--- /dev/null
+++ b/internal/provider/sweeper_test.go
@@ -0,0 +1,11 @@
+package provider
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestMain(m *testing.M) {
+	resource.TestMain(m)
+}