Skip to content

Commit dc5eeb8

Browse files
committed
add an ephemeral resource for tfe_audit_trail_token
1 parent 797d0ae commit dc5eeb8

File tree

5 files changed

+295
-0
lines changed

5 files changed

+295
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
FEATURES:
44

5+
* **New Ephemeral Resource:** `tfe_audit_trail_token` is a new ephemeral
6+
resource for creating and managing audit trail tokens, by
7+
@uturunku1 [#1675](https://github.com/hashicorp/terraform-provider-tfe/pull/1675)
8+
59
* **New Ephemeral Resource:** `tfe_organization_token` is a new ephemeral
610
resource for creating and managing organization tokens, by
711
@ctrombley [#1616](https://github.com/hashicorp/terraform-provider-tfe/pull/1616)
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright (c) HashiCorp, Inc.
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-timetypes/timetypes"
12+
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
13+
"github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
14+
"github.com/hashicorp/terraform-plugin-framework/types"
15+
"github.com/hashicorp/terraform-plugin-log/tflog"
16+
)
17+
18+
var (
19+
_ ephemeral.EphemeralResource = &AuditTrailTokenEphemeralResource{}
20+
_ ephemeral.EphemeralResourceWithConfigure = &AuditTrailTokenEphemeralResource{}
21+
)
22+
23+
func NewAuditTrailTokenEphemeralResource() ephemeral.EphemeralResource {
24+
return &AuditTrailTokenEphemeralResource{}
25+
}
26+
27+
type AuditTrailTokenEphemeralResource struct {
28+
config ConfiguredClient
29+
}
30+
31+
type AuditTrailTokenEphemeralResourceModel struct {
32+
Organization types.String `tfsdk:"organization"`
33+
Token types.String `tfsdk:"token"`
34+
ExpiredAt timetypes.RFC3339 `tfsdk:"expired_at"`
35+
}
36+
37+
func (e *AuditTrailTokenEphemeralResource) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) {
38+
resp.Schema = schema.Schema{
39+
Description: "This ephemeral resource can be used to retrieve an audit trail token without saving its value in state. Using this ephemeral resource will generate a new token each time it is used, invalidating any existing audit trail token.",
40+
Attributes: map[string]schema.Attribute{
41+
"organization": schema.StringAttribute{
42+
Description: `Name of the organization. If omitted, organization must be defined in the provider config.`,
43+
Optional: true,
44+
Computed: true,
45+
},
46+
"token": schema.StringAttribute{
47+
Description: `The generated token.`,
48+
Computed: true,
49+
Sensitive: true,
50+
},
51+
"expired_at": schema.StringAttribute{
52+
Description: `The token's expiration date. The expiration date must be a date/time string in RFC3339 format (e.g., "2024-12-31T23:59:59Z"). If no expiration date is supplied, the expiration date will default to null and never expire.`,
53+
Optional: true,
54+
CustomType: timetypes.RFC3339Type{},
55+
},
56+
},
57+
}
58+
}
59+
60+
// Configure adds the provider configured client to the data source.
61+
func (e *AuditTrailTokenEphemeralResource) Configure(_ context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) {
62+
if req.ProviderData == nil {
63+
return
64+
}
65+
66+
client, ok := req.ProviderData.(ConfiguredClient)
67+
if !ok {
68+
resp.Diagnostics.AddError(
69+
"Unexpected Ephemeral Resource Configure Type",
70+
fmt.Sprintf("Expected tfe.ConfiguredClient, got %T. This is a bug in the tfe provider, so please report it on GitHub.", req.ProviderData),
71+
)
72+
73+
return
74+
}
75+
76+
e.config = client
77+
}
78+
79+
func (e *AuditTrailTokenEphemeralResource) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) {
80+
resp.TypeName = req.ProviderTypeName + "_audit_trail_token"
81+
}
82+
83+
func (e *AuditTrailTokenEphemeralResource) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
84+
// Read Terraform config
85+
var config AuditTrailTokenEphemeralResourceModel
86+
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
87+
if resp.Diagnostics.HasError() {
88+
return
89+
}
90+
91+
// Get org name or default
92+
var orgName string
93+
resp.Diagnostics.Append(e.config.dataOrDefaultOrganization(ctx, req.Config, &orgName)...)
94+
if resp.Diagnostics.HasError() {
95+
return
96+
}
97+
98+
// Create options struct
99+
tokenType := tfe.AuditTrailToken // "audit_trail"
100+
opts := tfe.OrganizationTokenCreateOptions{
101+
TokenType: &tokenType,
102+
}
103+
104+
if !config.ExpiredAt.IsNull() {
105+
expiredAt, diags := config.ExpiredAt.ValueRFC3339Time()
106+
if diags.HasError() {
107+
resp.Diagnostics.Append(diags...)
108+
return
109+
}
110+
111+
opts.ExpiredAt = &expiredAt
112+
}
113+
114+
tflog.Debug(ctx, fmt.Sprintf("Creating audit trail token for organization %s", orgName))
115+
result, err := e.config.Client.OrganizationTokens.CreateWithOptions(ctx, orgName, opts)
116+
if err != nil {
117+
resp.Diagnostics.AddError("Unable to create organization audit trail token", err.Error())
118+
return
119+
}
120+
121+
// Set the token in the model
122+
config.Token = types.StringValue(result.Token)
123+
124+
// Write the data back to the ephemeral resource
125+
resp.Diagnostics.Append(resp.Result.Set(ctx, &config)...)
126+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright (c) HashiCorp, Inc.
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-go/tfprotov6"
13+
"github.com/hashicorp/terraform-plugin-testing/echoprovider"
14+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
15+
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
16+
"github.com/hashicorp/terraform-plugin-testing/statecheck"
17+
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
18+
"github.com/hashicorp/terraform-plugin-testing/tfversion"
19+
)
20+
21+
func TestAccAuditTrailTokenEphemeralResource_basic(t *testing.T) {
22+
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
23+
orgName := fmt.Sprintf("tst-terraform-%d", rInt)
24+
25+
resource.Test(t, resource.TestCase{
26+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
27+
tfversion.SkipBelow(tfversion.Version1_10_0),
28+
},
29+
PreCheck: func() { testAccPreCheck(t) },
30+
ProtoV5ProviderFactories: testAccMuxedProviders,
31+
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
32+
"echo": echoprovider.NewProviderServer(),
33+
},
34+
Steps: []resource.TestStep{
35+
{
36+
Config: testAccAuditTrailTokenEphemeralResourceConfig_basic(rInt),
37+
ConfigStateChecks: []statecheck.StateCheck{
38+
statecheck.ExpectKnownValue("echo.this", tfjsonpath.New("data").AtMapKey("organization"), knownvalue.StringExact(orgName)),
39+
},
40+
},
41+
},
42+
})
43+
}
44+
45+
func TestAccAuditTrailTokenEphemeralResource_expiredAt(t *testing.T) {
46+
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
47+
48+
resource.Test(t, resource.TestCase{
49+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
50+
tfversion.SkipBelow(tfversion.Version1_10_0),
51+
},
52+
PreCheck: func() { testAccPreCheck(t) },
53+
ProtoV5ProviderFactories: testAccMuxedProviders,
54+
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
55+
"echo": echoprovider.NewProviderServer(),
56+
},
57+
Steps: []resource.TestStep{
58+
{
59+
Config: testAccAuditTrailTokenEphemeralResourceConfig_expiredAt(rInt),
60+
ConfigStateChecks: []statecheck.StateCheck{
61+
statecheck.ExpectKnownValue("echo.this", tfjsonpath.New("data").AtMapKey("expired_at"), knownvalue.StringExact("2100-01-01T00:00:00Z")),
62+
},
63+
},
64+
},
65+
})
66+
}
67+
68+
func testAccAuditTrailTokenEphemeralResourceConfig_basic(rInt int) string {
69+
return fmt.Sprintf(`
70+
resource "tfe_organization" "this" {
71+
name = "tst-terraform-%d"
72+
73+
}
74+
75+
ephemeral "tfe_audit_trail_token" "this" {
76+
organization = tfe_organization.this.id
77+
}
78+
79+
provider "echo" {
80+
data = ephemeral.tfe_audit_trail_token.this
81+
}
82+
83+
resource "echo" "this" {}
84+
`, rInt)
85+
}
86+
87+
func testAccAuditTrailTokenEphemeralResourceConfig_expiredAt(rInt int) string {
88+
return fmt.Sprintf(`
89+
resource "tfe_organization" "this" {
90+
name = "tst-terraform-%d"
91+
92+
}
93+
94+
ephemeral "tfe_audit_trail_token" "this" {
95+
organization = tfe_organization.this.id
96+
expired_at = "2100-01-01T00:00:00Z"
97+
}
98+
99+
provider "echo" {
100+
data = ephemeral.tfe_audit_trail_token.this
101+
}
102+
103+
resource "echo" "this" {}
104+
`, rInt)
105+
}

