Skip to content

Commit cd4db82

Browse files
committed
resource_tfe_azure_oidc_configuration.go_oidc_configuration.go and test
1 parent 13bab79 commit cd4db82

File tree

3 files changed

+317
-0
lines changed

3 files changed

+317
-0
lines changed

internal/provider/provider_next.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ func (p *frameworkProvider) Resources(ctx context.Context) []func() resource.Res
170170
NewTeamTokenResource,
171171
NewAWSOIDCConfigurationResource,
172172
NewGCPOIDCConfigurationResource,
173+
NewAzureOIDCConfigurationResource,
173174
}
174175
}
175176

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
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 = &resourceTFEAzureOIDCConfiguration{}
23+
_ resource.ResourceWithImportState = &resourceTFEAzureOIDCConfiguration{}
24+
)
25+
26+
func NewAzureOIDCConfigurationResource() resource.Resource {
27+
return &resourceTFEAzureOIDCConfiguration{}
28+
}
29+
30+
type resourceTFEAzureOIDCConfiguration struct {
31+
config ConfiguredClient
32+
}
33+
34+
type modelTFEAzureOIDCConfiguration struct {
35+
ID types.String `tfsdk:"id"`
36+
ClientID types.String `tfsdk:"client_id"`
37+
SubscriptionID types.String `tfsdk:"subscription_id"`
38+
TenantID types.String `tfsdk:"tenant_id"`
39+
Organization types.String `tfsdk:"organization"`
40+
}
41+
42+
func (r *resourceTFEAzureOIDCConfiguration) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
43+
// Prevent panic if the provider has not been configured.
44+
if req.ProviderData == nil {
45+
return
46+
}
47+
48+
client, ok := req.ProviderData.(ConfiguredClient)
49+
if !ok {
50+
resp.Diagnostics.AddError(
51+
"Unexpected resource Configure type",
52+
fmt.Sprintf("Expected tfe.ConfiguredClient, got %T. This is a bug in the tfe provider, so please report it on GitHub.", req.ProviderData),
53+
)
54+
}
55+
r.config = client
56+
}
57+
58+
func (r *resourceTFEAzureOIDCConfiguration) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
59+
resp.TypeName = req.ProviderTypeName + "_azure_oidc_configuration"
60+
}
61+
62+
func (r *resourceTFEAzureOIDCConfiguration) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
63+
resp.Schema = schema.Schema{
64+
Attributes: map[string]schema.Attribute{
65+
"id": schema.StringAttribute{
66+
Description: "The ID of the Azure OIDC configuration.",
67+
Computed: true,
68+
PlanModifiers: []planmodifier.String{
69+
stringplanmodifier.UseStateForUnknown(),
70+
},
71+
},
72+
"client_id": schema.StringAttribute{
73+
Description: "The Client (or Application) ID of your Entra ID application.",
74+
Required: true,
75+
PlanModifiers: []planmodifier.String{
76+
stringplanmodifier.RequiresReplace(),
77+
},
78+
},
79+
"subscription_id": schema.StringAttribute{
80+
Description: "The ID of your Azure subscription.",
81+
Required: true,
82+
PlanModifiers: []planmodifier.String{
83+
stringplanmodifier.RequiresReplace(),
84+
},
85+
},
86+
"tenant_id": schema.StringAttribute{
87+
Description: "The Tenant (or Directory) ID of your Entra ID application.",
88+
Required: true,
89+
PlanModifiers: []planmodifier.String{
90+
stringplanmodifier.RequiresReplace(),
91+
},
92+
},
93+
"organization": schema.StringAttribute{
94+
Description: "Name of the organization to which the TFE Azure OIDC configuration belongs.",
95+
Optional: true,
96+
Computed: true,
97+
PlanModifiers: []planmodifier.String{
98+
stringplanmodifier.RequiresReplace(),
99+
},
100+
},
101+
},
102+
Description: "Generates a new TFE Azure OIDC Configuration.",
103+
}
104+
}
105+
106+
func (r *resourceTFEAzureOIDCConfiguration) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
107+
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
108+
}
109+
110+
func (r *resourceTFEAzureOIDCConfiguration) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
111+
// Read Terraform plan into the model
112+
var plan modelTFEAzureOIDCConfiguration
113+
diags := req.Plan.Get(ctx, &plan)
114+
resp.Diagnostics.Append(diags...)
115+
if resp.Diagnostics.HasError() {
116+
return
117+
}
118+
119+
// Get the organization name from resource or provider config
120+
var orgName string
121+
resp.Diagnostics.Append(r.config.dataOrDefaultOrganization(ctx, req.Config, &orgName)...)
122+
if resp.Diagnostics.HasError() {
123+
return
124+
}
125+
126+
options := tfe.AzureOIDCConfigurationCreateOptions{
127+
ClientID: plan.ClientID.ValueString(),
128+
SubscriptionID: plan.SubscriptionID.ValueString(),
129+
TenantID: plan.TenantID.ValueString(),
130+
}
131+
132+
tflog.Debug(ctx, fmt.Sprintf("Create TFE Azure OIDC Configuration for organization %s", orgName))
133+
oidc, err := r.config.Client.AzureOIDCConfigurations.Create(ctx, orgName, options)
134+
if err != nil {
135+
resp.Diagnostics.AddError("Error creating TFE Azure OIDC Configuration", err.Error())
136+
return
137+
}
138+
result := modelFromTFEAzureOIDCConfiguration(oidc)
139+
resp.Diagnostics.Append(resp.State.Set(ctx, result)...)
140+
}
141+
142+
func (r *resourceTFEAzureOIDCConfiguration) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
143+
// Read Terraform state into the model
144+
var state modelTFEAzureOIDCConfiguration
145+
diags := req.State.Get(ctx, &state)
146+
resp.Diagnostics.Append(diags...)
147+
if resp.Diagnostics.HasError() {
148+
return
149+
}
150+
151+
oidcID := state.ID.ValueString()
152+
tflog.Debug(ctx, fmt.Sprintf("Read Azure OIDC configuration: %s", oidcID))
153+
oidc, err := r.config.Client.AzureOIDCConfigurations.Read(ctx, state.ID.ValueString())
154+
if err != nil {
155+
if errors.Is(err, tfe.ErrResourceNotFound) {
156+
tflog.Debug(ctx, fmt.Sprintf("Azure OIDC configuration %s no longer exists", oidcID))
157+
resp.State.RemoveResource(ctx)
158+
return
159+
}
160+
resp.Diagnostics.AddError(
161+
fmt.Sprintf("Error reading Azure OIDC configuration %s", oidcID),
162+
err.Error(),
163+
)
164+
return
165+
}
166+
result := modelFromTFEAzureOIDCConfiguration(oidc)
167+
resp.Diagnostics.Append(resp.State.Set(ctx, result)...)
168+
}
169+
170+
func (r *resourceTFEAzureOIDCConfiguration) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
171+
var plan modelTFEAzureOIDCConfiguration
172+
diags := req.Plan.Get(ctx, &plan)
173+
resp.Diagnostics.Append(diags...)
174+
175+
var state modelTFEAzureOIDCConfiguration
176+
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
177+
if resp.Diagnostics.HasError() {
178+
return
179+
}
180+
181+
options := tfe.AzureOIDCConfigurationUpdateOptions{
182+
ClientID: plan.ClientID.ValueStringPointer(),
183+
SubscriptionID: plan.SubscriptionID.ValueStringPointer(),
184+
TenantID: plan.TenantID.ValueStringPointer(),
185+
}
186+
187+
oidcID := state.ID.ValueString()
188+
tflog.Debug(ctx, fmt.Sprintf("Update TFE Azure OIDC Configuration %s", oidcID))
189+
oidc, err := r.config.Client.AzureOIDCConfigurations.Update(ctx, oidcID, options)
190+
if err != nil {
191+
resp.Diagnostics.AddError("Error updating TFE Azure OIDC Configuration", err.Error())
192+
return
193+
}
194+
195+
result := modelFromTFEAzureOIDCConfiguration(oidc)
196+
resp.Diagnostics.Append(resp.State.Set(ctx, result)...)
197+
}
198+
199+
func (r *resourceTFEAzureOIDCConfiguration) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
200+
var state modelTFEAzureOIDCConfiguration
201+
diags := req.State.Get(ctx, &state)
202+
resp.Diagnostics.Append(diags...)
203+
if resp.Diagnostics.HasError() {
204+
return
205+
}
206+
207+
oidcID := state.ID.ValueString()
208+
tflog.Debug(ctx, fmt.Sprintf("Delete TFE Azure OIDC configuration: %s", oidcID))
209+
err := r.config.Client.AzureOIDCConfigurations.Delete(ctx, oidcID)
210+
if err != nil {
211+
if errors.Is(err, tfe.ErrResourceNotFound) {
212+
tflog.Debug(ctx, fmt.Sprintf("TFE Azure OIDC configuration %s no longer exists", oidcID))
213+
}
214+
215+
resp.Diagnostics.AddError("Error deleting TFE Azure OIDC Configuration", err.Error())
216+
return
217+
}
218+
}
219+
220+
func modelFromTFEAzureOIDCConfiguration(p *tfe.AzureOIDCConfiguration) modelTFEAzureOIDCConfiguration {
221+
return modelTFEAzureOIDCConfiguration{
222+
ID: types.StringValue(p.ID),
223+
ClientID: types.StringValue(p.ClientID),
224+
SubscriptionID: types.StringValue(p.SubscriptionID),
225+
TenantID: types.StringValue(p.TenantID),
226+
Organization: types.StringValue(p.Organization.Name),
227+
}
228+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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 TestAccTFEAzureOIDCConfiguration_basic(t *testing.T) {
13+
orgName := os.Getenv("HYOK_ORGANIZATION_NAME")
14+
15+
if orgName == "" {
16+
t.Skip("Test skipped: HYOK_ORGANIZATION_NAME environment variable is not set")
17+
}
18+
19+
originalClientID := "client-id-1"
20+
updatedClientID := "client-id-2"
21+
originalSubscriptionID := "subscription-id-1"
22+
updatedSubscriptionID := "subscription-id-2"
23+
originalTenantID := "tenant-id-1"
24+
updatedTenantID := "tenant-id-2"
25+
26+
resource.Test(t, resource.TestCase{
27+
PreCheck: func() { testAccPreCheck(t) },
28+
ProtoV5ProviderFactories: testAccMuxedProviders,
29+
CheckDestroy: testAccCheckTFEAzureOIDCConfigurationDestroy,
30+
Steps: []resource.TestStep{
31+
{
32+
Config: testAccTFEAzureOIDCConfigurationConfig(orgName, originalClientID, originalSubscriptionID, originalTenantID),
33+
Check: resource.ComposeAggregateTestCheckFunc(
34+
resource.TestCheckResourceAttrSet("tfe_azure_oidc_configuration.test", "id"),
35+
resource.TestCheckResourceAttr("tfe_azure_oidc_configuration.test", "client_id", originalClientID),
36+
resource.TestCheckResourceAttr("tfe_azure_oidc_configuration.test", "subscription_id", originalSubscriptionID),
37+
resource.TestCheckResourceAttr("tfe_azure_oidc_configuration.test", "tenant_id", originalTenantID),
38+
),
39+
},
40+
// Import
41+
{
42+
ResourceName: "tfe_azure_oidc_configuration.test",
43+
ImportState: true,
44+
ImportStateVerify: true,
45+
},
46+
// Update
47+
{
48+
Config: testAccTFEAzureOIDCConfigurationConfig(orgName, updatedClientID, updatedSubscriptionID, updatedTenantID),
49+
Check: resource.ComposeAggregateTestCheckFunc(
50+
resource.TestCheckResourceAttrSet("tfe_azure_oidc_configuration.test", "id"),
51+
resource.TestCheckResourceAttr("tfe_azure_oidc_configuration.test", "client_id", updatedClientID),
52+
resource.TestCheckResourceAttr("tfe_azure_oidc_configuration.test", "subscription_id", updatedSubscriptionID),
53+
resource.TestCheckResourceAttr("tfe_azure_oidc_configuration.test", "tenant_id", updatedTenantID),
54+
),
55+
},
56+
},
57+
})
58+
}
59+
60+
func testAccTFEAzureOIDCConfigurationConfig(orgName string, clientID string, subscriptionID string, tenantID string) string {
61+
return fmt.Sprintf(`
62+
resource "tfe_azure_oidc_configuration" "test" {
63+
client_id = "%s"
64+
subscription_id = "%s"
65+
tenant_id = "%s"
66+
organization = "%s"
67+
}
68+
`, clientID, subscriptionID, tenantID, orgName)
69+
}
70+
71+
func testAccCheckTFEAzureOIDCConfigurationDestroy(s *terraform.State) error {
72+
for _, rs := range s.RootModule().Resources {
73+
if rs.Type != "tfe_azure_oidc_configuration" {
74+
continue
75+
}
76+
77+
if rs.Primary.ID == "" {
78+
return fmt.Errorf("no instance ID is set")
79+
}
80+
81+
_, err := testAccConfiguredClient.Client.AzureOIDCConfigurations.Read(ctx, rs.Primary.ID)
82+
if err == nil {
83+
return fmt.Errorf("TFE Azure OIDC Configuration %s still exists", rs.Primary.ID)
84+
}
85+
}
86+
87+
return nil
88+
}

0 commit comments

Comments
 (0)