diff --git a/tfe/data_source_team_access.go b/tfe/data_source_team_access.go index 6252ed0be..49c16ea0d 100644 --- a/tfe/data_source_team_access.go +++ b/tfe/data_source_team_access.go @@ -46,6 +46,11 @@ func dataSourceTFETeamAccess() *schema.Resource { Type: schema.TypeBool, Computed: true, }, + + "run_tasks": { + Type: schema.TypeBool, + Computed: true, + }, }, }, }, diff --git a/tfe/data_source_team_access_test.go b/tfe/data_source_team_access_test.go index efce93836..9185d5939 100644 --- a/tfe/data_source_team_access_test.go +++ b/tfe/data_source_team_access_test.go @@ -33,6 +33,8 @@ func TestAccTFETeamAccessDataSource_basic(t *testing.T) { "data.tfe_team_access.foobar", "permissions.0.sentinel_mocks", "read"), resource.TestCheckResourceAttr( "data.tfe_team_access.foobar", "permissions.0.workspace_locking", "true"), + resource.TestCheckResourceAttr( + "data.tfe_team_access.foobar", "permissions.0.run_tasks", "false"), resource.TestCheckResourceAttrSet("data.tfe_team_access.foobar", "id"), resource.TestCheckResourceAttrSet("data.tfe_team_access.foobar", "team_id"), resource.TestCheckResourceAttrSet("data.tfe_team_access.foobar", "workspace_id"), diff --git a/tfe/resource_tfe_team_access.go b/tfe/resource_tfe_team_access.go index 0548a23cc..48be0a07a 100644 --- a/tfe/resource_tfe_team_access.go +++ b/tfe/resource_tfe_team_access.go @@ -112,6 +112,11 @@ func resourceTFETeamAccess() *schema.Resource { Type: schema.TypeBool, Required: true, }, + + "run_tasks": { + Type: schema.TypeBool, + Required: true, + }, }, }, }, @@ -193,6 +198,12 @@ func resourceTFETeamAccessCreate(d *schema.ResourceData, meta interface{}) error } } + if d.HasChange("permissions.0.run_tasks") { + if v, ok := d.GetOkExists("permissions.0.run_tasks"); ok { + options.RunTasks = tfe.Bool(v.(bool)) + } + } + log.Printf("[DEBUG] Give team %s %s access to workspace: %s", tm.Name, access, ws.Name) tmAccess, err := tfeClient.TeamAccess.Add(ctx, options) if err != nil { @@ -227,6 +238,7 @@ func resourceTFETeamAccessRead(d *schema.ResourceData, meta interface{}) error { "state_versions": tmAccess.StateVersions, "sentinel_mocks": tmAccess.SentinelMocks, "workspace_locking": tmAccess.WorkspaceLocking, + "run_tasks": tmAccess.RunTasks, }} if err := d.Set("permissions", permissions); err != nil { return fmt.Errorf("error setting permissions for team access %s: %s", d.Id(), err) @@ -281,6 +293,12 @@ func resourceTFETeamAccessUpdate(d *schema.ResourceData, meta interface{}) error } } + if d.HasChange("permissions.0.run_tasks") { + if v, ok := d.GetOkExists("permissions.0.run_tasks"); ok { + options.RunTasks = tfe.Bool(v.(bool)) + } + } + log.Printf("[DEBUG] Update team access: %s", d.Id()) tmAccess, err := tfeClient.TeamAccess.Update(ctx, d.Id(), options) if err != nil { @@ -295,6 +313,7 @@ func resourceTFETeamAccessUpdate(d *schema.ResourceData, meta interface{}) error "state_versions": tmAccess.StateVersions, "sentinel_mocks": tmAccess.SentinelMocks, "workspace_locking": tmAccess.WorkspaceLocking, + "run_tasks": tmAccess.RunTasks, }} if err := d.Set("permissions", permissions); err != nil { return fmt.Errorf("error setting permissions for team access %s: %s", d.Id(), err) @@ -397,7 +416,14 @@ func setCustomAccess(d *schema.ResourceDiff) error { // Interpolated values not known at plan time are not allowed because we cannot re-check // for a change in permissions later - when the plan is expanded for new values learned during // an apply. This creates an inconsistent final plan and causes an error. - for _, permission := range []string{"permissions.0.runs", "permissions.0.variables", "permissions.0.state_versions", "permissions.0.sentinel_mocks", "permissions.0.workspace_locking"} { + for _, permission := range []string{ + "permissions.0.runs", + "permissions.0.variables", + "permissions.0.state_versions", + "permissions.0.sentinel_mocks", + "permissions.0.workspace_locking", + "permissions.0.run_tasks", + } { if !d.NewValueKnown(permission) { return fmt.Errorf("'%q' cannot be derived from a value that is unknown during planning", permission) } diff --git a/tfe/resource_tfe_team_access_test.go b/tfe/resource_tfe_team_access_test.go index 2a1c76d5e..8c4d5f72a 100644 --- a/tfe/resource_tfe_team_access_test.go +++ b/tfe/resource_tfe_team_access_test.go @@ -11,6 +11,44 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) +func TestAccTFETeamAccess_admin(t *testing.T) { + tmAccess := &tfe.TeamAccess{} + rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int() + + expectedPermissions := map[string]interface{}{ + "runs": tfe.RunsPermissionApply, + "variables": tfe.VariablesPermissionWrite, + "state_versions": tfe.StateVersionsPermissionWrite, + "sentinel_mocks": tfe.SentinelMocksPermissionRead, + "workspace_locking": true, + "run_tasks": true, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckTFETeamAccessDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTFETeamAccess_admin(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckTFETeamAccessExists( + "tfe_team_access.foobar", tmAccess), + testAccCheckTFETeamAccessAttributesAccessIs(tmAccess, tfe.AccessAdmin), + testAccCheckTFETeamAccessAttributesPermissionsAre(tmAccess, expectedPermissions), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "admin"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.runs", "apply"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.variables", "write"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "write"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "read"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "true"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "true"), + ), + }, + }, + }) +} + func TestAccTFETeamAccess_write(t *testing.T) { tmAccess := &tfe.TeamAccess{} rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int() @@ -21,6 +59,7 @@ func TestAccTFETeamAccess_write(t *testing.T) { "state_versions": tfe.StateVersionsPermissionWrite, "sentinel_mocks": tfe.SentinelMocksPermissionRead, "workspace_locking": true, + "run_tasks": false, } resource.Test(t, resource.TestCase{ @@ -41,6 +80,7 @@ func TestAccTFETeamAccess_write(t *testing.T) { resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "write"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "read"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "true"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"), ), }, }, @@ -70,6 +110,7 @@ func TestAccTFETeamAccess_custom(t *testing.T) { "state_versions": tfe.StateVersionsPermissionReadOutputs, "sentinel_mocks": tfe.SentinelMocksPermissionNone, "workspace_locking": false, + "run_tasks": false, }, ), resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "custom"), @@ -78,6 +119,7 @@ func TestAccTFETeamAccess_custom(t *testing.T) { resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "read-outputs"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "none"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "false"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"), ), }, }, @@ -107,6 +149,7 @@ func TestAccTFETeamAccess_updateToCustom(t *testing.T) { "state_versions": tfe.StateVersionsPermissionWrite, "sentinel_mocks": tfe.SentinelMocksPermissionRead, "workspace_locking": true, + "run_tasks": false, }, ), resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "write"), @@ -115,6 +158,7 @@ func TestAccTFETeamAccess_updateToCustom(t *testing.T) { resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "write"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "read"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "true"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"), ), }, { @@ -131,6 +175,7 @@ func TestAccTFETeamAccess_updateToCustom(t *testing.T) { "state_versions": tfe.StateVersionsPermissionReadOutputs, "sentinel_mocks": tfe.SentinelMocksPermissionNone, "workspace_locking": false, + "run_tasks": false, }, ), resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "custom"), @@ -139,6 +184,7 @@ func TestAccTFETeamAccess_updateToCustom(t *testing.T) { resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "read-outputs"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "none"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "false"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"), ), }, }, @@ -168,6 +214,7 @@ func TestAccTFETeamAccess_updateFromCustom(t *testing.T) { "state_versions": tfe.StateVersionsPermissionReadOutputs, "sentinel_mocks": tfe.SentinelMocksPermissionNone, "workspace_locking": false, + "run_tasks": false, }, ), resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "custom"), @@ -176,6 +223,7 @@ func TestAccTFETeamAccess_updateFromCustom(t *testing.T) { resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "read-outputs"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "none"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "false"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"), ), }, { @@ -192,6 +240,7 @@ func TestAccTFETeamAccess_updateFromCustom(t *testing.T) { "state_versions": tfe.StateVersionsPermissionRead, "sentinel_mocks": tfe.SentinelMocksPermissionNone, "workspace_locking": false, + "run_tasks": false, }, ), resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "plan"), @@ -200,6 +249,7 @@ func TestAccTFETeamAccess_updateFromCustom(t *testing.T) { resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "read"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "none"), resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "false"), + resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"), ), }, }, @@ -283,6 +333,9 @@ func testAccCheckTFETeamAccessAttributesPermissionsAre(tmAccess *tfe.TeamAccess, if tmAccess.WorkspaceLocking != expectedPermissions["workspace_locking"].(bool) { return fmt.Errorf("Bad workspace-locking permission: Expected %s, Received %t", expectedPermissions["workspace_locking"], tmAccess.WorkspaceLocking) } + if tmAccess.RunTasks != expectedPermissions["run_tasks"].(bool) { + return fmt.Errorf("Bad run_tasks permission: Expected %s, Received %t", expectedPermissions["run_tasks"], tmAccess.RunTasks) + } return nil } } @@ -308,6 +361,30 @@ func testAccCheckTFETeamAccessDestroy(s *terraform.State) error { return nil } +func testAccTFETeamAccess_admin(rInt int) string { + return fmt.Sprintf(` +resource "tfe_organization" "foobar" { + name = "tst-terraform-%d" + email = "admin@company.com" +} + +resource "tfe_team" "foobar" { + name = "team-test" + organization = tfe_organization.foobar.id +} + +resource "tfe_workspace" "foobar" { + name = "workspace-test" + organization = tfe_organization.foobar.id +} + +resource "tfe_team_access" "foobar" { + access = "admin" + team_id = tfe_team.foobar.id + workspace_id = tfe_workspace.foobar.id +}`, rInt) +} + func testAccTFETeamAccess_write(rInt int) string { return fmt.Sprintf(` resource "tfe_organization" "foobar" { @@ -380,6 +457,7 @@ resource "tfe_team_access" "foobar" { state_versions = "read-outputs" sentinel_mocks = "none" workspace_locking = false + run_tasks = false } team_id = tfe_team.foobar.id workspace_id = tfe_workspace.foobar.id