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

Update Agent Pools scope to Workspaces #870

Merged
merged 7 commits into from
Jun 26, 2023
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
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
## Unreleased

FEATURES:
* **New Resource**: `r/tfe_agent_pool_allowed_workspaces` restricts the use of an agent pool to particular workspaces, by @hs26gill [870](https://github.com/hashicorp/terraform-provider-tfe/pull/870)

BUG FIXES:
* `r/tfe_workspace_run`: Ensure `wait_for_run` correctly results in a fire-and-forget Run when set to `false` by @lucymhdavies ([#910](https://github.com/hashicorp/terraform-provider-tfe/pull/910))
* `r/tfe_notification_configuration`: Add support for missing "Check failed" Health Event notifications by @lucymhdavies ([#927](https://github.com/hashicorp/terraform-provider-tfe/pull/927))


ENHANCEMENTS:
* `r/tfe_agent_pool`: Add attribute `organization_scoped` to set the scope of an agent pool by @hs26gill [870](https://github.com/hashicorp/terraform-provider-tfe/pull/870)
* `d/tfe_agent_pool`: Add attribute `organization_scoped` and `allowed_workspace_ids` to retrieve agent pool scope and associated allowed workspace ids by @hs26gill [870](https://github.com/hashicorp/terraform-provider-tfe/pull/870)

## v0.45.0 (May 25, 2023)

Expand All @@ -16,7 +21,6 @@ FEATURES:
* `r/tfe_team_token`: Add optional `expired_at` field to team tokens by, @juliannatetreault ([#844](https://github.com/hashicorp/terraform-provider-tfe/pull/844))

ENHANCEMENTS:

* `r/tfe_workspace`: Retry workspace safe delete if resources are still being processed to determine safety. ([#881](https://github.com/hashicorp/terraform-provider-tfe/pull/881))

BUG FIXES:
Expand Down
8 changes: 4 additions & 4 deletions tfe/agent_pool_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
tfe "github.com/hashicorp/go-tfe"
)

func fetchAgentPoolID(orgName string, poolName string, client *tfe.Client) (string, error) {
func fetchAgentPool(orgName string, poolName string, client *tfe.Client) (*tfe.AgentPool, error) {
hs26gill marked this conversation as resolved.
Show resolved Hide resolved
// to reduce the number of pages returned, search based on the name. TFE instances which
// do not support agent pool search will just ignore the query parameter
options := tfe.AgentPoolListOptions{
Expand All @@ -19,12 +19,12 @@ func fetchAgentPoolID(orgName string, poolName string, client *tfe.Client) (stri
for {
l, err := client.AgentPools.List(ctx, orgName, &options)
if err != nil {
return "", fmt.Errorf("Error retrieving agent pools: %w", err)
return nil, fmt.Errorf("Error retrieving agent pools: %w", err)
}

for _, k := range l.Items {
if k.Name == poolName {
return k.ID, nil
return k, nil
}
}

Expand All @@ -37,5 +37,5 @@ func fetchAgentPoolID(orgName string, poolName string, client *tfe.Client) (stri
options.PageNumber = l.NextPage
}

return "", tfe.ErrResourceNotFound
return nil, tfe.ErrResourceNotFound
}
24 changes: 22 additions & 2 deletions tfe/data_source_agent_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ func dataSourceTFEAgentPool() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},

"organization_scoped": {
Type: schema.TypeBool,
Computed: true,
},

"allowed_workspace_ids": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
Comment on lines +30 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this move to its own data source in order to align with the tfe_agent_pool_allowed_workspaces resource?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This resource only adds the workspace to the allowed_workspaces attribute of an agent_pool. So this was kept inside the agent_pool data source similar to the team_organization_members

},
}
}
Expand All @@ -35,10 +46,19 @@ func dataSourceTFEAgentPoolRead(d *schema.ResourceData, meta interface{}) error
return err
}

id, err := fetchAgentPoolID(organization, name, config.Client)
pool, err := fetchAgentPool(organization, name, config.Client)
if err != nil {
return err
}
d.SetId(id)

d.SetId(pool.ID)
d.Set("organization_scoped", pool.OrganizationScoped)

var allowedWorkspaceIDs []string
for _, allowedWorkspaceID := range pool.AllowedWorkspaces {
allowedWorkspaceIDs = append(allowedWorkspaceIDs, allowedWorkspaceID.ID)
}
d.Set("allowed_workspace_ids", allowedWorkspaceIDs)

return nil
}
65 changes: 65 additions & 0 deletions tfe/data_source_agent_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"testing"
"time"

"github.com/hashicorp/go-tfe"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

Expand Down Expand Up @@ -37,6 +39,50 @@ func TestAccTFEAgentPoolDataSource_basic(t *testing.T) {
"data.tfe_agent_pool.foobar", "name", fmt.Sprintf("agent-pool-test-%d", rInt)),
resource.TestCheckResourceAttr(
"data.tfe_agent_pool.foobar", "organization", org.Name),
resource.TestCheckResourceAttr(
"data.tfe_agent_pool.foobar", "organization_scoped", "true"),
),
},
},
})
}

func TestAccTFEAgentPoolDataSource_allowed_workspaces(t *testing.T) {
skipIfEnterprise(t)

tfeClient, err := getClientUsingEnv()
if err != nil {
t.Fatal(err)
}

org, orgCleanup := createBusinessOrganization(t, tfeClient)
t.Cleanup(orgCleanup)

rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

ws, err := tfeClient.Workspaces.Create(ctx, org.Name, tfe.WorkspaceCreateOptions{
Name: tfe.String(fmt.Sprintf("tst-workspace-test-%d", rInt)),
})
if err != nil {
t.Fatal(err)
}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccTFEAgentPoolDataSourceAllowedWorkspacesConfig(org.Name, rInt, ws.ID),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet("data.tfe_agent_pool.foobar", "id"),
resource.TestCheckResourceAttr(
"data.tfe_agent_pool.foobar", "name", fmt.Sprintf("agent-pool-test-%d", rInt)),
resource.TestCheckResourceAttr(
"data.tfe_agent_pool.foobar", "organization", org.Name),
resource.TestCheckResourceAttr(
"data.tfe_agent_pool.foobar", "organization_scoped", "false"),
resource.TestCheckResourceAttr(
"data.tfe_agent_pool.foobar", "allowed_workspace_ids.0", ws.ID),
),
},
},
Expand All @@ -55,3 +101,22 @@ data "tfe_agent_pool" "foobar" {
organization = "%s"
}`, rInt, organization, organization)
}

func testAccTFEAgentPoolDataSourceAllowedWorkspacesConfig(organization string, rInt int, workspaceID string) string {
return fmt.Sprintf(`
resource "tfe_agent_pool" "foobar" {
name = "agent-pool-test-%d"
organization = "%s"
organization_scoped = false
}

