diff --git a/internal/provider/resource_account_resource.go b/internal/provider/resource_account_resource.go index c399e66..8652e46 100644 --- a/internal/provider/resource_account_resource.go +++ b/internal/provider/resource_account_resource.go @@ -170,6 +170,12 @@ func (r *ResourceAccountResource) Read(ctx context.Context, req resource.ReadReq return } + if httpResp.StatusCode() == 404 { + resp.Diagnostics.AddWarning("Resource account not found", fmt.Sprintf("The resource account (%s) was deleted outside Terraform", data.ID.ValueString())) + resp.State.RemoveResource(ctx) + return + } + if httpResp.StatusCode() != 200 { resp.Diagnostics.AddError(HUM_API_ERR, fmt.Sprintf("Unable to read resource account, unexpected status code: %d, body: %s", httpResp.StatusCode(), httpResp.Body)) return diff --git a/internal/provider/resource_account_resource_test.go b/internal/provider/resource_account_resource_test.go index 4ec3483..93f41cf 100644 --- a/internal/provider/resource_account_resource_test.go +++ b/internal/provider/resource_account_resource_test.go @@ -1,15 +1,21 @@ package provider import ( + "context" "fmt" + "os" "testing" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/humanitec/humanitec-go-autogen" + "github.com/stretchr/testify/assert" ) func TestAccResourceAccountResource(t *testing.T) { id := fmt.Sprintf("gcp-test-%d", time.Now().UnixNano()) + email := fmt.Sprintf("gpc-myemail-%d@email.com", time.Now().UnixNano()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -17,7 +23,7 @@ func TestAccResourceAccountResource(t *testing.T) { Steps: []resource.TestStep{ // Create and Read testing { - Config: testAccResourceAccountResource(id, "gcp-test-1"), + Config: testAccResourceAccountResource(id, "gcp-test-1", email), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("humanitec_resource_account.gcp_test", "id", id), resource.TestCheckResourceAttr("humanitec_resource_account.gcp_test", "name", "gcp-test-1"), @@ -32,7 +38,7 @@ func TestAccResourceAccountResource(t *testing.T) { }, // Update and Read testing { - Config: testAccResourceAccountResource(id, "gcp-test-2"), + Config: testAccResourceAccountResource(id, "gcp-test-2", email), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("humanitec_resource_account.gcp_test", "name", "gcp-test-2"), ), @@ -42,13 +48,65 @@ func TestAccResourceAccountResource(t *testing.T) { }) } -func testAccResourceAccountResource(id, name string) string { +func TestAccResourceAccountResource_DeletedManually(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + id := fmt.Sprintf("gcp-test-%d", time.Now().UnixNano()) + email := fmt.Sprintf("gpc-myemail-%d@email.com", time.Now().UnixNano()) + + orgID := os.Getenv("HUMANITEC_ORG") + token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } + + var client *humanitec.Client + var err error + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + + client, err = NewHumanitecClient(apiHost, token, "test", nil) + assert.NoError(err) + }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccResourceAccountResource(id, "gcp-test-2", email), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_resource_account.gcp_test", "id", id), + func(_ *terraform.State) error { + // Manually delete the resource account via the API + resp, err := client.DeleteResourceAccountWithResponse(ctx, orgID, id) + if err != nil { + return err + } + + if resp.StatusCode() != 204 { + return fmt.Errorf("expected status code 204, got %d, body: %s", resp.StatusCode(), string(resp.Body)) + } + + return nil + }, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccResourceAccountResource(id, name, email string) string { return fmt.Sprintf(` resource "humanitec_resource_account" "gcp_test" { id = "%s" name = "%s" type = "gcp" - credentials = "{}" + credentials = jsonencode({ + client_email = "%s" + private_key = "mykey" + }) } -`, id, name) +`, id, name, email) } diff --git a/internal/provider/resource_agent.go b/internal/provider/resource_agent.go index ed5da1d..9cb1f46 100644 --- a/internal/provider/resource_agent.go +++ b/internal/provider/resource_agent.go @@ -217,7 +217,8 @@ func (a *Agent) Read(ctx context.Context, req resource.ReadRequest, resp *resour } } if agent == nil { - resp.Diagnostics.AddError(HUM_API_ERR, fmt.Sprintf("Can't find agent %s in organization agent list", id)) + resp.Diagnostics.AddWarning("Agent not found", fmt.Sprintf("The agent (%s) was deleted outside Terraform", data.ID.ValueString())) + resp.State.RemoveResource(ctx) return } default: diff --git a/internal/provider/resource_agent_test.go b/internal/provider/resource_agent_test.go index 0579c8a..ed29fa0 100644 --- a/internal/provider/resource_agent_test.go +++ b/internal/provider/resource_agent_test.go @@ -1,16 +1,19 @@ package provider import ( + "context" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" + "os" "testing" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/humanitec/humanitec-go-autogen" "github.com/stretchr/testify/assert" ) @@ -77,7 +80,56 @@ func TestAccAgent(t *testing.T) { // Delete testing automatically occurs in TestCase }, }) +} + +func TestAccResourceAgent_DeletedManually(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + id := fmt.Sprintf("agent-test-%d", time.Now().UnixNano()) + orgID := os.Getenv("HUMANITEC_ORG") + token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } + + var client *humanitec.Client + var err error + publicKeyOne := getPublicKey(t) + publicKeyTwo := getPublicKey(t) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + + client, err = NewHumanitecClient(apiHost, token, "test", nil) + assert.NoError(err) + }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCreateAgent(id, "my agent", publicKeyOne, publicKeyTwo), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_agent.agent_test", "public_keys.#", "2"), + func(_ *terraform.State) error { + // Manually delete the agent via the API + resp, err := client.DeleteAgentWithResponse(ctx, orgID, id) + if err != nil { + return err + } + + if resp.StatusCode() != 204 { + return fmt.Errorf("expected status code 204, got %d, body: %s", resp.StatusCode(), string(resp.Body)) + } + + return nil + }, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) } func testAccCreateAgent(id, description string, publicKey, otherPublicKey string) string { diff --git a/internal/provider/resource_application_test.go b/internal/provider/resource_application_test.go index d9277dd..8116f8b 100644 --- a/internal/provider/resource_application_test.go +++ b/internal/provider/resource_application_test.go @@ -46,6 +46,10 @@ func TestAccResourceApplicationDeletedOutManually(t *testing.T) { orgID := os.Getenv("HUMANITEC_ORG") token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } var client *humanitec.Client var err error @@ -54,7 +58,7 @@ func TestAccResourceApplicationDeletedOutManually(t *testing.T) { PreCheck: func() { testAccPreCheck(t) - client, err = NewHumanitecClient(humanitec.DefaultAPIHost, token, "test", nil) + client, err = NewHumanitecClient(apiHost, token, "test", nil) assert.NoError(err) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, diff --git a/internal/provider/resource_application_user_test.go b/internal/provider/resource_application_user_test.go index cae4561..09d5fc9 100644 --- a/internal/provider/resource_application_user_test.go +++ b/internal/provider/resource_application_user_test.go @@ -58,6 +58,10 @@ func TestAccResourceApplicationUserDeletedManually(t *testing.T) { orgID := os.Getenv("HUMANITEC_ORG") token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } var client *humanitec.Client var err error @@ -66,17 +70,17 @@ func TestAccResourceApplicationUserDeletedManually(t *testing.T) { PreCheck: func() { testAccPreCheck(t) - client, err = NewHumanitecClient(humanitec.DefaultAPIHost, token, "test", nil) + client, err = NewHumanitecClient(apiHost, token, "test", nil) assert.NoError(err) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and Read testing { - Config: testAccResourceApplicationUser(id, testUserID, "owner"), + Config: testAccResourceApplicationUser(id, testUserID, "developer"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("humanitec_application_user.another_user", "id", fmt.Sprintf("%s/%s", id, testUserID)), - resource.TestCheckResourceAttr("humanitec_application_user.another_user", "role", "owner"), + resource.TestCheckResourceAttr("humanitec_application_user.another_user", "role", "developer"), func(_ *terraform.State) error { // Manually delete the application via the API resp, err := client.DeleteApplicationWithResponse(ctx, orgID, id) diff --git a/internal/provider/resource_environment_type_user_test.go b/internal/provider/resource_environment_type_user_test.go index 0a74097..1cf8282 100644 --- a/internal/provider/resource_environment_type_user_test.go +++ b/internal/provider/resource_environment_type_user_test.go @@ -59,6 +59,10 @@ func TestAccResourceEnvironmentTypeUserDeletedManually(t *testing.T) { orgID := os.Getenv("HUMANITEC_ORG") token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } var client *humanitec.Client var err error @@ -67,7 +71,7 @@ func TestAccResourceEnvironmentTypeUserDeletedManually(t *testing.T) { PreCheck: func() { testAccPreCheck(t) - client, err = NewHumanitecClient(humanitec.DefaultAPIHost, token, "test", nil) + client, err = NewHumanitecClient(apiHost, token, "test", nil) assert.NoError(err) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, @@ -79,7 +83,7 @@ func TestAccResourceEnvironmentTypeUserDeletedManually(t *testing.T) { resource.TestCheckResourceAttr("humanitec_environment_type_user.another_user", "id", fmt.Sprintf("%s/%s", id, testUserID)), resource.TestCheckResourceAttr("humanitec_environment_type_user.another_user", "role", "deployer"), func(_ *terraform.State) error { - // Manually delete the application via the API + // Manually delete the environment type via the API resp, err := client.DeleteEnvironmentTypeWithResponse(ctx, orgID, id) if err != nil { return err diff --git a/internal/provider/resource_key_test.go b/internal/provider/resource_key_test.go index 3df7091..fd91e6f 100644 --- a/internal/provider/resource_key_test.go +++ b/internal/provider/resource_key_test.go @@ -1,11 +1,15 @@ package provider import ( + "context" "fmt" + "os" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/humanitec/humanitec-go-autogen" + "github.com/stretchr/testify/assert" ) func TestAccResourceKeys(t *testing.T) { @@ -43,6 +47,73 @@ func TestAccResourceKeys(t *testing.T) { }) } +func TestAccResourceKey_DeletedManually(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + + orgID := os.Getenv("HUMANITEC_ORG") + token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } + + var client *humanitec.Client + var err error + + key := getPublicKey(t) + var id string + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + + client, err = NewHumanitecClient(apiHost, token, "test", nil) + assert.NoError(err) + }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: testAccResourceKey(key), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_key.key_test", "key", key), + resource.TestCheckResourceAttrSet("humanitec_key.key_test", "id"), + resource.TestCheckResourceAttrSet("humanitec_key.key_test", "fingerprint"), + ), + }, + // ImportState testing + { + ResourceName: "humanitec_key.key_test", + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + id = s.RootModule().Resources["humanitec_key.key_test"].Primary.Attributes["id"] + return id, nil + }, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_key.key_test", "key", key), + resource.TestCheckResourceAttr("humanitec_key.key_test", "id", id), + func(_ *terraform.State) error { + // Manually delete the public key via the API + resp, err := client.DeletePublicKeyWithResponse(ctx, orgID, id) + if err != nil { + return err + } + + if resp.StatusCode() != 204 { + return fmt.Errorf("expected status code 204, got %d, body: %s", resp.StatusCode(), string(resp.Body)) + } + + return nil + }, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccResourceKey(key string) string { return fmt.Sprintf(` resource "humanitec_key" "key_test" { diff --git a/internal/provider/resource_resource_class.go b/internal/provider/resource_resource_class.go index 2ecd4b8..58e2dc5 100644 --- a/internal/provider/resource_resource_class.go +++ b/internal/provider/resource_resource_class.go @@ -142,6 +142,12 @@ func (r *ResourceResourceClass) Read(ctx context.Context, req resource.ReadReque return } + if httpResp.StatusCode() == 404 { + resp.Diagnostics.AddWarning("Resource class not found", fmt.Sprintf("The resource class (%s) was deleted outside Terraform", data.ID.ValueString())) + resp.State.RemoveResource(ctx) + return + } + if httpResp.StatusCode() != 200 { resp.Diagnostics.AddError(HUM_API_ERR, fmt.Sprintf("Unable to read resource class, unexpected status code: %d, body: %s", httpResp.StatusCode(), httpResp.Body)) return diff --git a/internal/provider/resource_resource_class_test.go b/internal/provider/resource_resource_class_test.go index 8b2f636..a80fe21 100644 --- a/internal/provider/resource_resource_class_test.go +++ b/internal/provider/resource_resource_class_test.go @@ -1,12 +1,16 @@ package provider import ( + "context" "fmt" + "os" "testing" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/humanitec/humanitec-go-autogen" + "github.com/stretchr/testify/assert" ) func TestAccResourceClass(t *testing.T) { @@ -51,6 +55,56 @@ func TestAccResourceClass(t *testing.T) { }) } +func TestAccResourceClass_DeletedManually(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + id := fmt.Sprintf("test-class-%d", time.Now().UnixNano()) + description := "test-description" + resourceType := "mysql" + + orgID := os.Getenv("HUMANITEC_ORG") + token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } + + var client *humanitec.Client + var err error + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + + client, err = NewHumanitecClient(apiHost, token, "test", nil) + assert.NoError(err) + }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccResourceClass(id, description, resourceType), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_resource_class.class_test", "id", id), + func(_ *terraform.State) error { + // Manually delete the resource class via the API + resp, err := client.DeleteResourceClassWithResponse(ctx, orgID, resourceType, id) + if err != nil { + return err + } + + if resp.StatusCode() != 204 { + return fmt.Errorf("expected status code 204, got %d, body: %s", resp.StatusCode(), string(resp.Body)) + } + + return nil + }, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccResourceClass(id, description, resourceType string) string { return fmt.Sprintf(` resource "humanitec_resource_class" "class_test" { diff --git a/internal/provider/resource_resource_driver.go b/internal/provider/resource_resource_driver.go index b383190..69fde37 100644 --- a/internal/provider/resource_resource_driver.go +++ b/internal/provider/resource_resource_driver.go @@ -212,6 +212,12 @@ func (r *ResourceResourceDriver) Read(ctx context.Context, req resource.ReadRequ return } + if httpResp.StatusCode() == 404 { + resp.Diagnostics.AddWarning("Resource driver not found", fmt.Sprintf("The resource driver (%s) was deleted outside Terraform", data.ID.ValueString())) + resp.State.RemoveResource(ctx) + return + } + if httpResp.StatusCode() != 200 { resp.Diagnostics.AddError(HUM_API_ERR, fmt.Sprintf("Unable to read resource driver, unexpected status code: %d, body: %s", httpResp.StatusCode(), httpResp.Body)) return diff --git a/internal/provider/resource_resource_driver_test.go b/internal/provider/resource_resource_driver_test.go index c26bc16..53dd1d2 100644 --- a/internal/provider/resource_resource_driver_test.go +++ b/internal/provider/resource_resource_driver_test.go @@ -1,11 +1,16 @@ package provider import ( + "context" "fmt" + "os" "testing" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/humanitec/humanitec-go-autogen" + "github.com/stretchr/testify/assert" ) func TestAccResourceResourceDriver(t *testing.T) { @@ -76,6 +81,54 @@ func TestAccResourceResourceDriver(t *testing.T) { } } +func TestAccResourceDriver_DeletedManually(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + id := fmt.Sprintf("driver-%d", time.Now().UnixNano()) + + orgID := os.Getenv("HUMANITEC_ORG") + token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } + + var client *humanitec.Client + var err error + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + + client, err = NewHumanitecClient(apiHost, token, "test", nil) + assert.NoError(err) + }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccResourceResourceDriver(id, "http://driver.driver:8080/driver"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_resource_driver.s3", "target", "http://driver.driver:8080/driver"), + func(_ *terraform.State) error { + // Manually delete the resource driver via the API + resp, err := client.DeleteResourceDriverWithResponse(ctx, orgID, id) + if err != nil { + return err + } + + if resp.StatusCode() != 204 { + return fmt.Errorf("expected status code 204, got %d, body: %s", resp.StatusCode(), string(resp.Body)) + } + + return nil + }, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccResourceResourceDriver(id, target string) string { return fmt.Sprintf(` resource "humanitec_resource_driver" "s3" { diff --git a/internal/provider/resource_rule.go b/internal/provider/resource_rule.go index 0c73bfc..1b23a16 100644 --- a/internal/provider/resource_rule.go +++ b/internal/provider/resource_rule.go @@ -209,6 +209,11 @@ func (r *ResourceRule) Read(ctx context.Context, req resource.ReadRequest, resp resp.Diagnostics.AddError(HUM_CLIENT_ERR, fmt.Sprintf("Unable to read rule, got error: %s", err)) return } + if httpResp.StatusCode() == 404 { + resp.Diagnostics.AddWarning("Rule not found", fmt.Sprintf("The rule (%s) was deleted outside Terraform", data.ID.ValueString())) + resp.State.RemoveResource(ctx) + return + } if httpResp.StatusCode() != 200 { resp.Diagnostics.AddError(HUM_API_ERR, fmt.Sprintf("Unable to read rule, unexpected status code: %d, body: %s", httpResp.StatusCode(), httpResp.Body)) return diff --git a/internal/provider/resource_rule_test.go b/internal/provider/resource_rule_test.go index 2a4244a..9c21a2b 100644 --- a/internal/provider/resource_rule_test.go +++ b/internal/provider/resource_rule_test.go @@ -1,12 +1,16 @@ package provider import ( + "context" "fmt" + "os" "testing" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/humanitec/humanitec-go-autogen" + "github.com/stretchr/testify/assert" ) func TestAccResourceRule(t *testing.T) { @@ -73,6 +77,71 @@ func TestAccResourceRule(t *testing.T) { } } +func TestAccResourceRule_DeletedManually(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + appId := fmt.Sprintf("tf-rule-%d", time.Now().UnixNano()) + + orgID := os.Getenv("HUMANITEC_ORG") + token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } + + var client *humanitec.Client + var err error + var id string + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + + client, err = NewHumanitecClient(apiHost, token, "test", nil) + assert.NoError(err) + }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccResourceRule(appId, "my-artefact"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_rule.rule1", "artefacts_filter.0", "my-artefact"), + ), + }, + { + ResourceName: "humanitec_rule.rule1", + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + rule, err := testResource("humanitec_rule.rule1", s) + if err != nil { + return "", err + } + id = fmt.Sprintf("%s/dev/%s", appId, rule.Primary.ID) + return id, nil + }, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_rule.rule1", "id", id), + func(_ *terraform.State) error { + // Manually delete the rule via the API + resp, err := client.DeleteAutomationRuleWithResponse(ctx, orgID, appId, "dev", id) + if err != nil { + return err + } + + if resp.StatusCode() != 204 { + return fmt.Errorf("expected status code 204, got %d, body: %s", resp.StatusCode(), string(resp.Body)) + } + + return nil + }, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccResourceRule(appID, artefact string) string { return fmt.Sprintf(` resource "humanitec_application" "rule_test" { diff --git a/internal/provider/resource_secret_store.go b/internal/provider/resource_secret_store.go index 0ea86d3..d97e6fc 100644 --- a/internal/provider/resource_secret_store.go +++ b/internal/provider/resource_secret_store.go @@ -377,6 +377,13 @@ func (s *SecretStore) Read(ctx context.Context, req resource.ReadRequest, resp * resp.Diagnostics.AddError(HUM_CLIENT_ERR, fmt.Sprintf("Unable to read secret store, got error: %s", err)) return } + + if httpResp.StatusCode() == 404 { + resp.Diagnostics.AddWarning("Secret store not found", fmt.Sprintf("The secret store (%s) was deleted outside Terraform", data.ID.ValueString())) + resp.State.RemoveResource(ctx) + return + } + if httpResp.StatusCode() != 200 { resp.Diagnostics.AddError(HUM_API_ERR, fmt.Sprintf("Unable to read secret store, unexpected status code: %d, body: %s", httpResp.StatusCode(), httpResp.Body)) return diff --git a/internal/provider/resource_secret_store_test.go b/internal/provider/resource_secret_store_test.go index e1c2627..89bc2dd 100644 --- a/internal/provider/resource_secret_store_test.go +++ b/internal/provider/resource_secret_store_test.go @@ -1,12 +1,16 @@ package provider import ( + "context" "fmt" + "os" "testing" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/humanitec/humanitec-go-autogen" + "github.com/stretchr/testify/assert" ) func TestAccResourceSecretStore_AzureKV(t *testing.T) { @@ -209,6 +213,54 @@ func TestAccResourceSecretStore_Vault_RemoveAuth(t *testing.T) { }) } +func TestAccResourceSecretStore_DeletedManually(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + id := fmt.Sprintf("secret-store-%d", time.Now().UnixNano()) + + orgID := os.Getenv("HUMANITEC_ORG") + token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } + + var client *humanitec.Client + var err error + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + + client, err = NewHumanitecClient(apiHost, token, "test", nil) + assert.NoError(err) + }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccSecretStoreVaultNoAuth(id, "dumburl", false), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("humanitec_secretstore.secret_store_vault_test", "vault.url", "dumburl"), + func(_ *terraform.State) error { + // Manually delete the secret store via the API + resp, err := client.DeleteOrgsOrgIdSecretstoresStoreIdWithResponse(ctx, orgID, id) + if err != nil { + return err + } + + if resp.StatusCode() != 204 { + return fmt.Errorf("expected status code 204, got %d, body: %s", resp.StatusCode(), string(resp.Body)) + } + + return nil + }, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccSecretStoreAzureKV(storeID, tenantID, url, clientID, clientSecret string) string { return fmt.Sprintf(` resource "humanitec_secretstore" "secret_store_azurekv_test" { diff --git a/internal/provider/resource_value_test.go b/internal/provider/resource_value_test.go index 5801d86..cae3131 100644 --- a/internal/provider/resource_value_test.go +++ b/internal/provider/resource_value_test.go @@ -197,6 +197,10 @@ func TestAccResourceValueDeletedOutManually(t *testing.T) { orgID := os.Getenv("HUMANITEC_ORG") token := os.Getenv("HUMANITEC_TOKEN") + apiHost := os.Getenv("HUMANITEC_HOST") + if apiHost == "" { + apiHost = humanitec.DefaultAPIHost + } var client *humanitec.Client var err error @@ -205,7 +209,7 @@ func TestAccResourceValueDeletedOutManually(t *testing.T) { PreCheck: func() { testAccPreCheck(t) - client, err = NewHumanitecClient(humanitec.DefaultAPIHost, token, "test", nil) + client, err = NewHumanitecClient(apiHost, token, "test", nil) assert.NoError(err) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,