Skip to content

Commit

Permalink
Merge pull request #1137 from hashicorp/SwiftEngineer/org-level-agent…
Browse files Browse the repository at this point in the history
…-pools

support for organization-level default execution mode and agent pool
  • Loading branch information
brandonc authored Nov 27, 2023
2 parents 39efeca + ca721a3 commit f217b6e
Show file tree
Hide file tree
Showing 11 changed files with 799 additions and 68 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
<!-- Add CHANGELOG entry to this section for any PR awaiting the next release -->
<!-- Please also include if this is a Bug Fix, Enhancement, or Feature -->

BREAKING CHANGES:
* `r/tfe_workspace`: Default value of the `execution_mode` field now uses the organization's `default_execution_mode`. If no `default_execution_mode` has been set, the default `execution_mode` will be unchanged (i.e. `remote`).

FEATURES:
* `d/tfe_registry_module`: Add `vcs_repo.tags` and `vcs_repo.branch` attributes to allow configuration of `publishing_mechanism`. Add `test_config` to support running tests on `branch`-based registry modules, by @hashimoon [1096](https://github.com/hashicorp/terraform-provider-tfe/pull/1096)
* **New Resource**: `r/tfe_organization_default_execution_mode` is a new resource to set the `default_execution_mode` and `default_agent_pool_id` for an organization, by @SwiftEngineer [1137](https://github.com/hashicorp/terraform-provider-tfe/pull/1137)'
* `r/tfe_workspace`: Now uses the organization's `default_execution_mode` and `default_agent_pool_id` as the default `execution_mode`, by @SwiftEngineer [1137](https://github.com/hashicorp/terraform-provider-tfe/pull/1137)'

ENHANCEMENTS:
* `d/tfe_organization`: Make `name` argument optional if configured for the provider, by @tmatilai [1133](https://github.com/hashicorp/terraform-provider-tfe/pull/1133)
Expand Down
77 changes: 39 additions & 38 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,44 +106,45 @@ func Provider() *schema.Provider {
},

ResourcesMap: map[string]*schema.Resource{
"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_policy_set": resourceTFEProjectPolicySet(),
"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_policy_set": resourceTFEWorkspacePolicySet(),
"tfe_workspace_policy_set_exclusion": resourceTFEWorkspacePolicySetExclusion(),
"tfe_workspace_run": resourceTFEWorkspaceRun(),
"tfe_workspace_variable_set": resourceTFEWorkspaceVariableSet(),
"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_default_execution_mode": resourceTFEOrganizationDefaultExecutionMode(),
"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_policy_set": resourceTFEProjectPolicySet(),
"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_policy_set": resourceTFEWorkspacePolicySet(),
"tfe_workspace_policy_set_exclusion": resourceTFEWorkspacePolicySetExclusion(),
"tfe_workspace_run": resourceTFEWorkspaceRun(),
"tfe_workspace_variable_set": resourceTFEWorkspaceVariableSet(),
},
ConfigureContextFunc: configure(),
}
Expand Down
162 changes: 162 additions & 0 deletions internal/provider/resource_tfe_organization_default_execution_mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package provider

import (
"context"
"errors"
"fmt"
tfe "github.com/hashicorp/go-tfe"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"log"
)

func resourceTFEOrganizationDefaultExecutionMode() *schema.Resource {
return &schema.Resource{
Create: resourceTFEOrganizationDefaultExecutionModeCreate,
Read: resourceTFEOrganizationDefaultExecutionModeRead,
Delete: resourceTFEOrganizationDefaultExecutionModeDelete,
Importer: &schema.ResourceImporter{
StateContext: resourceTFEOrganizationDefaultExecutionModeImporter,
},

Schema: map[string]*schema.Schema{
"organization": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"default_execution_mode": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(
[]string{
"agent",
"local",
"remote",
},
false,
),
ForceNew: true,
},

"default_agent_pool_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
}
}

func resourceTFEOrganizationDefaultExecutionModeCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(ConfiguredClient)

// Get the organization name.
organization, err := config.schemaOrDefaultOrganization(d)
if err != nil {
return fmt.Errorf("error getting organization name: %w", err)
}

// If the "default_agent_pool_id" was provided, get the agent pool
var agentPool *tfe.AgentPool
if v, ok := d.GetOk("default_agent_pool_id"); ok && v.(string) != "" {
agentPool = &tfe.AgentPool{
ID: v.(string),
}
}

defaultExecutionMode := ""
if v, ok := d.GetOk("default_execution_mode"); ok {
defaultExecutionMode = v.(string)
} else {
return fmt.Errorf("default_execution_mode was missing from tfstate, please create an issue to report this error")
}

// set organization default execution mode
_, err = config.Client.Organizations.Update(context.Background(), organization, tfe.OrganizationUpdateOptions{
DefaultExecutionMode: tfe.String(defaultExecutionMode),
DefaultAgentPool: agentPool,
})
if err != nil {
return fmt.Errorf("error setting default execution mode of organization %s: %w", d.Id(), err)
}

d.SetId(organization)

return resourceTFEOrganizationDefaultExecutionModeRead(d, meta)
}

func resourceTFEOrganizationDefaultExecutionModeRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(ConfiguredClient)

log.Printf("[DEBUG] Read the organization: %s", d.Id())
organization, err := config.Client.Organizations.Read(ctx, d.Id())
if err != nil {
if errors.Is(err, tfe.ErrResourceNotFound) {
log.Printf("[DEBUG] organization %s no longer exists", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("error reading organization %s: %w", d.Id(), err)
}

defaultExecutionMode := ""
if v, ok := d.GetOk("default_execution_mode"); ok {
defaultExecutionMode = v.(string)
} else {
return fmt.Errorf("default_execution_mode was missing from tfstate, please create an issue to report this error")
}
if organization.DefaultExecutionMode != defaultExecutionMode {
// set id to empty string so that the provider knows it needs to set the default execution mode again
d.SetId("")
}

return nil
}

func resourceTFEOrganizationDefaultExecutionModeDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(ConfiguredClient)

// Get the organization name.
organization, err := config.schemaOrDefaultOrganization(d)
if err != nil {
return fmt.Errorf("error getting organization name: %w", err)
}

log.Printf("[DEBUG] Reseting default execution mode of organization: %s", organization)
// reset organization default execution mode
_, err = config.Client.Organizations.Update(context.Background(), organization, tfe.OrganizationUpdateOptions{
DefaultExecutionMode: tfe.String("remote"),
DefaultAgentPool: nil,
})
if err != nil {
return fmt.Errorf("error updating organization default execution mode: %w", err)
}

return nil
}

func resourceTFEOrganizationDefaultExecutionModeImporter(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
config := meta.(ConfiguredClient)

log.Printf("[DEBUG] Read the organization: %s", d.Id())
organization, err := config.Client.Organizations.Read(ctx, d.Id())
if err != nil {
if errors.Is(err, tfe.ErrResourceNotFound) {
log.Printf("[DEBUG] organization %s no longer exists", d.Id())
d.SetId("")
}
return nil, fmt.Errorf("error reading organization %s: %w", d.Id(), err)
}

// Set the organization field.
d.Set("organization", d.Id())
d.Set("default_execution_mode", organization.DefaultExecutionMode)
if organization.DefaultAgentPool != nil {
d.Set("default_agent_pool_id", organization.DefaultAgentPool.ID)
}

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

0 comments on commit f217b6e

Please sign in to comment.