Skip to content

Commit 27309d8

Browse files
authored
Merge pull request #992 from isaacmcollins/add_tfe_organization_teams_data_source
Add tfe_teams data source
2 parents cf9e146 + 8bcda60 commit 27309d8

File tree

5 files changed

+234
-1
lines changed

5 files changed

+234
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
FEATURES:
44
* `d/tfe_variable_set`: Add `project_ids` attribute, by @Netra2104 [994](https://github.com/hashicorp/terraform-provider-tfe/pull/994)
5-
5+
* **New Data Source**: `d/tfe_teams` is a new data source to return names and IDs of Teams in an Organization, by @isaacmcollins [992](https://github.com/hashicorp/terraform-provider-tfe/pull/992)
66
## v0.48.0 (August 7, 2023)
77

88
BUG FIXES:
@@ -18,6 +18,7 @@ FEATURES:
1818
various customizable permissions options to apply to a project and all of the workspaces therein, by @rberecka [983](https://github.com/hashicorp/terraform-provider-tfe/pull/983)
1919
* `d/team_project_access`: Add a `custom` option to the `access` attribute as well as `project_access` and `workspace_access` attributes, by @rberecka [983](https://github.com/hashicorp/terraform-provider-tfe/pull/983)
2020

21+
2122
NOTES:
2223
* The provider is now using go-tfe [v1.32.0](https://github.com/hashicorp/go-tfe/releases/tag/v1.32.0)
2324
## v0.47.0 (July 18, 2023)

tfe/data_source_teams.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package tfe
5+
6+
import (
7+
"fmt"
8+
9+
tfe "github.com/hashicorp/go-tfe"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
)
12+
13+
func dataSourceTFETeams() *schema.Resource {
14+
return &schema.Resource{
15+
Read: dataSourceTFETeamsRead,
16+
17+
Schema: map[string]*schema.Schema{
18+
"organization": {
19+
Type: schema.TypeString,
20+
Optional: true,
21+
},
22+
23+
"names": {
24+
Type: schema.TypeList,
25+
Computed: true,
26+
Elem: &schema.Schema{Type: schema.TypeString},
27+
},
28+
29+
"ids": {
30+
Type: schema.TypeMap,
31+
Computed: true,
32+
},
33+
},
34+
}
35+
}
36+
37+
func dataSourceTFETeamsRead(d *schema.ResourceData, meta interface{}) error {
38+
config := meta.(ConfiguredClient)
39+
organization, err := config.schemaOrDefaultOrganization(d)
40+
if err != nil {
41+
return err
42+
}
43+
44+
teams, err := config.Client.Teams.List(ctx, organization, &tfe.TeamListOptions{})
45+
if err != nil {
46+
return fmt.Errorf("Error retrieving teams: %w", err)
47+
}
48+
49+
if len(teams.Items) == 0 {
50+
return fmt.Errorf("Could not find teams in %s", organization)
51+
} else {
52+
options := &tfe.TeamListOptions{}
53+
names := []string{}
54+
ids := map[string]string{}
55+
for {
56+
for _, team := range teams.Items {
57+
names = append(names, team.Name)
58+
ids[team.Name] = team.ID
59+
}
60+
61+
if teams.CurrentPage >= teams.TotalPages {
62+
break
63+
}
64+
65+
options.PageNumber = teams.NextPage
66+
67+
teams, err = config.Client.Teams.List(ctx, organization, options)
68+
if err != nil {
69+
return fmt.Errorf("Error retrieving teams: %w", err)
70+
}
71+
}
72+
d.SetId(organization)
73+
d.Set("names", names)
74+
d.Set("ids", ids)
75+
}
76+
return nil
77+
}

tfe/data_source_teams_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package tfe
5+
6+
import (
7+
"fmt"
8+
"math/rand"
9+
"strconv"
10+
"testing"
11+
"time"
12+
13+
tfe "github.com/hashicorp/go-tfe"
14+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
15+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
16+
)
17+
18+
func TestAccTFETeamsDataSource_basic(t *testing.T) {
19+
tfeClient, err := getClientUsingEnv()
20+
if err != nil {
21+
t.Fatal(err)
22+
}
23+
24+
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
25+
26+
org, orgCleanup := createOrganization(t, tfeClient, tfe.OrganizationCreateOptions{
27+
Name: tfe.String(fmt.Sprintf("tst-terraform-%d", rInt)),
28+
Email: tfe.String(fmt.Sprintf("%[email protected]", randomString(t))),
29+
})
30+
t.Cleanup(orgCleanup)
31+
32+
resource.Test(t, resource.TestCase{
33+
PreCheck: func() { testAccPreCheck(t) },
34+
Providers: testAccProviders,
35+
Steps: []resource.TestStep{
36+
{
37+
Config: testAccTFETeamsDataSourceConfig_basic_resource(rInt, org.Name),
38+
},
39+
{
40+
Config: testAccTFETeamsDataSourceConfig_basic_data(org.Name),
41+
Check: resource.ComposeAggregateTestCheckFunc(
42+
testAccCheckTFETeamsHasNames("data.tfe_teams.foobar", []string{
43+
fmt.Sprintf("team-foo-%d", rInt),
44+
fmt.Sprintf("team-bar-%d", rInt),
45+
}),
46+
testAccCheckTFETeamsHasIDs("data.tfe_teams.foobar", []string{
47+
fmt.Sprintf("team-foo-%d", rInt),
48+
fmt.Sprintf("team-bar-%d", rInt),
49+
}),
50+
),
51+
},
52+
},
53+
})
54+
}
55+
56+
func testAccCheckTFETeamsHasNames(teamsData string, teamNames []string) resource.TestCheckFunc {
57+
return func(s *terraform.State) error {
58+
teams, ok := s.RootModule().Resources[teamsData]
59+
if !ok {
60+
return fmt.Errorf("Teams data '%s' not found.", teamsData)
61+
}
62+
numTeamsStr := teams.Primary.Attributes["names.#"]
63+
numTeams, _ := strconv.Atoi(numTeamsStr)
64+
65+
if numTeams < len(teamNames) {
66+
return fmt.Errorf("expected %d organizations, but found %d.", len(teamNames), numTeams)
67+
}
68+
69+
teamsMap := map[string]struct{}{}
70+
for i := 0; i < numTeams; i++ {
71+
teamName := teams.Primary.Attributes[fmt.Sprintf("names.%d", i)]
72+
teamsMap[teamName] = struct{}{}
73+
}
74+
75+
for _, teamName := range teamNames {
76+
_, ok := teamsMap[teamName]
77+
if !ok {
78+
return fmt.Errorf("expected to find team name %s, but did not.", teamName)
79+
}
80+
}
81+
82+
return nil
83+
}
84+
}
85+
86+
func testAccCheckTFETeamsHasIDs(teamsData string, teamNames []string) resource.TestCheckFunc {
87+
return func(s *terraform.State) error {
88+
teams, ok := s.RootModule().Resources[teamsData]
89+
if !ok {
90+
return fmt.Errorf("Teams data '%s' not found.", teamsData)
91+
}
92+
93+
for _, teamName := range teamNames {
94+
id := fmt.Sprintf("ids.%s", teamName)
95+
_, ok := teams.Primary.Attributes[id]
96+
if !ok {
97+
return fmt.Errorf("expected to find team id %s, but did not.", id)
98+
}
99+
}
100+
101+
return nil
102+
}
103+
}
104+
105+
func testAccTFETeamsDataSourceConfig_basic_resource(rInt int, organization string) string {
106+
return fmt.Sprintf(`
107+
resource "tfe_team" "foo" {
108+
name = "team-foo-%d"
109+
organization = "%s"
110+
}
111+
112+
resource "tfe_team" "bar" {
113+
name = "team-bar-%d"
114+
organization = "%s"
115+
}`, rInt, organization, rInt, organization)
116+
}
117+
118+
func testAccTFETeamsDataSourceConfig_basic_data(organization string) string {
119+
return fmt.Sprintf(`
120+
data "tfe_teams" "foobar" {
121+
organization = "%s"
122+
}`, organization)
123+
}

tfe/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ func Provider() *schema.Provider {
121121
"tfe_slug": dataSourceTFESlug(),
122122
"tfe_ssh_key": dataSourceTFESSHKey(),
123123
"tfe_team": dataSourceTFETeam(),
124+
"tfe_teams": dataSourceTFETeams(),
124125
"tfe_team_access": dataSourceTFETeamAccess(),
125126
"tfe_team_project_access": dataSourceTFETeamProjectAccess(),
126127
"tfe_workspace": dataSourceTFEWorkspace(),

website/docs/d/teams.html.markdown

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
layout: "tfe"
3+
page_title: "Terraform Enterprise: tfe_teams"
4+
description: |-
5+
Get information on Teams.
6+
---
7+
8+
# Data Source: tfe_teams
9+
10+
Use this data source to get a list of Teams in an Organization and a map of their IDs. The Teams returned may be a subset of all teams in an Organization based on the permissions of the API token.
11+
12+
## Example Usage
13+
14+
```hcl
15+
data "tfe_teams" "foo" {
16+
organization = "my-org-name"
17+
}
18+
```
19+
20+
## Argument Reference
21+
22+
The following arguments are supported:
23+
24+
* `organization` - (Optional) Name of the organization.
25+
26+
## Attributes Reference
27+
28+
In addition to all arguments above, the following attributes are exported:
29+
* `id` - Name of the organization.
30+
* `names` - A list of team names in an organization.
31+
* `ids` - A map of team names in an organization and their IDs.

0 commit comments

Comments
 (0)