Skip to content

Commit 635d4f6

Browse files
committed
New Resource for maxTTL
1 parent d0d6fdb commit 635d4f6

7 files changed

Lines changed: 1112 additions & 0 deletions
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// Copyright IBM Corp. 2018, 2025
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package provider
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
tfe "github.com/hashicorp/go-tfe"
11+
"github.com/hashicorp/terraform-plugin-framework/datasource"
12+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
13+
"github.com/hashicorp/terraform-plugin-framework/types"
14+
"github.com/hashicorp/terraform-plugin-log/tflog"
15+
)
16+
17+
var _ datasource.DataSource = &dataSourceTFEOrgMaxTokenTTLPolicy{}
18+
var _ datasource.DataSourceWithConfigure = &dataSourceTFEOrgMaxTokenTTLPolicy{}
19+
20+
func NewOrgMaxTokenTTLPolicyDataSource() datasource.DataSource {
21+
return &dataSourceTFEOrgMaxTokenTTLPolicy{}
22+
}
23+
24+
type dataSourceTFEOrgMaxTokenTTLPolicy struct {
25+
config ConfiguredClient
26+
}
27+
28+
type modelTFEOrgMaxTokenTTLPolicyData struct {
29+
Organization types.String `tfsdk:"organization"`
30+
Enabled types.Bool `tfsdk:"enabled"`
31+
OrgTokenMaxTTLMs types.Int64 `tfsdk:"org_token_max_ttl_ms"`
32+
TeamTokenMaxTTLMs types.Int64 `tfsdk:"team_token_max_ttl_ms"`
33+
AuditTrailTokenMaxTTLMs types.Int64 `tfsdk:"audit_trail_token_max_ttl_ms"`
34+
UserTokenMaxTTLMs types.Int64 `tfsdk:"user_token_max_ttl_ms"`
35+
}
36+
37+
func (d *dataSourceTFEOrgMaxTokenTTLPolicy) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
38+
resp.TypeName = req.ProviderTypeName + "_org_max_token_ttl_policy"
39+
}
40+
41+
func (d *dataSourceTFEOrgMaxTokenTTLPolicy) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
42+
resp.Schema = schema.Schema{
43+
Description: "Retrieves the maximum time-to-live (TTL) policy for API tokens in an organization. " +
44+
"This data source fetches the current TTL limits for organization, team, audit trail, " +
45+
"and user tokens from the database.",
46+
47+
Attributes: map[string]schema.Attribute{
48+
"organization": schema.StringAttribute{
49+
Description: "Name of the organization.",
50+
Required: true,
51+
},
52+
"enabled": schema.BoolAttribute{
53+
Description: "Indicates whether the maximum TTL token policy is enabled (true) or disabled (false) for the organization.",
54+
Computed: true,
55+
},
56+
"org_token_max_ttl_ms": schema.Int64Attribute{
57+
Description: "Maximum lifespan allowed for organization tokens in milliseconds.",
58+
Computed: true,
59+
},
60+
"team_token_max_ttl_ms": schema.Int64Attribute{
61+
Description: "Maximum lifespan allowed for team tokens in milliseconds.",
62+
Computed: true,
63+
},
64+
"audit_trail_token_max_ttl_ms": schema.Int64Attribute{
65+
Description: "Maximum lifespan allowed for audit trail tokens in milliseconds.",
66+
Computed: true,
67+
},
68+
"user_token_max_ttl_ms": schema.Int64Attribute{
69+
Description: "Maximum lifespan allowed for user tokens in milliseconds.",
70+
Computed: true,
71+
},
72+
},
73+
}
74+
}
75+
76+
func (d *dataSourceTFEOrgMaxTokenTTLPolicy) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
77+
if req.ProviderData == nil {
78+
return
79+
}
80+
81+
client, ok := req.ProviderData.(ConfiguredClient)
82+
if !ok {
83+
resp.Diagnostics.AddError(
84+
"Unexpected data source Configure type",
85+
fmt.Sprintf("Expected tfe.ConfiguredClient, got %T", req.ProviderData),
86+
)
87+
return
88+
}
89+
d.config = client
90+
}
91+
92+
func (d *dataSourceTFEOrgMaxTokenTTLPolicy) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
93+
var config modelTFEOrgMaxTokenTTLPolicyData
94+
95+
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
96+
if resp.Diagnostics.HasError() {
97+
return
98+
}
99+
100+
organization := config.Organization.ValueString()
101+
102+
tflog.Debug(ctx, fmt.Sprintf("Reading token TTL policies for organization: %s", organization))
103+
policyList, err := d.config.Client.OrganizationTokenTTLPolicies.List(ctx, organization, nil)
104+
if err != nil {
105+
resp.Diagnostics.AddError("Unable to read organization token TTL policies", err.Error())
106+
return
107+
}
108+
109+
// If no policies exist, treat as disabled with default values
110+
enabled := len(policyList.Items) > 0
111+
112+
// Convert the API response to the data source model
113+
result := modelFromTokenTTLPoliciesData(organization, enabled, policyList.Items)
114+
115+
resp.Diagnostics.Append(resp.State.Set(ctx, &result)...)
116+
}
117+
118+
func modelFromTokenTTLPoliciesData(organization string, enabled bool, policies []*tfe.OrganizationTokenTTLPolicy) modelTFEOrgMaxTokenTTLPolicyData {
119+
// Default TTL: 2 years in milliseconds
120+
defaultTTLMs := int64(63072000000000) // 2 years = 365 * 2 * 24 * 60 * 60 * 1000
121+
122+
result := modelTFEOrgMaxTokenTTLPolicyData{
123+
Organization: types.StringValue(organization),
124+
Enabled: types.BoolValue(enabled),
125+
OrgTokenMaxTTLMs: types.Int64Value(defaultTTLMs),
126+
TeamTokenMaxTTLMs: types.Int64Value(defaultTTLMs),
127+
AuditTrailTokenMaxTTLMs: types.Int64Value(defaultTTLMs),
128+
UserTokenMaxTTLMs: types.Int64Value(defaultTTLMs),
129+
}
130+
131+
// Set actual values from policies
132+
for _, policy := range policies {
133+
switch policy.TokenType {
134+
case tfe.TokenTypeOrganization:
135+
result.OrgTokenMaxTTLMs = types.Int64Value(policy.MaxTTLMs)
136+
case tfe.TokenTypeTeam:
137+
result.TeamTokenMaxTTLMs = types.Int64Value(policy.MaxTTLMs)
138+
case tfe.TokenTypeAuditTrails:
139+
result.AuditTrailTokenMaxTTLMs = types.Int64Value(policy.MaxTTLMs)
140+
case tfe.TokenTypeUser:
141+
result.UserTokenMaxTTLMs = types.Int64Value(policy.MaxTTLMs)
142+
}
143+
}
144+
145+
return result
146+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright IBM Corp. 2018, 2025
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package provider
5+
6+
import (
7+
"fmt"
8+
"math/rand"
9+
"testing"
10+
"time"
11+
12+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
13+
)
14+
15+
func TestAccTFEOrgMaxTokenTTLPolicyDataSource_basic(t *testing.T) {
16+
skipUnlessBeta(t)
17+
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
18+
orgName := fmt.Sprintf("tst-terraform-%d", rInt)
19+
20+
resource.Test(t, resource.TestCase{
21+
PreCheck: func() { testAccPreCheck(t) },
22+
ProtoV6ProviderFactories: testAccMuxedProviders,
23+
Steps: []resource.TestStep{
24+
{
25+
Config: testAccTFEOrgMaxTokenTTLPolicyDataSourceConfig_basic(orgName),
26+
Check: resource.ComposeAggregateTestCheckFunc(
27+
resource.TestCheckResourceAttr("data.tfe_org_max_token_ttl_policy.test", "organization", orgName),
28+
resource.TestCheckResourceAttrSet("data.tfe_org_max_token_ttl_policy.test", "enabled"),
29+
resource.TestCheckResourceAttrSet("data.tfe_org_max_token_ttl_policy.test", "org_token_max_ttl_ms"),
30+
resource.TestCheckResourceAttrSet("data.tfe_org_max_token_ttl_policy.test", "team_token_max_ttl_ms"),
31+
resource.TestCheckResourceAttrSet("data.tfe_org_max_token_ttl_policy.test", "audit_trail_token_max_ttl_ms"),
32+
resource.TestCheckResourceAttrSet("data.tfe_org_max_token_ttl_policy.test", "user_token_max_ttl_ms"),
33+
),
34+
},
35+
},
36+
})
37+
}
38+
39+
func TestAccTFEOrgMaxTokenTTLPolicyDataSource_withResource(t *testing.T) {
40+
skipUnlessBeta(t)
41+
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
42+
orgName := fmt.Sprintf("tst-terraform-%d", rInt)
43+
44+
resource.Test(t, resource.TestCase{
45+
PreCheck: func() { testAccPreCheck(t) },
46+
ProtoV6ProviderFactories: testAccMuxedProviders,
47+
Steps: []resource.TestStep{
48+
{
49+
Config: testAccTFEOrgMaxTokenTTLPolicyDataSourceConfig_withResource(orgName),
50+
Check: resource.ComposeAggregateTestCheckFunc(
51+
// Check resource
52+
resource.TestCheckResourceAttr("tfe_org_max_token_ttl_policy.test", "enabled", "true"),
53+
resource.TestCheckResourceAttr("tfe_org_max_token_ttl_policy.test", "org_token_max_ttl", "30d"),
54+
resource.TestCheckResourceAttr("tfe_org_max_token_ttl_policy.test", "team_token_max_ttl", "7d"),
55+
resource.TestCheckResourceAttr("tfe_org_max_token_ttl_policy.test", "user_token_max_ttl", "24h"),
56+
resource.TestCheckResourceAttr("tfe_org_max_token_ttl_policy.test", "audit_trail_token_max_ttl", "90d"),
57+
// Check data source returns milliseconds
58+
resource.TestCheckResourceAttr("data.tfe_org_max_token_ttl_policy.test", "enabled", "true"),
59+
resource.TestCheckResourceAttr("data.tfe_org_max_token_ttl_policy.test", "org_token_max_ttl_ms", "2592000000"), // 30 days
60+
resource.TestCheckResourceAttr("data.tfe_org_max_token_ttl_policy.test", "team_token_max_ttl_ms", "604800000"), // 7 days
61+
resource.TestCheckResourceAttr("data.tfe_org_max_token_ttl_policy.test", "user_token_max_ttl_ms", "86400000"), // 24 hours
62+
resource.TestCheckResourceAttr("data.tfe_org_max_token_ttl_policy.test", "audit_trail_token_max_ttl_ms", "7776000000"), // 90 days
63+
),
64+
},
65+
},
66+
})
67+
}
68+
69+
func testAccTFEOrgMaxTokenTTLPolicyDataSourceConfig_basic(orgName string) string {
70+
return fmt.Sprintf(`
71+
resource "tfe_organization" "test" {
72+
name = "%s"
73+
}
74+
75+
data "tfe_org_max_token_ttl_policy" "test" {
76+
organization = tfe_organization.test.name
77+
}
78+
`, orgName)
79+
}
80+
81+
func testAccTFEOrgMaxTokenTTLPolicyDataSourceConfig_withResource(orgName string) string {
82+
return fmt.Sprintf(`
83+
resource "tfe_organization" "test" {
84+
name = "%s"
85+
}
86+
87+
resource "tfe_org_max_token_ttl_policy" "test" {
88+
organization = tfe_organization.test.name
89+
enabled = true
90+
org_token_max_ttl = "30d"
91+
team_token_max_ttl = "7d"
92+
user_token_max_ttl = "24h"
93+
audit_trail_token_max_ttl = "90d"
94+
}
95+
96+
data "tfe_org_max_token_ttl_policy" "test" {
97+
organization = tfe_org_max_token_ttl_policy.test.organization
98+
depends_on = [tfe_org_max_token_ttl_policy.test]
99+
}
100+
`, orgName)
101+
}

internal/provider/provider_next.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ func (p *frameworkProvider) DataSources(ctx context.Context) []func() datasource
146146
NewHYOKCustomerKeyVersionDataSource,
147147
NewHYOKEncryptedDataKeyDataSource,
148148
NewNoCodeModuleDataSource,
149+
NewOrgMaxTokenTTLPolicyDataSource,
149150
NewOrganizationAuditConfigurationDataSource,
150151
NewOrganizationRunTaskDataSource,
151152
NewOrganizationRunTaskGlobalSettingsDataSource,
@@ -167,6 +168,7 @@ func (p *frameworkProvider) Resources(ctx context.Context) []func() resource.Res
167168
return []func() resource.Resource{
168169
NewAuditTrailTokenResource,
169170
NewDataRetentionPolicyResource,
171+
NewOrgMaxTokenTTLPolicyResource,
170172
NewOrganizationDefaultSettings,
171173
NewOrganizationRunTaskGlobalSettingsResource,
172174
NewOrganizationRunTaskResource,

0 commit comments

Comments
 (0)