diff --git a/docs/resources/account.md b/docs/resources/account.md index b2439160..d9a22996 100644 --- a/docs/resources/account.md +++ b/docs/resources/account.md @@ -48,5 +48,5 @@ Import is supported using the following syntax: ```shell # Prefect Accounts can be imported using the account's UUID -terraform import prefect_account.example account-uuid +terraform import prefect_account.example 00000000-0000-0000-0000-000000000000 ``` diff --git a/docs/resources/variable.md b/docs/resources/variable.md index a4715c44..3ffc052f 100644 --- a/docs/resources/variable.md +++ b/docs/resources/variable.md @@ -48,5 +48,5 @@ Import is supported using the following syntax: terraform import prefect_variable.example name/name-of-variable # Prefect Variables can also be imported via UUID -terraform import prefect_variable.example variable-uuid +terraform import prefect_variable.example 00000000-0000-0000-0000-000000000000 ``` diff --git a/docs/resources/workspace.md b/docs/resources/workspace.md index e5150603..1e12eff1 100644 --- a/docs/resources/workspace.md +++ b/docs/resources/workspace.md @@ -47,5 +47,5 @@ Import is supported using the following syntax: terraform import prefect_workspace.example handle/workspace-handle # Prefect Workspaces can also be imported via UUID -terraform import prefect_workspace.example workspace-uuid +terraform import prefect_workspace.example 00000000-0000-0000-0000-000000000000 ``` diff --git a/docs/resources/workspace_role.md b/docs/resources/workspace_role.md index 66fdcb0f..29ea81f5 100644 --- a/docs/resources/workspace_role.md +++ b/docs/resources/workspace_role.md @@ -48,5 +48,5 @@ Import is supported using the following syntax: ```shell # Prefect Workspace Roles can be imported using the workspace role's UUID -terraform import prefect_workspace_role.example workspace-role-uuid +terraform import prefect_workspace_role.example 00000000-0000-0000-0000-000000000000 ``` diff --git a/examples/resources/prefect_account/import.sh b/examples/resources/prefect_account/import.sh index e7dd3aff..1cf72a0d 100644 --- a/examples/resources/prefect_account/import.sh +++ b/examples/resources/prefect_account/import.sh @@ -1,2 +1,2 @@ # Prefect Accounts can be imported using the account's UUID -terraform import prefect_account.example account-uuid +terraform import prefect_account.example 00000000-0000-0000-0000-000000000000 diff --git a/examples/resources/prefect_variable/import.sh b/examples/resources/prefect_variable/import.sh index 99725471..18f9a1d8 100644 --- a/examples/resources/prefect_variable/import.sh +++ b/examples/resources/prefect_variable/import.sh @@ -2,4 +2,4 @@ terraform import prefect_variable.example name/name-of-variable # Prefect Variables can also be imported via UUID -terraform import prefect_variable.example variable-uuid +terraform import prefect_variable.example 00000000-0000-0000-0000-000000000000 diff --git a/examples/resources/prefect_workspace/import.sh b/examples/resources/prefect_workspace/import.sh index b5c29503..a509469c 100644 --- a/examples/resources/prefect_workspace/import.sh +++ b/examples/resources/prefect_workspace/import.sh @@ -2,4 +2,4 @@ terraform import prefect_workspace.example handle/workspace-handle # Prefect Workspaces can also be imported via UUID -terraform import prefect_workspace.example workspace-uuid +terraform import prefect_workspace.example 00000000-0000-0000-0000-000000000000 diff --git a/examples/resources/prefect_workspace_role/import.sh b/examples/resources/prefect_workspace_role/import.sh index cae31fd7..06998fae 100644 --- a/examples/resources/prefect_workspace_role/import.sh +++ b/examples/resources/prefect_workspace_role/import.sh @@ -1,2 +1,2 @@ # Prefect Workspace Roles can be imported using the workspace role's UUID -terraform import prefect_workspace_role.example workspace-role-uuid +terraform import prefect_workspace_role.example 00000000-0000-0000-0000-000000000000 diff --git a/internal/provider/datasources/account_test.go b/internal/provider/datasources/account_test.go new file mode 100644 index 00000000..04b28067 --- /dev/null +++ b/internal/provider/datasources/account_test.go @@ -0,0 +1,37 @@ +package datasources_test + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/prefecthq/terraform-provider-prefect/internal/testutils" +) + +func fixtureAccAccount() string { + return fmt.Sprintf(` +data "prefect_account" "test" { + id = "%s" +} + `, os.Getenv("PREFECT_CLOUD_ACCOUNT_ID")) +} + +//nolint:paralleltest // we use the resource.ParallelTest helper instead +func TestAccDatasource_account(t *testing.T) { + datasourceName := "data.prefect_account.test" + resource.ParallelTest(t, resource.TestCase{ + ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, + PreCheck: func() { testutils.AccTestPreCheck(t) }, + Steps: []resource.TestStep{ + { + Config: fixtureAccAccount(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(datasourceName, "id", os.Getenv("PREFECT_CLOUD_ACCOUNT_ID")), + resource.TestCheckResourceAttrSet(datasourceName, "name"), + resource.TestCheckResourceAttrSet(datasourceName, "handle"), + ), + }, + }, + }) +} diff --git a/internal/provider/datasources/variable_test.go b/internal/provider/datasources/variable_test.go new file mode 100644 index 00000000..b9cc44e0 --- /dev/null +++ b/internal/provider/datasources/variable_test.go @@ -0,0 +1,42 @@ +package datasources_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/prefecthq/terraform-provider-prefect/internal/testutils" +) + +func fixtureAccVariableByName(name string) string { + return fmt.Sprintf(` + data "prefect_workspace" "evergreen" { + handle = "evergreen-workspace" + } + data "prefect_variable" "test" { + name = "%s" + workspace_id = data.prefect_workspace.evergreen.id + } + `, name) +} + +//nolint:paralleltest // we use the resource.ParallelTest helper instead +func TestAccDatasource_variable(t *testing.T) { + datasourceName := "data.prefect_variable.test" + variableName := "my_variable" + variableValue := "variable value goes here" + resource.ParallelTest(t, resource.TestCase{ + ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, + PreCheck: func() { testutils.AccTestPreCheck(t) }, + Steps: []resource.TestStep{ + { + Config: fixtureAccVariableByName(variableName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(datasourceName, "id"), + resource.TestCheckResourceAttr(datasourceName, "name", variableName), + resource.TestCheckResourceAttr(datasourceName, "value", variableValue), + ), + }, + }, + }) +} diff --git a/internal/provider/resources/account_test.go b/internal/provider/resources/account_test.go new file mode 100644 index 00000000..660fdbb1 --- /dev/null +++ b/internal/provider/resources/account_test.go @@ -0,0 +1,35 @@ +package resources_test + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/prefecthq/terraform-provider-prefect/internal/testutils" +) + +//nolint:paralleltest // we use the resource.ParallelTest helper instead +func TestAccResource_account(t *testing.T) { + resourceName := "prefect_account.test" + + resource.ParallelTest(t, resource.TestCase{ + ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, + PreCheck: func() { testutils.AccTestPreCheck(t) }, + Steps: []resource.TestStep{ + // Import State checks - import by ID (from environment) + // NOTE: the prefect_account resource is a little special in that + // we cannot create an account via API, meaning the TF lifecycle + // will be challenging to test. Instead, we'll ensure that the + // resource can be found and properly imported. Note that + // ImportStateVerify is set to false, as the resource can't be + // saved to state after a Create. + { + Config: `resource "prefect_account" "test" {}`, + ImportStateId: os.Getenv("PREFECT_CLOUD_ACCOUNT_ID"), + ImportState: true, + ResourceName: resourceName, + ImportStateVerify: false, + }, + }, + }) +} diff --git a/internal/provider/resources/service_account.go b/internal/provider/resources/service_account.go index 057ff541..01987b48 100644 --- a/internal/provider/resources/service_account.go +++ b/internal/provider/resources/service_account.go @@ -492,6 +492,6 @@ func (r *ServiceAccountResource) ImportState(ctx context.Context, req resource.I name := strings.TrimPrefix(req.ID, "name/") resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("name"), name)...) } else { - resource.ImportStatePassthroughID(ctx, path.Root("name"), req, resp) + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } } diff --git a/internal/provider/resources/service_account_test.go b/internal/provider/resources/service_account_test.go index 4ac79d53..981fd404 100644 --- a/internal/provider/resources/service_account_test.go +++ b/internal/provider/resources/service_account_test.go @@ -128,6 +128,23 @@ func TestAccResource_service_account(t *testing.T) { resource.TestCheckResourceAttr(botResourceName, "name", botRandomName2), ), }, + // Import State checks - import by name + { + ImportState: true, + ImportStateId: botRandomName2, + ImportStateIdPrefix: "name/", + ResourceName: botResourceName, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "name", + ImportStateVerifyIgnore: []string{"api_key"}, + }, + // Import State checks - import by ID (default) + { + ImportState: true, + ResourceName: botResourceName, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, + }, }, }) } diff --git a/internal/provider/resources/variable_test.go b/internal/provider/resources/variable_test.go new file mode 100644 index 00000000..7da916a4 --- /dev/null +++ b/internal/provider/resources/variable_test.go @@ -0,0 +1,143 @@ +package resources_test + +import ( + "context" + "fmt" + "testing" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/prefecthq/terraform-provider-prefect/internal/api" + "github.com/prefecthq/terraform-provider-prefect/internal/testutils" +) + +func fixtureAccVariableResource(name string, value string) string { + return fmt.Sprintf(` +data "prefect_workspace" "evergreen" { + handle = "evergreen-workspace" +} +resource "prefect_variable" "test" { + workspace_id = data.prefect_workspace.evergreen.id + name = "%s" + value = "%s" +} + `, name, value) +} + +func fixtureAccVariableResourceWithTags(name string, value string) string { + return fmt.Sprintf(` +data "prefect_workspace" "evergreen" { + handle = "evergreen-workspace" +} +resource "prefect_variable" "test" { + workspace_id = data.prefect_workspace.evergreen.id + name = "%s" + value = "%s" + tags = ["foo", "bar"] +} + `, name, value) +} + +//nolint:paralleltest // we use the resource.ParallelTest helper instead +func TestAccResource_variable(t *testing.T) { + resourceName := "prefect_variable.test" + const workspaceDatsourceName = "data.prefect_workspace.evergreen" + + randomName := testutils.TestAccPrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + randomName2 := testutils.TestAccPrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + randomValue := testutils.TestAccPrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + randomValue2 := testutils.TestAccPrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + // We use this variable to store the fetched resource from the API + // and it will be shared between TestSteps via a pointer. + var variable api.Variable + + resource.ParallelTest(t, resource.TestCase{ + ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, + PreCheck: func() { testutils.AccTestPreCheck(t) }, + Steps: []resource.TestStep{ + { + // Check creation + existence of the variable resource + Config: fixtureAccVariableResource(randomName, randomValue), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckVariableExists(resourceName, workspaceDatsourceName, &variable), + testAccCheckVariableValues(&variable, &api.Variable{Name: randomName, Value: randomValue}), + resource.TestCheckResourceAttr(resourceName, "name", randomName), + resource.TestCheckResourceAttr(resourceName, "value", randomValue), + ), + }, + { + // Check updating name + value of the variable resource + Config: fixtureAccVariableResource(randomName2, randomValue2), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckVariableExists(resourceName, workspaceDatsourceName, &variable), + testAccCheckVariableValues(&variable, &api.Variable{Name: randomName2, Value: randomValue2}), + resource.TestCheckResourceAttr(resourceName, "name", randomName2), + resource.TestCheckResourceAttr(resourceName, "value", randomValue2), + ), + }, + { + // Check adding tags + Config: fixtureAccVariableResourceWithTags(randomName2, randomValue2), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckVariableExists(resourceName, workspaceDatsourceName, &variable), + testAccCheckVariableValues(&variable, &api.Variable{Name: randomName2, Value: randomValue2}), + resource.TestCheckResourceAttr(resourceName, "name", randomName2), + resource.TestCheckResourceAttr(resourceName, "value", randomValue2), + resource.TestCheckResourceAttr(resourceName, "tags.#", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.0", "foo"), + resource.TestCheckResourceAttr(resourceName, "tags.1", "bar"), + ), + }, + }, + }) +} + +func testAccCheckVariableExists(variableResourceName string, workspaceDatasourceName string, variable *api.Variable) resource.TestCheckFunc { + return func(state *terraform.State) error { + variableResource, exists := state.RootModule().Resources[variableResourceName] + if !exists { + return fmt.Errorf("Resource not found in state: %s", variableResourceName) + } + variableResourceID, _ := uuid.Parse(variableResource.Primary.ID) + + workspaceDatsource, exists := state.RootModule().Resources[workspaceDatasourceName] + if !exists { + return fmt.Errorf("Resource not found in state: %s", workspaceDatasourceName) + } + workspaceID, _ := uuid.Parse(workspaceDatsource.Primary.ID) + + // Create a new client, and use the default configurations from the environment + c, _ := testutils.NewTestClient() + variablesClient, _ := c.Variables(uuid.Nil, workspaceID) + + variableName := variableResource.Primary.Attributes["name"] + + fetchedVariable, err := variablesClient.Get(context.Background(), variableResourceID) + if err != nil { + return fmt.Errorf("Error fetching variable: %w", err) + } + if fetchedVariable == nil { + return fmt.Errorf("Variable not found for name: %s", variableName) + } + + *variable = *fetchedVariable + + return nil + } +} +func testAccCheckVariableValues(fetchedVariable *api.Variable, valuesToCheck *api.Variable) resource.TestCheckFunc { + return func(state *terraform.State) error { + if fetchedVariable.Name != valuesToCheck.Name { + return fmt.Errorf("Expected variable name to be %s, got %s", valuesToCheck.Name, fetchedVariable.Name) + } + if fetchedVariable.Value != valuesToCheck.Value { + return fmt.Errorf("Expected variable value to be %s, got %s", valuesToCheck.Name, fetchedVariable.Name) + } + + return nil + } +} diff --git a/internal/provider/resources/workspace_role_test.go b/internal/provider/resources/workspace_role_test.go index 76809a93..a900d802 100644 --- a/internal/provider/resources/workspace_role_test.go +++ b/internal/provider/resources/workspace_role_test.go @@ -73,6 +73,13 @@ func TestAccResource_workspace_role(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "scopes.2", "see_work_queues"), ), }, + // Import State checks - import by ID (default) + { + ImportState: true, + ResourceName: resourceName, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"scopes"}, + }, }, }) } diff --git a/internal/provider/resources/workspace_test.go b/internal/provider/resources/workspace_test.go index 48459431..1ac5c51c 100644 --- a/internal/provider/resources/workspace_test.go +++ b/internal/provider/resources/workspace_test.go @@ -69,6 +69,20 @@ func TestAccResource_workspace(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "description", randomDescription), ), }, + // Import State checks - import by handle + { + ImportState: true, + ResourceName: resourceName, + ImportStateId: randomName2, + ImportStateIdPrefix: "handle/", + ImportStateVerify: true, + }, + // Import State checks - import by ID (default) + { + ImportState: true, + ResourceName: resourceName, + ImportStateVerify: true, + }, }, }) }