Skip to content

Commit 63e34d6

Browse files
tylerwolfJarrettSpiker
authored andcommitted
Add resources for allowed projects and excluded workspaces
1 parent 20a3c8e commit 63e34d6

5 files changed

+720
-0
lines changed

internal/provider/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ func Provider() *schema.Provider {
107107
ResourcesMap: map[string]*schema.Resource{
108108
"tfe_admin_organization_settings": resourceTFEAdminOrganizationSettings(),
109109
"tfe_agent_pool": resourceTFEAgentPool(),
110+
"tfe_agent_pool_allowed_projects": resourceTFEAgentPoolAllowedProjects(),
110111
"tfe_agent_pool_allowed_workspaces": resourceTFEAgentPoolAllowedWorkspaces(),
112+
"tfe_agent_pool_excluded_workspaces": resourceTFEAgentPoolExcludedWorkspaces(),
111113
"tfe_agent_token": resourceTFEAgentToken(),
112114
"tfe_oauth_client": resourceTFEOAuthClient(),
113115
"tfe_opa_version": resourceTFEOPAVersion(),
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
// NOTE: This is a legacy resource and should be migrated to the Plugin
5+
// Framework if substantial modifications are planned. See
6+
// docs/new-resources.md if planning to use this code as boilerplate for
7+
// a new resource.
8+
9+
package provider
10+
11+
import (
12+
"errors"
13+
"fmt"
14+
"log"
15+
16+
"github.com/hashicorp/go-tfe"
17+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
18+
)
19+
20+
func resourceTFEAgentPoolAllowedProjects() *schema.Resource {
21+
return &schema.Resource{
22+
Create: resourceTFEAgentPoolAllowedProjectsCreate,
23+
Read: resourceTFEAgentPoolAllowedProjectsRead,
24+
Update: resourceTFEAgentPoolAllowedProjectsUpdate,
25+
Delete: resourceTFEAgentPoolAllowedProjectsDelete,
26+
Importer: &schema.ResourceImporter{
27+
StateContext: schema.ImportStatePassthroughContext,
28+
},
29+
30+
Schema: map[string]*schema.Schema{
31+
"agent_pool_id": {
32+
Type: schema.TypeString,
33+
Required: true,
34+
ForceNew: true,
35+
},
36+
37+
"allowed_project_ids": {
38+
Type: schema.TypeSet,
39+
Required: true,
40+
Elem: &schema.Schema{Type: schema.TypeString},
41+
},
42+
},
43+
}
44+
}
45+
46+
func resourceTFEAgentPoolAllowedProjectsCreate(d *schema.ResourceData, meta interface{}) error {
47+
config := meta.(ConfiguredClient)
48+
49+
apID := d.Get("agent_pool_id").(string)
50+
51+
// Create a new options struct.
52+
options := tfe.AgentPoolAllowedProjectsUpdateOptions{}
53+
54+
if allowedProjectIDs, allowedProjectSet := d.GetOk("allowed_project_ids"); allowedProjectSet {
55+
options.AllowedProjects = []*tfe.Project{}
56+
for _, projectID := range allowedProjectIDs.(*schema.Set).List() {
57+
if val, ok := projectID.(string); ok {
58+
options.AllowedProjects = append(options.AllowedProjects, &tfe.Project{ID: val})
59+
}
60+
}
61+
}
62+
63+
log.Printf("[DEBUG] Update agent pool: %s", apID)
64+
_, err := config.Client.AgentPools.UpdateAllowedProjects(ctx, apID, options)
65+
if err != nil {
66+
return fmt.Errorf("Error updating agent pool %s: %w", apID, err)
67+
}
68+
69+
d.SetId(apID)
70+
71+
return nil
72+
}
73+
74+
func resourceTFEAgentPoolAllowedProjectsRead(d *schema.ResourceData, meta interface{}) error {
75+
config := meta.(ConfiguredClient)
76+
77+
agentPool, err := config.Client.AgentPools.Read(ctx, d.Id())
78+
if err != nil {
79+
if errors.Is(err, tfe.ErrResourceNotFound) {
80+
log.Printf("[DEBUG] agent pool %s no longer exists", d.Id())
81+
d.SetId("")
82+
return nil
83+
}
84+
return fmt.Errorf("Error reading configuration of agent pool %s: %w", d.Id(), err)
85+
}
86+
87+
var allowedProjectIDs []string
88+
for _, project := range agentPool.AllowedProjects {
89+
allowedProjectIDs = append(allowedProjectIDs, project.ID)
90+
}
91+
d.Set("allowed_project_ids", allowedProjectIDs)
92+
d.Set("agent_pool_id", agentPool.ID)
93+
94+
return nil
95+
}
96+
97+
func resourceTFEAgentPoolAllowedProjectsUpdate(d *schema.ResourceData, meta interface{}) error {
98+
config := meta.(ConfiguredClient)
99+
100+
apID := d.Get("agent_pool_id").(string)
101+
102+
// Create a new options struct.
103+
options := tfe.AgentPoolAllowedProjectsUpdateOptions{
104+
AllowedProjects: []*tfe.Project{},
105+
}
106+
107+
if allowedProjectIDs, allowedProjectSet := d.GetOk("allowed_project_ids"); allowedProjectSet {
108+
options.AllowedProjects = []*tfe.Project{}
109+
for _, projectID := range allowedProjectIDs.(*schema.Set).List() {
110+
if val, ok := projectID.(string); ok {
111+
options.AllowedProjects = append(options.AllowedProjects, &tfe.Project{ID: val})
112+
}
113+
}
114+
}
115+
116+
log.Printf("[DEBUG] Update agent pool: %s", apID)
117+
_, err := config.Client.AgentPools.UpdateAllowedProjects(ctx, apID, options)
118+
if err != nil {
119+
return fmt.Errorf("Error updating agent pool %s: %w", apID, err)
120+
}
121+
122+
d.SetId(apID)
123+
124+
return nil
125+
}
126+
127+
func resourceTFEAgentPoolAllowedProjectsDelete(d *schema.ResourceData, meta interface{}) error {
128+
config := meta.(ConfiguredClient)
129+
130+
apID := d.Get("agent_pool_id").(string)
131+
132+
// Create a new options struct.
133+
options := tfe.AgentPoolAllowedProjectsUpdateOptions{
134+
AllowedProjects: []*tfe.Project{},
135+
}
136+
137+
log.Printf("[DEBUG] Update agent pool: %s", apID)
138+
_, err := config.Client.AgentPools.UpdateAllowedProjects(ctx, apID, options)
139+
if err != nil {
140+
return fmt.Errorf("Error updating agent pool %s: %w", apID, err)
141+
}
142+
143+
return nil
144+
}
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package provider
5+
6+
import (
7+
"errors"
8+
"fmt"
9+
"testing"
10+
11+
tfe "github.com/hashicorp/go-tfe"
12+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
13+
"github.com/hashicorp/terraform-plugin-testing/terraform"
14+
)
15+
16+
func TestAccTFEAgentPoolAllowedProjects_create_update(t *testing.T) {
17+
tfeClient, err := getClientUsingEnv()
18+
if err != nil {
19+
t.Fatal(err)
20+
}
21+
22+
org, orgCleanup := createBusinessOrganization(t, tfeClient)
23+
t.Cleanup(orgCleanup)
24+
25+
allowedProjectsIDs := &[]string{}
26+
27+
resource.Test(t, resource.TestCase{
28+
PreCheck: func() { testAccPreCheck(t) },
29+
ProtoV5ProviderFactories: testAccMuxedProviders,
30+
Steps: []resource.TestStep{
31+
{
32+
Config: testAccTFEAgentPoolAllowedProjects_basic(org.Name),
33+
Check: resource.ComposeTestCheckFunc(
34+
testAccCheckTFEAgentPoolAllowedProjectExists("tfe_agent_pool.foobar", allowedProjectsIDs),
35+
testAccCheckTFEAgentPoolAllowedProjectsCount(2, allowedProjectsIDs),
36+
),
37+
},
38+
{
39+
Config: testAccTFEAgentPoolAllowedProjects_update(org.Name),
40+
Check: resource.ComposeTestCheckFunc(
41+
testAccCheckTFEAgentPoolAllowedProjectExists("tfe_agent_pool.foobar", allowedProjectsIDs),
42+
testAccCheckTFEAgentPoolAllowedProjectsCount(1, allowedProjectsIDs),
43+
),
44+
},
45+
{
46+
Config: testAccTFEAgentPoolAllowedProjects_destroy(org.Name),
47+
Check: resource.ComposeTestCheckFunc(
48+
testAccCheckTFEAgentPoolAllowedProjectsNotExists("tfe_agent_pool.foobar"),
49+
),
50+
},
51+
},
52+
})
53+
}
54+
55+
func testAccCheckTFEAgentPoolAllowedProjectExists(resourceName string, allowedProjects *[]string) resource.TestCheckFunc {
56+
return func(s *terraform.State) error {
57+
*allowedProjects = []string{}
58+
59+
rs, ok := s.RootModule().Resources[resourceName]
60+
if !ok {
61+
return fmt.Errorf("Not found: %s", resourceName)
62+
}
63+
64+
// Resource ID equals the Agent Pool ID
65+
if rs.Primary.ID == "" {
66+
return fmt.Errorf("No instance ID is set")
67+
}
68+
69+
agentPool, err := testAccConfiguredClient.Client.AgentPools.Read(ctx, rs.Primary.ID)
70+
if err != nil && !errors.Is(err, tfe.ErrResourceNotFound) {
71+
return fmt.Errorf("error while fetching agent pool: %w", err)
72+
}
73+
74+
if len(agentPool.AllowedProjects) == 0 {
75+
return fmt.Errorf("Allowed Projects for agent pool %s do not exist", rs.Primary.ID)
76+
}
77+
78+
for _, project := range agentPool.AllowedProjects {
79+
*allowedProjects = append(*allowedProjects, project.ID)
80+
}
81+
82+
return nil
83+
}
84+
}
85+
86+
func testAccCheckTFEAgentPoolAllowedProjectsNotExists(resourceName string) resource.TestCheckFunc {
87+
return func(s *terraform.State) error {
88+
rs, ok := s.RootModule().Resources[resourceName]
89+
if !ok {
90+
return fmt.Errorf("Not found: %s", resourceName)
91+
}
92+
93+
// Resource ID equals the Agent Pool ID
94+
if rs.Primary.ID == "" {
95+
return fmt.Errorf("No instance ID is set")
96+
}
97+
98+
agentPool, err := testAccConfiguredClient.Client.AgentPools.Read(ctx, rs.Primary.ID)
99+
if err != nil && !errors.Is(err, tfe.ErrResourceNotFound) {
100+
return fmt.Errorf("error while fetching agent pool: %w", err)
101+
}
102+
103+
if len(agentPool.AllowedProjects) > 0 {
104+
return fmt.Errorf("Allowed Projects for agent pool %s exists", rs.Primary.ID)
105+
}
106+
107+
return nil
108+
}
109+
}
110+
111+
func testAccCheckTFEAgentPoolAllowedProjectsCount(expected int, allowedProjects *[]string) resource.TestCheckFunc {
112+
return func(s *terraform.State) error {
113+
if len(*allowedProjects) != expected {
114+
return fmt.Errorf("expected %d allowed projects, got %d", expected, len(*allowedProjects))
115+
}
116+
return nil
117+
}
118+
}
119+
120+
func TestAccTFEAgentPoolAllowedProjects_import(t *testing.T) {
121+
skipIfEnterprise(t)
122+
123+
tfeClient, err := getClientUsingEnv()
124+
if err != nil {
125+
t.Fatal(err)
126+
}
127+
128+
org, orgCleanup := createBusinessOrganization(t, tfeClient)
129+
t.Cleanup(orgCleanup)
130+
131+
resource.Test(t, resource.TestCase{
132+
PreCheck: func() { testAccPreCheck(t) },
133+
ProtoV5ProviderFactories: testAccMuxedProviders,
134+
Steps: []resource.TestStep{
135+
{
136+
Config: testAccTFEAgentPoolAllowedProjects_basic(org.Name),
137+
},
138+
{
139+
ResourceName: "tfe_agent_pool_allowed_projects.foobar",
140+
ImportState: true,
141+
ImportStateVerify: true,
142+
},
143+
},
144+
})
145+
}
146+
147+
func testAccTFEAgentPoolAllowedProjects_destroy(organization string) string {
148+
return fmt.Sprintf(`
149+
resource "tfe_project" "foobar" {
150+
name = "foobar"
151+
organization = "%s"
152+
}
153+
154+
resource "tfe_project" "test-project" {
155+
name = "test-project"
156+
organization = "%s"
157+
}
158+
159+
resource "tfe_agent_pool" "foobar" {
160+
name = "agent-pool-updated"
161+
organization = "%s"
162+
organization_scoped = false
163+
}`, organization, organization, organization)
164+
}
165+
166+
func testAccTFEAgentPoolAllowedProjects_update(organization string) string {
167+
return fmt.Sprintf(`
168+
resource "tfe_project" "foobar" {
169+
name = "foobar"
170+
organization = "%s"
171+
}
172+
173+
resource "tfe_project" "test-project" {
174+
name = "test-project"
175+
organization = "%s"
176+
}
177+
178+
resource "tfe_agent_pool" "foobar" {
179+
name = "agent-pool-updated"
180+
organization = "%s"
181+
organization_scoped = false
182+
}
183+
184+
resource "tfe_agent_pool_allowed_projects" "foobar"{
185+
agent_pool_id = tfe_agent_pool.foobar.id
186+
allowed_project_ids = [tfe_project.foobar.id]
187+
}`, organization, organization, organization)
188+
}
189+
190+
func testAccTFEAgentPoolAllowedProjects_basic(organization string) string {
191+
return fmt.Sprintf(`
192+
resource "tfe_project" "foobar" {
193+
name = "foobar"
194+
organization = "%s"
195+
}
196+
197+
resource "tfe_project" "test-project" {
198+
name = "test-project"
199+
organization = "%s"
200+
}
201+
202+
resource "tfe_agent_pool" "foobar" {
203+
name = "agent-pool-updated"
204+
organization = "%s"
205+
organization_scoped = false
206+
}
207+
208+
resource "tfe_agent_pool_allowed_projects" "foobar"{
209+
agent_pool_id = tfe_agent_pool.foobar.id
210+
allowed_project_ids = [
211+
tfe_project.foobar.id,
212+
tfe_project.test-project.id
213+
]
214+
}`, organization, organization, organization)
215+
}

0 commit comments

Comments
 (0)