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, ¶ms) 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, ¶ms) + 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) +}