Skip to content

Commit

Permalink
Merge pull request #1038 from jfrog/GH-1034-fix-inconsistent-value-fo…
Browse files Browse the repository at this point in the history
…r-scoped-token

Fix 'ignore_missing_token_warning' value not being updated
  • Loading branch information
alexhung authored Jul 25, 2024
2 parents 53e46f3 + 7e968ae commit f18e061
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
BUG FIXES:

* resource/artifactory_group: Fix updating `name` attribute results in API error. Updating this attribute now will trigger a deletion and recreation of the resource. Issue: [#1035](https://github.com/jfrog/terraform-provider-artifactory/issues/1035) PR: [#1037](https://github.com/jfrog/terraform-provider-artifactory/pull/1037)
* resource/artifactory_scoped_token: Fix inconsistent value for `ignore_missing_token_warning` attribute when it is set. Issue: [#1034](https://github.com/jfrog/terraform-provider-artifactory/issues/1034) PR: [#1038](https://github.com/jfrog/terraform-provider-artifactory/pull/1038)

## 11.2.1 (July 22, 2024). Tested on Artifactory 7.84.17 with Terraform 1.9.2 and OpenTofu 1.7.3

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,16 +405,16 @@ func (r *ScopedTokenResource) Configure(ctx context.Context, req resource.Config
func (r *ScopedTokenResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
go util.SendUsageResourceCreate(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName)

var data *ScopedTokenResourceModel
var plan *ScopedTokenResourceModel
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

scopes := []string{}
if !data.Scopes.IsNull() {
scopes = utilfw.StringSetToStrings(data.Scopes)
if !plan.Scopes.IsNull() {
scopes = utilfw.StringSetToStrings(plan.Scopes)
}
scopesString := strings.Join(scopes, " ") // Join slice into space-separated string
if len(scopesString) > 500 {
Expand All @@ -426,8 +426,8 @@ func (r *ScopedTokenResource) Create(ctx context.Context, req resource.CreateReq
}

audiences := []string{}
if !data.Audiences.IsNull() {
audiences = utilfw.StringSetToStrings(data.Audiences)
if !plan.Audiences.IsNull() {
audiences = utilfw.StringSetToStrings(plan.Audiences)
}
audiencesString := strings.Join(audiences, " ") // Join slice into space-separated string
if len(audiencesString) > 255 {
Expand All @@ -440,15 +440,15 @@ func (r *ScopedTokenResource) Create(ctx context.Context, req resource.CreateReq

// Convert from Terraform data model into API data model
accessTokenPostBody := AccessTokenPostRequestAPIModel{
GrantType: data.GrantType.ValueString(),
Username: data.Username.ValueString(),
ProjectKey: data.ProjectKey.ValueString(),
GrantType: plan.GrantType.ValueString(),
Username: plan.Username.ValueString(),
ProjectKey: plan.ProjectKey.ValueString(),
Scope: scopesString,
ExpiresIn: data.ExpiresIn.ValueInt64(),
Refreshable: data.Refreshable.ValueBool(),
Description: data.Description.ValueString(),
ExpiresIn: plan.ExpiresIn.ValueInt64(),
Refreshable: plan.Refreshable.ValueBool(),
Description: plan.Description.ValueString(),
Audience: audiencesString,
IncludeReferenceToken: data.IncludeReferenceToken.ValueBool(),
IncludeReferenceToken: plan.IncludeReferenceToken.ValueBool(),
}

postResult := AccessTokenPostResponseAPIModel{}
Expand Down Expand Up @@ -504,21 +504,21 @@ func (r *ScopedTokenResource) Create(ctx context.Context, req resource.CreateReq
}

// Assign the attribute values for the resource in the state
resp.Diagnostics.Append(data.PostResponseToState(ctx, &postResult, &accessTokenPostBody, &getResult)...)
resp.Diagnostics.Append(plan.PostResponseToState(ctx, &postResult, &accessTokenPostBody, &getResult)...)
if resp.Diagnostics.HasError() {
return
}

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) // All attributes are assigned in data
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) // All attributes are assigned in data
}

func (r *ScopedTokenResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
go util.SendUsageResourceRead(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName)

var data *ScopedTokenResourceModel
var state *ScopedTokenResourceModel
// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
Expand All @@ -528,7 +528,7 @@ func (r *ScopedTokenResource) Read(ctx context.Context, req resource.ReadRequest

var artifactoryError artifactory.ArtifactoryErrorsResponse
response, err := r.ProviderData.Client.R().
SetPathParam("id", data.Id.ValueString()).
SetPathParam("id", state.Id.ValueString()).
SetResult(&accessToken).
SetError(&artifactoryError).
Get("access/api/v1/tokens/{id}")
Expand All @@ -541,9 +541,9 @@ func (r *ScopedTokenResource) Read(ctx context.Context, req resource.ReadRequest
}

if response.StatusCode() == http.StatusNotFound {
if !data.IgnoreMissingTokenWarning.ValueBool() {
if !state.IgnoreMissingTokenWarning.ValueBool() {
resp.Diagnostics.AddWarning(
fmt.Sprintf("Scoped token %s not found or not created", data.Id.ValueString()),
fmt.Sprintf("Scoped token %s not found or not created", state.Id.ValueString()),
"Access Token would not be saved by Artifactory if 'expires_in' is less than the persistence threshold value (default to 10800 seconds) set in Access configuration. See https://www.jfrog.com/confluence/display/JFROG/Access+Tokens#AccessTokens-PersistencyThreshold for details."+response.String(),
)
}
Expand All @@ -558,25 +558,38 @@ func (r *ScopedTokenResource) Read(ctx context.Context, req resource.ReadRequest

// Convert from the API data model to the Terraform data model
// and refresh any attribute values.
data.GetResponseToState(ctx, &accessToken)
state.GetResponseToState(ctx, &accessToken)

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}

func (r *ScopedTokenResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
// Scoped tokens are not updatable
go util.SendUsageResourceUpdate(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName)

var plan *ScopedTokenResourceModel
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

// Save data into Terraform state
//
// We only care about updating state for 'ignore_missing_token_warning' attribute
// All other attributes should trigger a recreation instead
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}

func (r *ScopedTokenResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
go util.SendUsageResourceDelete(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName)

var data ScopedTokenResourceModel
var state ScopedTokenResourceModel
respError := AccessTokenErrorResponseAPIModel{}

// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
id := data.Id.ValueString()
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
id := state.Id.ValueString()

response, err := r.ProviderData.Client.R().
SetPathParam("id", id).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,79 @@ func TestAccScopedToken_UpgradeGH_818(t *testing.T) {
})
}

func TestAccScopedToken_UpgradeToV1Schema(t *testing.T) {
_, fqrn, name := testutil.MkNames("test-scope-token", "artifactory_scoped_token")

_, _, username := testutil.MkNames("test-user", "artifactory_user")

config := util.ExecuteTemplate(
"TestAccScopedToken",
`resource "artifactory_user" "{{ .username }}" {
name = "{{ .username }}"
email = "{{ .username }}@tempurl.org"
admin = true
disable_ui_access = false
groups = ["readers"]
password = "Passw0rd!"
}
resource "artifactory_scoped_token" "{{ .name }}" {
scopes = ["applied-permissions/user"]
username = artifactory_user.{{ .username }}.name
}`,
map[string]interface{}{
"name": name,
"username": username,
},
)

updatedConfig := util.ExecuteTemplate(
"TestAccScopedToken",
`resource "artifactory_user" "{{ .username }}" {
name = "{{ .username }}"
email = "{{ .username }}@tempurl.org"
admin = true
disable_ui_access = false
groups = ["readers"]
password = "Passw0rd!"
}
resource "artifactory_scoped_token" "{{ .name }}" {
scopes = ["applied-permissions/user"]
username = artifactory_user.{{ .username }}.name
ignore_missing_token_warning = true
}`,
map[string]interface{}{
"name": name,
"username": username,
},
)

resource.Test(t, resource.TestCase{
Steps: []resource.TestStep{
{
ExternalProviders: map[string]resource.ExternalProvider{
"artifactory": {
Source: "jfrog/artifactory",
VersionConstraint: "11.1.0",
},
},
Config: config,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr(fqrn, "ignore_missing_token_warning"),
),
},
{
ProtoV6ProviderFactories: acctest.ProtoV6MuxProviderFactories,
Config: updatedConfig,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(fqrn, "ignore_missing_token_warning", "true"),
),
},
},
})
}

func scopedTokenUpgradeTestCase(version string, t *testing.T) (*testing.T, resource.TestCase) {
_, fqrn, name := testutil.MkNames("test-access-token", "artifactory_scoped_token")

Expand Down

0 comments on commit f18e061

Please sign in to comment.