internal/provider/provider_next.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,5 +174,6 @@ func (p *frameworkProvider) EphemeralResources(ctx context.Context) []func() eph
174174
NewOrganizationTokenEphemeralResource,
175175
NewOutputsEphemeralResource,
176176
NewTeamTokenEphemeralResource,
177+
NewAuditTrailTokenEphemeralResource,
177178
}
178179
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
layout: "tfe"
3+
page_title: "Terraform Enterprise: Ephemeral: tfe_audit_trail_token"
4+
description: |-
5+
Generates a new audit trail token that is guaranteed not to be written to
6+
state.
7+
---
8+
9+
# Ephemeral: tfe_audit_trail_token
10+
11+
Terraform ephemeral resource for managing a TFE audit trail token. This
12+
resource is used to generate a new audit trail token that is guaranteed not to
13+
be written to state. Since audit trail tokens are singleton resources, using this ephemeral resource will replace any existing audit trail token, including those managed by `tfe_audit_trail_token`.
14+
15+
~> **NOTE:** Ephemeral resources are a new feature and may evolve as we continue to explore their most effective uses. [Learn more](https://developer.hashicorp.com/terraform/language/v1.10.x/resources/ephemeral).
16+
17+
## Example Usage
18+
19+
### Generate a new audit trail token:
20+
21+
This will invalidate any existing audit trail token.
22+
23+
```hcl
24+
ephemeral "tfe_audit_trail_token" "example" {
25+
organization = "my-org-name"
26+
}
27+
```
28+
29+
### Generate a new audit trail token with 30 day expiration:
30+
31+
This will invalidate any existing audit trail token.
32+
33+
```hcl
34+
resource "time_rotating" "example" {
35+
rotation_days = 30
36+
}
37+
38+
ephemeral "tfe_audit_trail_token" "example" {
39+
organization = "my-org-name"
40+
expired_at = time_rotating.example.rotation_rfc3339
41+
}
42+
```
43+
44+
## Argument Reference
45+
46+
The following arguments are required:
47+
48+
* `organization` - (Optional) Name of the organization. If omitted, organization must be defined in the provider config.
49+
50+
The following arguments are optional:
51+
52+
* `expired_at` - (Optional) The token's expiration date. The expiration date must be a date/time string in RFC3339
53+
format (e.g., "2024-12-31T23:59:59Z"). If no expiration date is supplied, the expiration date will default to null and
54+
never expire.
55+
56+
This ephemeral resource exports the following attributes in addition to the arguments above:
57+
58+
* `token` - The generated token. This value is sensitive and will not be stored
59+
in state.

0 commit comments

Comments
 (0)