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 default project to organization default settings #1603

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ FEATURES:
* `r/tfe_project`: Add `auto_destroy_activity_duration` field to the project resource, which automatically propagates auto-destroy settings to workspaces [1550](https://github.com/hashicorp/terraform-provider-tfe/pull/1550)
* `d/tfe_project`: Add `auto_destroy_activity_duration` field to the project datasource [1550](https://github.com/hashicorp/terraform-provider-tfe/pull/1550)
* `r/tfe_team_project_access`: Add `variable_sets` attribute to `project_access`, by @mkam [#1565](https://github.com/hashicorp/terraform-provider-tfe/pull/1565)
* `r/tfe_organization_default_settings`: Add `default_project_id` to allow setting a default project for an organization, by @netramali [#1603](https://github.com/hashicorp/terraform-provider-tfe/pull/1603)

BUG FIXES:
* `r/tfe_stack`: Fix serialization issue when using github app installation within vcs_repo block, by @mjyocca [#1572](https://github.com/hashicorp/terraform-provider-tfe/pull/1572)
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-slug v0.16.4
github.com/hashicorp/go-tfe v1.75.0
github.com/hashicorp/go-tfe v1.75.1-0.20250221201235-2bf0f5fde70c
github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
Expand Down Expand Up @@ -42,7 +42,7 @@ require (
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
github.com/hashicorp/go-plugin v1.6.3 // indirect
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/jsonapi v1.3.2
github.com/hashicorp/jsonapi v1.4.3-0.20250220162346-81a76b606f3e
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.22.0 // indirect
github.com/hashicorp/terraform-json v0.24.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ github.com/hashicorp/go-slug v0.16.4 h1:kI0mOUVjbBsyocwO29pZIQzzkBnfQNdU4eqlUpNd
github.com/hashicorp/go-slug v0.16.4/go.mod h1:THWVTAXwJEinbsp4/bBRcmbaO5EYNLTqxbG4tZ3gCYQ=
github.com/hashicorp/go-tfe v1.75.0 h1:7dixINN0rOmNo4Vpe/6aVCbF0j4bQpSVzw64CSLBTe8=
github.com/hashicorp/go-tfe v1.75.0/go.mod h1:IyJtCSk6TxidVAWcZeEgFzc/6fDDjinf21wyaBBc2mg=
github.com/hashicorp/go-tfe v1.75.1-0.20250210225844-d114b5d76004 h1:3BwbVozz6xQQEcdizD7inM35fCvFtNV/QNov69M2LqY=
github.com/hashicorp/go-tfe v1.75.1-0.20250210225844-d114b5d76004/go.mod h1:0y+AMmGlixZulyaEWAFu/pwLC0PQmY6XYnKDGODytps=
github.com/hashicorp/go-tfe v1.75.1-0.20250221201235-2bf0f5fde70c h1:WlfLV1Mb5Mms0wsbcsjHlsuhlYkCrGk8Br5Sot5q8lY=
github.com/hashicorp/go-tfe v1.75.1-0.20250221201235-2bf0f5fde70c/go.mod h1:+EccOb8gn34nC7HMd2ErF0TrUbltwyPWSFyRJclSFk4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
Expand All @@ -87,6 +91,10 @@ github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3q
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hashicorp/jsonapi v1.3.2 h1:gP3fX2ZT7qXi+PbwieptzkspIohO2kCSiBUvUTBAbMs=
github.com/hashicorp/jsonapi v1.3.2/go.mod h1:kWfdn49yCjQvbpnvY1dxxAuAFzISwrrMDQOcu6NsFoM=
github.com/hashicorp/jsonapi v1.4.1 h1:U6CZvnS70Sg7im0kpfhWAoF3NasLumaMndQhEWniHZA=
github.com/hashicorp/jsonapi v1.4.1/go.mod h1:kWfdn49yCjQvbpnvY1dxxAuAFzISwrrMDQOcu6NsFoM=
github.com/hashicorp/jsonapi v1.4.3-0.20250220162346-81a76b606f3e h1:xwy/1T0cxHWaLx2MM0g4BlaQc1BXn/9835mPrBqwSPU=
github.com/hashicorp/jsonapi v1.4.3-0.20250220162346-81a76b606f3e/go.mod h1:kWfdn49yCjQvbpnvY1dxxAuAFzISwrrMDQOcu6NsFoM=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/terraform-exec v0.22.0 h1:G5+4Sz6jYZfRYUCg6eQgDsqTzkNXV+fP8l+uRmZHj64=
Expand Down
18 changes: 18 additions & 0 deletions internal/provider/resource_tfe_organization_default_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"log"

tfe "github.com/hashicorp/go-tfe"
"github.com/hashicorp/jsonapi"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
Expand Down Expand Up @@ -57,6 +58,12 @@ func resourceTFEOrganizationDefaultSettings() *schema.Resource {
Optional: true,
ForceNew: true,
},

"default_project_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
}
}
Expand All @@ -78,6 +85,12 @@ func resourceTFEOrganizationDefaultSettingsCreate(d *schema.ResourceData, meta i
}
}

// If the default project id was provided, get the default project
var project jsonapi.NullableRelationship[*tfe.Project]
if v, ok := d.GetOk("default_project_id"); ok && v.(string) != "" {
project = jsonapi.NewNullableRelationshipWithValue[*tfe.Project](&tfe.Project{ID: v.(string)})
}

defaultExecutionMode := ""
if v, ok := d.GetOk("default_execution_mode"); ok {
defaultExecutionMode = v.(string)
Expand All @@ -89,6 +102,7 @@ func resourceTFEOrganizationDefaultSettingsCreate(d *schema.ResourceData, meta i
_, err = config.Client.Organizations.Update(context.Background(), organization, tfe.OrganizationUpdateOptions{
DefaultExecutionMode: tfe.String(defaultExecutionMode),
DefaultAgentPool: agentPool,
DefaultProject: project,
})
if err != nil {
return fmt.Errorf("error setting default execution mode of organization %s: %w", d.Id(), err)
Expand Down Expand Up @@ -141,6 +155,7 @@ func resourceTFEOrganizationDefaultSettingsDelete(d *schema.ResourceData, meta i
_, err = config.Client.Organizations.Update(context.Background(), organization, tfe.OrganizationUpdateOptions{
DefaultExecutionMode: tfe.String("remote"),
DefaultAgentPool: nil,
DefaultProject: jsonapi.NewNullNullableRelationship[*tfe.Project](),
})
if err != nil {
return fmt.Errorf("error updating organization default execution mode: %w", err)
Expand Down Expand Up @@ -168,6 +183,9 @@ func resourceTFEOrganizationDefaultSettingsImporter(ctx context.Context, d *sche
if organization.DefaultAgentPool != nil {
d.Set("default_agent_pool_id", organization.DefaultAgentPool.ID)
}
if organization.DefaultProject != nil {
d.Set("default_project_id", organization.DefaultProject.ID)
}

return []*schema.ResourceData{d}, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,27 @@ func TestAccTFEOrganizationDefaultSettings_agent(t *testing.T) {
})
}

func TestAccTFEOrganizationDefaultSettings_project(t *testing.T) {
org := &tfe.Organization{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEOrganizationDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEOrganizationDefaultSettings_project(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFEOrganizationExists(
"tfe_organization.foobar", org),
testAccCheckTFEOrganizationDefaultProjectIDExists(org),
),
},
},
})
}

func TestAccTFEOrganizationDefaultSettings_update(t *testing.T) {
org := &tfe.Organization{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
Expand All @@ -106,6 +127,14 @@ func TestAccTFEOrganizationDefaultSettings_update(t *testing.T) {
testAccCheckTFEOrganizationDefaultAgentPoolIDExists(org),
),
},
{
Config: testAccTFEOrganizationDefaultSettings_project(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFEOrganizationExists(
"tfe_organization.foobar", org),
testAccCheckTFEOrganizationDefaultProjectIDExists(org),
),
},
{
Config: testAccTFEOrganizationDefaultSettings_local(rInt),
Check: resource.ComposeTestCheckFunc(
Expand Down Expand Up @@ -135,9 +164,8 @@ func TestAccTFEOrganizationDefaultSettings_import(t *testing.T) {
CheckDestroy: testAccCheckTFEOrganizationDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEOrganizationDefaultSettings_remote(rInt),
Config: testAccTFEOrganizationDefaultSettings_import(rInt),
},

{
ResourceName: "tfe_organization_default_settings.foobar",
ImportState: true,
Expand Down Expand Up @@ -167,16 +195,51 @@ func testAccCheckTFEOrganizationDefaultAgentPoolIDExists(org *tfe.Organization)
}
}

func testAccCheckTFEOrganizationDefaultProjectIDExists(org *tfe.Organization) resource.TestCheckFunc {
return func(s *terraform.State) error {
if org.DefaultProject == nil {
return errors.New("default project was not set")
}

return nil
}
}

func testAccTFEOrganizationDefaultSettings_remote(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "[email protected]"
}

resource "tfe_project" "foobar" {
name = "project-test"
organization = tfe_organization.foobar.name
}

resource "tfe_organization_default_settings" "foobar" {
organization = tfe_organization.foobar.name
default_execution_mode = "remote"
default_project_id = tfe_project.foobar.id
}`, rInt)
}

func testAccTFEOrganizationDefaultSettings_import(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "[email protected]"
}

data "tfe_project" "original" {
name = "Default Project"
organization = tfe_organization.foobar.name
}

resource "tfe_organization_default_settings" "foobar" {
organization = tfe_organization.foobar.name
default_execution_mode = "remote"
default_project_id = data.tfe_project.original.id
}`, rInt)
}

Expand Down Expand Up @@ -211,3 +274,22 @@ resource "tfe_organization_default_settings" "foobar" {
default_agent_pool_id = tfe_agent_pool.foobar.id
}`, rInt)
}

func testAccTFEOrganizationDefaultSettings_project(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "[email protected]"
}

resource "tfe_project" "foobar" {
name = "project-test"
organization = tfe_organization.foobar.name
}

resource "tfe_organization_default_settings" "foobar" {
organization = tfe_organization.foobar.name
default_execution_mode = "remote"
default_project_id = tfe_project.foobar.id
}`, rInt)
}
11 changes: 9 additions & 2 deletions website/docs/r/organization_default_settings.html.markdown
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: "tfe"
page_title: "Terraform Enterprise: tfe_organization_default_settings
page_title: "Terraform Enterprise: tfe_organization_default_settings"
description: |-
Sets the workspace defaults for an organization
---
Expand All @@ -24,10 +24,16 @@ resource "tfe_agent_pool" "my_agents" {
organization = tfe_organization.test.name
}

resource "tfe_project" "my_project" {
name = "my-project"
organization = tfe_organization.test.name
}

resource "tfe_organization_default_settings" "org_default" {
organization = tfe_organization.test.name
default_execution_mode = "agent"
default_agent_pool_id = tfe_agent_pool.my_agents.id
default_project_id = tfe_project.my_project.id
}

resource "tfe_workspace" "my_workspace" {
Expand All @@ -46,12 +52,13 @@ The following arguments are supported:
* `default_execution_mode` - (Optional) Which [execution mode](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/settings#execution-mode)
to use as the default for all workspaces in the organization. Valid values are `remote`, `local` or`agent`.
* `default_agent_pool_id` - (Optional) The ID of an agent pool to assign to the workspace. Requires `default_execution_mode` to be set to `agent`. This value _must not_ be provided if `default_execution_mode` is set to any other value.
* `default_project_id` - (Optional) The ID of a project to assign as the default project for the organization.
* `organization` - (Optional) Name of the organization. If omitted, organization must be defined in the provider config.


## Import

Organization default execution mode can be imported; use `<ORGANIZATION NAME>` as the import ID. For example:
Organization default execution mode and default project can be imported; use `<ORGANIZATION NAME>` as the import ID. For example:

```shell
terraform import tfe_organization_default_settings.test my-org-name
Expand Down