resource "tfe_agent_pool_allowed_workspaces" "foobar" {
agent_pool_id = tfe_agent_pool.foobar.id
allowed_workspace_ids = ["%s"]
}

data "tfe_agent_pool" "foobar" {
name = tfe_agent_pool.foobar.name
organization = "%s"
}`, rInt, organization, workspaceID, organization)
}
71 changes: 36 additions & 35 deletions tfe/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,41 +134,42 @@ func Provider() *schema.Provider {
},

ResourcesMap: map[string]*schema.Resource{
"tfe_admin_organization_settings": resourceTFEAdminOrganizationSettings(),
"tfe_agent_pool": resourceTFEAgentPool(),
"tfe_agent_token": resourceTFEAgentToken(),
"tfe_notification_configuration": resourceTFENotificationConfiguration(),
"tfe_oauth_client": resourceTFEOAuthClient(),
"tfe_organization": resourceTFEOrganization(),
"tfe_organization_membership": resourceTFEOrganizationMembership(),
"tfe_organization_module_sharing": resourceTFEOrganizationModuleSharing(),
"tfe_organization_run_task": resourceTFEOrganizationRunTask(),
"tfe_organization_token": resourceTFEOrganizationToken(),
"tfe_policy": resourceTFEPolicy(),
"tfe_policy_set": resourceTFEPolicySet(),
"tfe_policy_set_parameter": resourceTFEPolicySetParameter(),
"tfe_project": resourceTFEProject(),
"tfe_project_variable_set": resourceTFEProjectVariableSet(),
"tfe_registry_module": resourceTFERegistryModule(),
"tfe_no_code_module": resourceTFENoCodeModule(),
"tfe_run_trigger": resourceTFERunTrigger(),
"tfe_sentinel_policy": resourceTFESentinelPolicy(),
"tfe_ssh_key": resourceTFESSHKey(),
"tfe_team": resourceTFETeam(),
"tfe_team_access": resourceTFETeamAccess(),
"tfe_team_organization_member": resourceTFETeamOrganizationMember(),
"tfe_team_organization_members": resourceTFETeamOrganizationMembers(),
"tfe_team_project_access": resourceTFETeamProjectAccess(),
"tfe_team_member": resourceTFETeamMember(),
"tfe_team_members": resourceTFETeamMembers(),
"tfe_team_token": resourceTFETeamToken(),
"tfe_terraform_version": resourceTFETerraformVersion(),
"tfe_workspace": resourceTFEWorkspace(),
"tfe_workspace_run_task": resourceTFEWorkspaceRunTask(),
"tfe_variable_set": resourceTFEVariableSet(),
"tfe_workspace_variable_set": resourceTFEWorkspaceVariableSet(),
"tfe_workspace_policy_set": resourceTFEWorkspacePolicySet(),
"tfe_workspace_run": resourceTFEWorkspaceRun(),
"tfe_admin_organization_settings": resourceTFEAdminOrganizationSettings(),
"tfe_agent_pool": resourceTFEAgentPool(),
"tfe_agent_pool_allowed_workspaces": resourceTFEAgentPoolAllowedWorkspaces(),
"tfe_agent_token": resourceTFEAgentToken(),
"tfe_notification_configuration": resourceTFENotificationConfiguration(),
"tfe_oauth_client": resourceTFEOAuthClient(),
"tfe_organization": resourceTFEOrganization(),
"tfe_organization_membership": resourceTFEOrganizationMembership(),
"tfe_organization_module_sharing": resourceTFEOrganizationModuleSharing(),
"tfe_organization_run_task": resourceTFEOrganizationRunTask(),
"tfe_organization_token": resourceTFEOrganizationToken(),
"tfe_policy": resourceTFEPolicy(),
"tfe_policy_set": resourceTFEPolicySet(),
"tfe_policy_set_parameter": resourceTFEPolicySetParameter(),
"tfe_project": resourceTFEProject(),
"tfe_project_variable_set": resourceTFEProjectVariableSet(),
"tfe_registry_module": resourceTFERegistryModule(),
"tfe_no_code_module": resourceTFENoCodeModule(),
"tfe_run_trigger": resourceTFERunTrigger(),
"tfe_sentinel_policy": resourceTFESentinelPolicy(),
"tfe_ssh_key": resourceTFESSHKey(),
"tfe_team": resourceTFETeam(),
"tfe_team_access": resourceTFETeamAccess(),
"tfe_team_organization_member": resourceTFETeamOrganizationMember(),
"tfe_team_organization_members": resourceTFETeamOrganizationMembers(),
"tfe_team_project_access": resourceTFETeamProjectAccess(),
"tfe_team_member": resourceTFETeamMember(),
"tfe_team_members": resourceTFETeamMembers(),
"tfe_team_token": resourceTFETeamToken(),
"tfe_terraform_version": resourceTFETerraformVersion(),
"tfe_workspace": resourceTFEWorkspace(),
"tfe_workspace_run_task": resourceTFEWorkspaceRunTask(),
"tfe_variable_set": resourceTFEVariableSet(),
"tfe_workspace_variable_set": resourceTFEWorkspaceVariableSet(),
"tfe_workspace_policy_set": resourceTFEWorkspacePolicySet(),
"tfe_workspace_run": resourceTFEWorkspaceRun(),
},
ConfigureContextFunc: configure(),
}
Expand Down
17 changes: 13 additions & 4 deletions tfe/resource_tfe_agent_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ func resourceTFEAgentPool() *schema.Resource {
Computed: true,
ForceNew: true,
},

"organization_scoped": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
},
}
}
Expand All @@ -51,7 +57,8 @@ func resourceTFEAgentPoolCreate(d *schema.ResourceData, meta interface{}) error

// Create a new options struct.
options := tfe.AgentPoolCreateOptions{
Name: tfe.String(name),
Name: tfe.String(name),
OrganizationScoped: tfe.Bool(d.Get("organization_scoped").(bool)),
}

log.Printf("[DEBUG] Create new agent pool for organization: %s", organization)
Expand Down Expand Up @@ -83,6 +90,7 @@ func resourceTFEAgentPoolRead(d *schema.ResourceData, meta interface{}) error {
// Update the config.
d.Set("name", agentPool.Name)
d.Set("organization", agentPool.Organization.Name)
d.Set("organization_scoped", agentPool.OrganizationScoped)

return nil
}
Expand All @@ -92,7 +100,8 @@ func resourceTFEAgentPoolUpdate(d *schema.ResourceData, meta interface{}) error

// Create a new options struct.
options := tfe.AgentPoolUpdateOptions{
Name: tfe.String(d.Get("name").(string)),
Name: tfe.String(d.Get("name").(string)),
OrganizationScoped: tfe.Bool(d.Get("organization_scoped").(bool)),
}

log.Printf("[DEBUG] Update agent pool: %s", d.Id())
Expand Down Expand Up @@ -131,13 +140,13 @@ func resourceTFEAgentPoolImporter(ctx context.Context, d *schema.ResourceData, m
} else if len(s) == 2 {
org := s[0]
poolName := s[1]
poolID, err := fetchAgentPoolID(org, poolName, config.Client)
pool, err := fetchAgentPool(org, poolName, config.Client)
if err != nil {
return nil, fmt.Errorf(
"error retrieving agent pool with name %s from organization %s %w", poolName, org, err)
}

d.SetId(poolID)
d.SetId(pool.ID)
}

return []*schema.ResourceData{d}, nil
Expand Down
Loading