Skip to content

Commit 9e2a8e1

Browse files
committed
WIP: fixes
1 parent b0f407e commit 9e2a8e1

File tree

3 files changed

+123
-12
lines changed

3 files changed

+123
-12
lines changed

internal/resources/cloud/resource_cloud_access_policy_rotating_token.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ var (
2424
emptyTokenRotationValueError = errors.New("empty value for required field")
2525
)
2626

27-
// TODO: Test importing existing tokens
2827
func resourceAccessPolicyRotatingToken() *common.Resource {
2928
schema := &schema.Resource{
3029

@@ -203,10 +202,25 @@ func getRotatingTokenRotateAfter(d getter) (*time.Time, error) {
203202
}
204203

205204
func computeRotatingTokenName(d getter) (string, error) {
205+
namePrefix := d.Get("name_prefix").(string)
206+
if namePrefix == "" {
207+
return "", emptyTokenRotationValueError
208+
}
209+
210+
postRotationLifetime := d.Get("post_rotation_lifetime").(string)
211+
if postRotationLifetime == "" {
212+
return "", emptyTokenRotationValueError
213+
}
214+
215+
rotateAfterInt, ok := d.Get("rotate_after").(int)
216+
if !ok || rotateAfterInt == 0 {
217+
return "", emptyTokenRotationValueError
218+
}
219+
206220
attrs := rotatingTokenNameAttributes{
207-
namePrefix: d.Get("name_prefix").(string),
208-
postRotationLifetime: d.Get("post_rotation_lifetime").(string),
209-
rotateAfter: d.Get("rotate_after").(int),
221+
namePrefix: namePrefix,
222+
postRotationLifetime: postRotationLifetime,
223+
rotateAfter: rotateAfterInt,
210224
}
211225

212226
return attrs.computedName(), nil

internal/resources/cloud/resource_cloud_access_policy_rotating_token_test.go

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/grafana/grafana-com-public-clients/go/gcom"
1313
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
1414
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
15+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
1516

1617
"github.com/grafana/terraform-provider-grafana/v4/internal/common"
1718
"github.com/grafana/terraform-provider-grafana/v4/internal/testutils"
@@ -24,21 +25,22 @@ func TestResourceAccessPolicyRotatingToken_Basic(t *testing.T) {
2425

2526
var policy gcom.AuthAccessPolicy
2627
var policyToken gcom.AuthToken
28+
var policyToken2 gcom.AuthToken
2729

28-
// Set up rotation parameters
2930
rotateAfter := time.Now().Add(time.Hour * 2).UTC()
31+
updatedRotateAfter := time.Now().Add(time.Hour * 4).UTC()
3032
postRotationLifetime := "24h"
31-
namePrefix := "test-rotating"
33+
namePrefix := "test-rotating-token-terraform"
3234
expectedExpiresAt := rotateAfter.Add(24 * time.Hour).Format(time.RFC3339)
3335
expectedName := fmt.Sprintf("%s-%d-%s", namePrefix, rotateAfter.Unix(), postRotationLifetime)
34-
35-
accessPolicyName := fmt.Sprintf("initial-%s", acctest.RandStringFromCharSet(6, acctest.CharSetAlpha))
36+
accessPolicyName := fmt.Sprintf("test-rotating-token-terraform-initial-%s", acctest.RandStringFromCharSet(6, acctest.CharSetAlpha))
3637

3738
resource.Test(t, resource.TestCase{
3839
ProtoV5ProviderFactories: testutils.ProtoV5ProviderFactories,
3940
CheckDestroy: resource.ComposeTestCheckFunc(
4041
testAccCloudAccessPolicyCheckDestroy("prod-us-east-0", &policy),
4142
testAccCloudAccessPolicyTokenCheckDestroy("prod-us-east-0", &policyToken),
43+
testAccCloudAccessPolicyTokenCheckDestroy("prod-us-east-0", &policyToken2),
4244
),
4345
Steps: []resource.TestStep{
4446
// Test that the cloud access policy and rotating token get created
@@ -52,7 +54,7 @@ func TestResourceAccessPolicyRotatingToken_Basic(t *testing.T) {
5254
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "name", expectedName),
5355
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "expires_at", expectedExpiresAt),
5456
// Input fields
55-
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "name_prefix", "test-rotating"),
57+
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "name_prefix", namePrefix),
5658
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "rotate_after", strconv.FormatInt(rotateAfter.Unix(), 10)),
5759
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "post_rotation_lifetime", postRotationLifetime),
5860
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "region", "prod-us-east-0"),
@@ -71,7 +73,7 @@ func TestResourceAccessPolicyRotatingToken_Basic(t *testing.T) {
7173
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "name", expectedName),
7274
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "expires_at", expectedExpiresAt),
7375
// Input fields
74-
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "name_prefix", "test-rotating"),
76+
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "name_prefix", namePrefix),
7577
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "rotate_after", strconv.FormatInt(rotateAfter.Unix(), 10)),
7678
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "post_rotation_lifetime", postRotationLifetime),
7779
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "region", "prod-us-east-0"),
@@ -109,6 +111,54 @@ func TestResourceAccessPolicyRotatingToken_Basic(t *testing.T) {
109111
ImportStateVerify: true,
110112
ImportStateVerifyIgnore: []string{"token"},
111113
},
114+
// Test rotation time change should force recreation
115+
{
116+
Config: testAccCloudAccessPolicyRotatingTokenConfigBasic(accessPolicyName, "", "prod-us-east-0", namePrefix, updatedRotateAfter.Unix(), postRotationLifetime),
117+
Check: resource.ComposeTestCheckFunc(
118+
testAccCloudAccessPolicyCheckExists("grafana_cloud_access_policy.rotating_token_test", &policy),
119+
testAccCloudAccessPolicyTokenCheckExists("grafana_cloud_access_policy_rotating_token.test", &policyToken2),
120+
resource.TestCheckResourceAttr("grafana_cloud_access_policy_rotating_token.test", "rotate_after", strconv.Itoa(int(updatedRotateAfter.Unix()))),
121+
// Verify the token ID changed (indicating recreation)
122+
func(s *terraform.State) error {
123+
if policyToken.Id == nil || policyToken2.Id == nil {
124+
return fmt.Errorf("expected token to be recreated, but ID is nil")
125+
}
126+
if *policyToken.Id == *policyToken2.Id {
127+
return fmt.Errorf("expected token to be recreated, but ID remained the same: %s", *policyToken.Id)
128+
}
129+
return nil
130+
},
131+
),
132+
},
133+
// Test import with different values in config vs what is inferred from the name
134+
{
135+
Config: testAccCloudAccessPolicyRotatingTokenConfigMismatch(accessPolicyName, "", "prod-us-east-0", "different-prefix", time.Now().Add(time.Hour*6).Unix(), "12h"),
136+
ResourceName: "grafana_cloud_access_policy_rotating_token.test",
137+
ImportState: true,
138+
ImportStateVerify: false, // We expect this to fail verification
139+
ImportStateCheck: func(s []*terraform.InstanceState) error {
140+
if len(s) != 1 {
141+
return fmt.Errorf("expected 1 state, got %d", len(s))
142+
}
143+
144+
state := s[0]
145+
146+
// Verify that imported values come from the token name in Grafana Cloud, not the Terraform state we had
147+
if state.Attributes["name_prefix"] != namePrefix {
148+
return fmt.Errorf("expected name_prefix to be inferred as %s from token name, got %s", namePrefix, state.Attributes["name_prefix"])
149+
}
150+
151+
if state.Attributes["rotate_after"] != strconv.Itoa(int(updatedRotateAfter.Unix())) {
152+
return fmt.Errorf("expected rotate_after to be inferred as %s from token name, got %s", strconv.Itoa(int(updatedRotateAfter.Unix())), state.Attributes["rotate_after"])
153+
}
154+
155+
if state.Attributes["post_rotation_lifetime"] != postRotationLifetime {
156+
return fmt.Errorf("expected post_rotation_lifetime to be inferred as %s from token name, got %s", postRotationLifetime, state.Attributes["post_rotation_lifetime"])
157+
}
158+
159+
return nil
160+
},
161+
},
112162
// Test that destroy does not actually delete the token (it should only show a warning instead)
113163
{
114164
Config: testAccCloudAccessPolicyRotatingTokenConfigBasic(accessPolicyName, "", "prod-us-east-0", "test-no-delete", rotateAfter.Unix(), postRotationLifetime),
@@ -166,3 +216,50 @@ func testAccCloudAccessPolicyRotatingTokenConfigBasic(name, displayName, region
166216
}
167217
`, name, displayName, strings.Join(scopes, `","`), os.Getenv("GRAFANA_CLOUD_ORG"), namePrefix, rotateAfter, region, postRotationLifetime)
168218
}
219+
220+
func testAccCloudAccessPolicyRotatingTokenConfigMismatch(name, displayName, region string, namePrefix string, rotateAfter int64, postRotationLifetime string) string {
221+
if displayName != "" {
222+
displayName = fmt.Sprintf("display_name = \"%s\"", displayName)
223+
}
224+
225+
scopes := []string{
226+
"metrics:read",
227+
"logs:write",
228+
"accesspolicies:read",
229+
"accesspolicies:write",
230+
"accesspolicies:delete",
231+
"datadog:validate",
232+
}
233+
234+
return fmt.Sprintf(`
235+
data "grafana_cloud_organization" "current" {
236+
slug = "%[4]s"
237+
}
238+
239+
resource "grafana_cloud_access_policy" "rotating_token_test" {
240+
region = "%[7]s"
241+
name = "%[1]s"
242+
%[2]s
243+
244+
scopes = ["%[3]s"]
245+
246+
realm {
247+
type = "org"
248+
identifier = data.grafana_cloud_organization.current.id
249+
250+
label_policy {
251+
selector = "{namespace=\"default\"}"
252+
}
253+
}
254+
}
255+
256+
resource "grafana_cloud_access_policy_rotating_token" "test" {
257+
region = "%[7]s"
258+
access_policy_id = grafana_cloud_access_policy.rotating_token_test.policy_id
259+
name_prefix = "%[5]s"
260+
rotate_after = "%[6]d"
261+
post_rotation_lifetime = "%[8]s"
262+
%[2]s
263+
}
264+
`, name, displayName, strings.Join(scopes, `","`), os.Getenv("GRAFANA_CLOUD_ORG"), namePrefix, rotateAfter, region, postRotationLifetime)
265+
}

internal/resources/cloud/resource_cloud_access_policy_token_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ func testAccCloudAccessPolicyTokenCheckExists(rn string, a *gcom.AuthToken) reso
221221

222222
func testAccCloudAccessPolicyCheckDestroy(region string, a *gcom.AuthAccessPolicy) resource.TestCheckFunc {
223223
return func(s *terraform.State) error {
224-
if a == nil {
224+
if a == nil || a.Id == nil {
225225
return nil
226226
}
227227
client := testutils.Provider.Meta().(*common.Client).GrafanaCloudAPI
@@ -236,7 +236,7 @@ func testAccCloudAccessPolicyCheckDestroy(region string, a *gcom.AuthAccessPolic
236236

237237
func testAccCloudAccessPolicyTokenCheckDestroy(region string, a *gcom.AuthToken) resource.TestCheckFunc {
238238
return func(s *terraform.State) error {
239-
if a == nil {
239+
if a == nil || a.Id == nil {
240240
return nil
241241
}
242242
client := testutils.Provider.Meta().(*common.Client).GrafanaCloudAPI

0 commit comments

Comments
 (0)