Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add run_tasks permission to Team Access #487

Merged
merged 1 commit into from
Jun 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

BREAKING CHANGES:
* **Removed Authentication Method**: Host-specific TF_TOKEN_... environment variable can no longer be used for token authentication. This method of authentication is incompatible with the Terraform Cloud remote execution model. Please use the TFE_TOKEN environment variable.
* r/tfe_workspace: Default value of the `file_triggers_enabled` field is changed to `false`. This will align the
`file_triggers_enabled` field default value with the default value for the same field in the
[TFC API](https://www.terraform.io/cloud-docs/api-docs/workspaces).
If the value of the `file_triggers_enabled` field was not explicitly set and either of the fields `working_directory`
(not an empty string) or `trigger_prefixes` was used - to keep the behavior unchanged, the `file_trigger_enabled`
field should now explicitly be set to `true`. ([#510](https://github.com/hashicorp/terraform-provider-tfe/pull/510/files))
* r/tfe_team_access: The `permissions` attribute requires `run_tasks` in the block. ([#487](https://github.com/hashicorp/terraform-provider-tfe/pull/487))

BUG FIXES:
* Prevent overwriting `vcs_repo` attributes in `r/tfe_workspace` when update API call fails ([#498](https://github.com/hashicorp/terraform-provider-tfe/pull/498))
Expand All @@ -14,14 +21,6 @@ FEATURES:
* **New Data Source**: d/tfe_workspace_run_task ([#488](https://github.com/hashicorp/terraform-provider-tfe/pull/488))
* r/tfe_notification_configuration: Add Microsoft Teams notification type ([#484](https://github.com/hashicorp/terraform-provider-tfe/pull/484))

BREAKING CHANGES:
* r/tfe_workspace: Default value of the `file_triggers_enabled` field is changed to `false`. This will align the
`file_triggers_enabled` field default value with the default value for the same field in the
[TFC API](https://www.terraform.io/cloud-docs/api-docs/workspaces).
If the value of the `file_triggers_enabled` field was not explicitly set and either of the fields `working_directory`
(not an empty string) or `trigger_prefixes` was used - to keep the behavior unchanged, the `file_trigger_enabled`
field should now explicitly be set to `true`. ([#510](https://github.com/hashicorp/terraform-provider-tfe/pull/510/files))

## 0.31.0 (April 21, 2022)

BUG FIXES:
Expand Down
5 changes: 5 additions & 0 deletions tfe/data_source_team_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func dataSourceTFETeamAccess() *schema.Resource {
Type: schema.TypeBool,
Computed: true,
},

"run_tasks": {
Type: schema.TypeBool,
Computed: true,
},
},
},
},
Expand Down
2 changes: 2 additions & 0 deletions tfe/data_source_team_access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
28 changes: 27 additions & 1 deletion tfe/resource_tfe_team_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ func resourceTFETeamAccess() *schema.Resource {
Type: schema.TypeBool,
Required: true,
},

"run_tasks": {
Type: schema.TypeBool,
Required: true,
},
},
},
},
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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: %w", d.Id(), err)
Expand Down Expand Up @@ -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 {
Expand All @@ -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: %w", d.Id(), err)
Expand Down Expand Up @@ -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)
}
Expand Down
78 changes: 78 additions & 0 deletions tfe/resource_tfe_team_access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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{
Expand All @@ -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"),
),
},
},
Expand Down Expand Up @@ -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"),
Expand All @@ -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"),
),
},
},
Expand Down Expand Up @@ -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"),
Expand All @@ -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"),
),
},
{
Expand All @@ -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"),
Expand All @@ -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"),
),
},
},
Expand Down Expand Up @@ -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"),
Expand All @@ -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"),
),
},
{
Expand All @@ -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"),
Expand All @@ -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"),
),
},
},
Expand Down Expand Up @@ -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
}
}
Expand All @@ -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" {
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions website/docs/d/team_access.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ The `permissions` block contains:
* `state_versions` - The permissions granted to state versions. Valid values are `none`, `read-outputs`, `read`, or `write`
* `sentinel_mocks` - The permissions granted to Sentinel mocks. Valid values are `none` or `read`
* `workspace_locking` - Whether permission is granted to manually lock the workspace or not.
* `run_tasks` - Whether permission is granted to manage workspace run tasks or not.
1 change: 1 addition & 0 deletions website/docs/r/team_access.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The `permissions` block supports:
* `state_versions` - (Required) The permission to grant the team on the workspace's state versions. Valid values are `none`, `read`, `read-outputs`, or `write`.
* `sentinel_mocks` - (Required) The permission to grant the team on the workspace's generated Sentinel mocks, Valid values are `none` or `read`.
* `workspace_locking` - (Required) Boolean determining whether or not to grant the team permission to manually lock/unlock the workspace.
* `run_tasks` - (Required) Whether permission is granted to manage workspace run tasks or not.

-> **Note:** At least one of `access` or `permissions` _must_ be provided, but not both. Whichever is omitted will automatically reflect the state of the other.

Expand Down