Skip to content

Commit b564c32

Browse files
committed
First draft of resource_tfe_aws_oidc_configuration.go
resource_tfe_aws_oidc_configuration.go and basic test resource_tfe_gcp_oidc_configuration.go and test resource_tfe_azure_oidc_configuration.go_oidc_configuration.go and test resource_tfe_vault_oidc_configuration.go and tests Add HYOK_ORGANIATION_NAME environment variable to testing.md Add documentation for resources Add to CHANGELOG.md update basic usage in vault_oidc_configuration.html.markdown Do not require replace for everything Update documentation and default value of auth_path skipIfEnterprise update pricing info Implement skipUnlessHYOKEnabled function
1 parent 516409f commit b564c32

16 files changed

+1444
-0
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
## Unreleased
2+
FEATURES:
3+
* **New resource**: `r/tfe_vault_oidc_configuration` for managing Vault OIDC configurations. [#1835](https://github.com/hashicorp/terraform-provider-tfe/pull/1835)
4+
* **New resource**: `r/tfe_aws_oidc_configuration` for managing AWS OIDC configurations. [#1835](https://github.com/hashicorp/terraform-provider-tfe/pull/1835)
5+
* **New resource**: `r/tfe_gcp_oidc_configuration` for managing GCP OIDC configurations. [#1835](https://github.com/hashicorp/terraform-provider-tfe/pull/1835)
6+
* **New resource**: `r/tfe_azure_oidc_configuration` for managing Azure OIDC configurations. [#1835](https://github.com/hashicorp/terraform-provider-tfe/pull/1835)
27

38
## v0.69.0
49

docs/testing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ these values with the environment variables specified below:
4949
1. `RUN_TASKS_HMAC` - The optional HMAC Key that should be used for Run Task operations. The default is no key.
5050
1. `GITHUB_APP_INSTALLATION_ID` - GitHub App installation internal id in the format `ghain-xxxxxxx`. Required for running any tests that use GitHub App VCS (workspace, policy sets, registry module).
5151
1. `GITHUB_APP_INSTALLATION_NAME` - GitHub App installation name. Required for running tfe_github_app_installation data source test.
52+
1. `HYOK_ORGANIZATION_NAME` - Name of an organization entitled to use HYOK. Required to run tests for HYOK resources and data sources.
5253

5354
**Note:** In order to run integration tests for **Paid** features you will need a token `TFE_TOKEN` with HCP Terraform or Terraform Enterprise administrator privileges, otherwise the attempt to upgrade an organization's feature set will fail.
5455

internal/provider/helper_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
const RunTasksURLEnvName = "RUN_TASKS_URL"
2020
const RunTasksHMACKeyEnvName = "RUN_TASKS_HMAC"
21+
const HYOKOrganizationNameEnvName = "HYOK_ORGANIZATION_NAME"
2122

2223
type testClientOptions struct {
2324
defaultOrganization string
@@ -238,6 +239,14 @@ func skipUnlessBeta(t *testing.T) {
238239
}
239240
}
240241

242+
func skipUnlessHYOKEnabled(t *testing.T) {
243+
skipIfEnterprise(t)
244+
245+
if value, ok := os.LookupEnv(HYOKOrganizationNameEnvName); !ok || value == "" {
246+
t.Skipf("Skipping tests for HYOK. Set '%s' to enable tests.", HYOKOrganizationNameEnvName)
247+
}
248+
}
249+
241250
// Temporarily skip a test that may be experiencing API errors. This method
242251
// purposefully errors after the set date to remind contributors to remove this check
243252
// and verify that the API errors are no longer occurring.

internal/provider/provider_next.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ func (p *frameworkProvider) Resources(ctx context.Context) []func() resource.Res
171171
NewTerraformVersionResource,
172172
NewOPAVersionResource,
173173
NewsentinelVersionResource,
174+
NewAWSOIDCConfigurationResource,
175+
NewGCPOIDCConfigurationResource,
176+
NewAzureOIDCConfigurationResource,
177+
NewVaultOIDCConfigurationResource,
174178
}
175179
}
176180

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
// // Copyright (c) HashiCorp, Inc.
2+
// // SPDX-License-Identifier: MPL-2.0
3+
4+
package provider
5+
6+
import (
7+
"context"
8+
"errors"
9+
"fmt"
10+
"github.com/hashicorp/terraform-plugin-framework/path"
11+
12+
tfe "github.com/hashicorp/go-tfe"
13+
"github.com/hashicorp/terraform-plugin-framework/resource"
14+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
15+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
16+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
17+
"github.com/hashicorp/terraform-plugin-framework/types"
18+
"github.com/hashicorp/terraform-plugin-log/tflog"
19+
)
20+
21+
var (
22+
_ resource.ResourceWithConfigure = &resourceTFEAWSOIDCConfiguration{}
23+
_ resource.ResourceWithImportState = &resourceTFEAWSOIDCConfiguration{}
24+
)
25+
26+
func NewAWSOIDCConfigurationResource() resource.Resource {
27+
return &resourceTFEAWSOIDCConfiguration{}
28+
}
29+
30+
type resourceTFEAWSOIDCConfiguration struct {
31+
config ConfiguredClient
32+
}
33+
34+
type modelTFEAWSOIDCConfiguration struct {
35+
ID types.String `tfsdk:"id"`
36+
RoleARN types.String `tfsdk:"role_arn"`
37+
Organization types.String `tfsdk:"organization"`
38+
}
39+
40+
func (r *resourceTFEAWSOIDCConfiguration) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
41+
// Prevent panic if the provider has not been configured.
42+
if req.ProviderData == nil {
43+
return
44+
}
45+
46+
client, ok := req.ProviderData.(ConfiguredClient)
47+
if !ok {
48+
resp.Diagnostics.AddError(
49+
"Unexpected resource Configure type",
50+
fmt.Sprintf("Expected tfe.ConfiguredClient, got %T. This is a bug in the tfe provider, so please report it on GitHub.", req.ProviderData),
51+
)
52+
}
53+
r.config = client
54+
}
55+
56+
func (r *resourceTFEAWSOIDCConfiguration) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
57+
resp.TypeName = req.ProviderTypeName + "_aws_oidc_configuration"
58+
}
59+
60+
func (r *resourceTFEAWSOIDCConfiguration) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
61+
resp.Schema = schema.Schema{
62+
Attributes: map[string]schema.Attribute{
63+
"id": schema.StringAttribute{
64+
Description: "The ID of the AWS OIDC configuration.",
65+
Computed: true,
66+
PlanModifiers: []planmodifier.String{
67+
stringplanmodifier.UseStateForUnknown(),
68+
},
69+
},
70+
"role_arn": schema.StringAttribute{
71+
Description: "The AWS ARN of your role.",
72+
Required: true,
73+
},
74+
"organization": schema.StringAttribute{
75+
Description: "Name of the organization to which the TFE AWS OIDC configuration belongs.",
76+
Optional: true,
77+
Computed: true,
78+
PlanModifiers: []planmodifier.String{
79+
stringplanmodifier.RequiresReplace(),
80+
},
81+
},
82+
},
83+
Description: "Generates a new TFE AWS OIDC Configuration.",
84+
}
85+
}
86+
87+
func (r *resourceTFEAWSOIDCConfiguration) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
88+
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
89+
}
90+
91+
func (r *resourceTFEAWSOIDCConfiguration) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
92+
// Read Terraform plan into the model
93+
var plan modelTFEAWSOIDCConfiguration
94+
diags := req.Plan.Get(ctx, &plan)
95+
resp.Diagnostics.Append(diags...)
96+
if resp.Diagnostics.HasError() {
97+
return
98+
}
99+
100+
// Get the organization name from resource or provider config
101+
var orgName string
102+
resp.Diagnostics.Append(r.config.dataOrDefaultOrganization(ctx, req.Config, &orgName)...)
103+
if resp.Diagnostics.HasError() {
104+
return
105+
}
106+
107+
options := tfe.AWSOIDCConfigurationCreateOptions{
108+
RoleARN: plan.RoleARN.ValueString(),
109+
}
110+
111+
tflog.Debug(ctx, fmt.Sprintf("Create TFE AWS OIDC Configuration for organization %s", orgName))
112+
oidc, err := r.config.Client.AWSOIDCConfigurations.Create(ctx, orgName, options)
113+
if err != nil {
114+
resp.Diagnostics.AddError("Error creating TFE AWS OIDC Configuration", err.Error())
115+
return
116+
}
117+
result := modelFromTFEAWSOIDCConfiguration(oidc)
118+
resp.Diagnostics.Append(resp.State.Set(ctx, result)...)
119+
}
120+
121+
func (r *resourceTFEAWSOIDCConfiguration) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
122+
// Read Terraform state into the model
123+
var state modelTFEAWSOIDCConfiguration
124+
diags := req.State.Get(ctx, &state)
125+
resp.Diagnostics.Append(diags...)
126+
if resp.Diagnostics.HasError() {
127+
return
128+
}
129+
130+
oidcID := state.ID.ValueString()
131+
tflog.Debug(ctx, fmt.Sprintf("Read AWS OIDC configuration: %s", oidcID))
132+
oidc, err := r.config.Client.AWSOIDCConfigurations.Read(ctx, state.ID.ValueString())
133+
if err != nil {
134+
if errors.Is(err, tfe.ErrResourceNotFound) {
135+
tflog.Debug(ctx, fmt.Sprintf("AWS OIDC configuration %s no longer exists", oidcID))
136+
resp.State.RemoveResource(ctx)
137+
return
138+
}
139+
resp.Diagnostics.AddError(
140+
fmt.Sprintf("Error reading AWS OIDC configuration %s", oidcID),
141+
err.Error(),
142+
)
143+
return
144+
}
145+
result := modelFromTFEAWSOIDCConfiguration(oidc)
146+
resp.Diagnostics.Append(resp.State.Set(ctx, result)...)
147+
}
148+
149+
func (r *resourceTFEAWSOIDCConfiguration) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
150+
var plan modelTFEAWSOIDCConfiguration
151+
diags := req.Plan.Get(ctx, &plan)
152+
resp.Diagnostics.Append(diags...)
153+
154+
var state modelTFEAWSOIDCConfiguration
155+
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
156+
if resp.Diagnostics.HasError() {
157+
return
158+
}
159+
160+
options := tfe.AWSOIDCConfigurationUpdateOptions{
161+
RoleARN: plan.RoleARN.ValueString(),
162+
}
163+
164+
oidcID := state.ID.ValueString()
165+
tflog.Debug(ctx, fmt.Sprintf("Update TFE AWS OIDC Configuration %s", oidcID))
166+
oidc, err := r.config.Client.AWSOIDCConfigurations.Update(ctx, oidcID, options)
167+
if err != nil {
168+
resp.Diagnostics.AddError("Error updating TFE AWS OIDC Configuration", err.Error())
169+
return
170+
}
171+
172+
result := modelFromTFEAWSOIDCConfiguration(oidc)
173+
resp.Diagnostics.Append(resp.State.Set(ctx, result)...)
174+
}
175+
176+
func (r *resourceTFEAWSOIDCConfiguration) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
177+
var state modelTFEAWSOIDCConfiguration
178+
diags := req.State.Get(ctx, &state)
179+
resp.Diagnostics.Append(diags...)
180+
if resp.Diagnostics.HasError() {
181+
return
182+
}
183+
184+
oidcID := state.ID.ValueString()
185+
tflog.Debug(ctx, fmt.Sprintf("Delete TFE AWS OIDC configuration: %s", oidcID))
186+
err := r.config.Client.AWSOIDCConfigurations.Delete(ctx, oidcID)
187+
if err != nil {
188+
if errors.Is(err, tfe.ErrResourceNotFound) {
189+
tflog.Debug(ctx, fmt.Sprintf("TFE AWS OIDC configuration %s no longer exists", oidcID))
190+
}
191+
192+
resp.Diagnostics.AddError("Error deleting TFE AWS OIDC Configuration", err.Error())
193+
return
194+
}
195+
}
196+
197+
func modelFromTFEAWSOIDCConfiguration(p *tfe.AWSOIDCConfiguration) modelTFEAWSOIDCConfiguration {
198+
return modelTFEAWSOIDCConfiguration{
199+
ID: types.StringValue(p.ID),
200+
RoleARN: types.StringValue(p.RoleARN),
201+
Organization: types.StringValue(p.Organization.Name),
202+
}
203+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package provider
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-testing/terraform"
10+
)
11+
12+
func TestAccTFEAWSOIDCConfiguration_basic(t *testing.T) {
13+
skipUnlessHYOKEnabled(t)
14+
15+
orgName := os.Getenv("HYOK_ORGANIZATION_NAME")
16+
17+
originalRoleARN := "arn:aws:iam::123456789012:role/terraform-provider-tfe-example-1"
18+
newRoleARN := "arn:aws:iam::123456789012:role/terraform-provider-tfe-example-2"
19+
20+
resource.Test(t, resource.TestCase{
21+
PreCheck: func() { testAccPreCheck(t) },
22+
ProtoV5ProviderFactories: testAccMuxedProviders,
23+
CheckDestroy: testAccCheckTFEAWSOIDCConfigurationDestroy,
24+
Steps: []resource.TestStep{
25+
{
26+
Config: testAccTFEAWSOIDCConfigurationConfig(orgName, originalRoleARN),
27+
Check: resource.ComposeAggregateTestCheckFunc(
28+
resource.TestCheckResourceAttrSet("tfe_aws_oidc_configuration.test", "id"),
29+
resource.TestCheckResourceAttr("tfe_aws_oidc_configuration.test", "role_arn", originalRoleARN),
30+
),
31+
},
32+
// Import
33+
{
34+
ResourceName: "tfe_aws_oidc_configuration.test",
35+
ImportState: true,
36+
ImportStateVerify: true,
37+
},
38+
// Update role ARN
39+
{
40+
Config: testAccTFEAWSOIDCConfigurationConfig(orgName, newRoleARN),
41+
Check: resource.ComposeAggregateTestCheckFunc(
42+
resource.TestCheckResourceAttrSet("tfe_aws_oidc_configuration.test", "id"),
43+
resource.TestCheckResourceAttr("tfe_aws_oidc_configuration.test", "role_arn", newRoleARN),
44+
),
45+
},
46+
},
47+
})
48+
}
49+
50+
func testAccTFEAWSOIDCConfigurationConfig(orgName string, roleARN string) string {
51+
return fmt.Sprintf(`
52+
resource "tfe_aws_oidc_configuration" "test" {
53+
role_arn = "%s"
54+
organization = "%s"
55+
}
56+
`, roleARN, orgName)
57+
}
58+
59+
func testAccCheckTFEAWSOIDCConfigurationDestroy(s *terraform.State) error {
60+
for _, rs := range s.RootModule().Resources {
61+
if rs.Type != "tfe_aws_oidc_configuration" {
62+
continue
63+
}
64+
65+
if rs.Primary.ID == "" {
66+
return fmt.Errorf("no instance ID is set")
67+
}
68+
69+
_, err := testAccConfiguredClient.Client.AWSOIDCConfigurations.Read(ctx, rs.Primary.ID)
70+
if err == nil {
71+
return fmt.Errorf("TFE AWS OIDC Configuration %s still exists", rs.Primary.ID)
72+
}
73+
}
74+
75+
return nil
76+
}

0 commit comments

Comments
 (0)