Skip to content

Commit 99097c7

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 resource_tfe_hyok_configuration.go Add hyok_configuration.html.markdown fix bug where aws configs recognized as gcp configs Add in acceptance tests Wait for revoked status during acceptance test Add CHANGELOG.md
1 parent adb0fe2 commit 99097c7

18 files changed

+2236
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
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)
7+
* **New resource**: `r/tfe_hyok_configuration` for managing HYOK configurations, by @helenjw. [#1835](https://github.com/hashicorp/terraform-provider-tfe/pull/1841)
28

39
## v0.68.3
410

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/provider_next.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ func (p *frameworkProvider) Resources(ctx context.Context) []func() resource.Res
168168
NewWorkspaceRunTaskResource,
169169
NewNotificationConfigurationResource,
170170
NewTeamTokenResource,
171+
NewAWSOIDCConfigurationResource,
172+
NewGCPOIDCConfigurationResource,
173+
NewAzureOIDCConfigurationResource,
174+
NewVaultOIDCConfigurationResource,
175+
NewHYOKConfigurationResource,
171176
}
172177
}
173178

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: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
skipIfEnterprise(t)
14+
15+
orgName := os.Getenv("HYOK_ORGANIZATION_NAME")
16+
17+
if orgName == "" {
18+
t.Skip("Test skipped: HYOK_ORGANIZATION_NAME environment variable is not set")
19+
}
20+
21+
originalRoleARN := "arn:aws:iam::123456789012:role/terraform-provider-tfe-example-1"
22+
newRoleARN := "arn:aws:iam::123456789012:role/terraform-provider-tfe-example-2"
23+
24+
resource.Test(t, resource.TestCase{
25+
PreCheck: func() { testAccPreCheck(t) },
26+
ProtoV5ProviderFactories: testAccMuxedProviders,
27+
CheckDestroy: testAccCheckTFEAWSOIDCConfigurationDestroy,
28+
Steps: []resource.TestStep{
29+
{
30+
Config: testAccTFEAWSOIDCConfigurationConfig(orgName, originalRoleARN),
31+
Check: resource.ComposeAggregateTestCheckFunc(
32+
resource.TestCheckResourceAttrSet("tfe_aws_oidc_configuration.test", "id"),
33+
resource.TestCheckResourceAttr("tfe_aws_oidc_configuration.test", "role_arn", originalRoleARN),
34+
),
35+
},
36+
// Import
37+
{
38+
ResourceName: "tfe_aws_oidc_configuration.test",
39+
ImportState: true,
40+
ImportStateVerify: true,
41+
},
42+
// Update role ARN
43+
{
44+
Config: testAccTFEAWSOIDCConfigurationConfig(orgName, newRoleARN),
45+
Check: resource.ComposeAggregateTestCheckFunc(
46+
resource.TestCheckResourceAttrSet("tfe_aws_oidc_configuration.test", "id"),
47+
resource.TestCheckResourceAttr("tfe_aws_oidc_configuration.test", "role_arn", newRoleARN),
48+
),
49+
},
50+
},
51+
})
52+
}
53+
54+
func testAccTFEAWSOIDCConfigurationConfig(orgName string, roleARN string) string {
55+
return fmt.Sprintf(`
56+
resource "tfe_aws_oidc_configuration" "test" {
57+
role_arn = "%s"
58+
organization = "%s"
59+
}
60+
`, roleARN, orgName)
61+
}
62+
63+
func testAccCheckTFEAWSOIDCConfigurationDestroy(s *terraform.State) error {
64+
for _, rs := range s.RootModule().Resources {
65+
if rs.Type != "tfe_aws_oidc_configuration" {
66+
continue
67+
}
68+
69+
if rs.Primary.ID == "" {
70+
return fmt.Errorf("no instance ID is set")
71+
}
72+
73+
_, err := testAccConfiguredClient.Client.AWSOIDCConfigurations.Read(ctx, rs.Primary.ID)
74+
if err == nil {
75+
return fmt.Errorf("TFE AWS OIDC Configuration %s still exists", rs.Primary.ID)
76+
}
77+
}
78+
79+
return nil
80+
}

0 commit comments

Comments
 (0)