diff --git a/CHANGELOG.md b/CHANGELOG.md index 726ccc3ed..ec7e69ca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v0.7.1 February 29th, 2024 +### BUG FIXES +* `pingfederate_oauth_access_token_manager` resource `attribute_contract.extended_attributes` Provider produced inconsistent result after apply ([#202](https://github.com/pingidentity/terraform-provider-pingfederate/pull/202)) + # v0.7.0 February 28th, 2024 ### DEPRECATED * `location` property in `resourceLink` object types for all Resources and DataSources. This property will be removed in a future release. ([#195](https://github.com/pingidentity/terraform-provider-pingfederate/pull/195)) diff --git a/docs/resources/oauth_access_token_manager.md b/docs/resources/oauth_access_token_manager.md index c67332232..3f463703d 100644 --- a/docs/resources/oauth_access_token_manager.md +++ b/docs/resources/oauth_access_token_manager.md @@ -273,7 +273,7 @@ resource "pingfederate_oauth_access_token_manager" "jsonWebTokenOauthAccessToken Required: -- `extended_attributes` (Attributes List) A list of additional token attributes that are associated with this access token management plugin instance. (see [below for nested schema](#nestedatt--attribute_contract--extended_attributes)) +- `extended_attributes` (Attributes Set) A list of additional token attributes that are associated with this access token management plugin instance. (see [below for nested schema](#nestedatt--attribute_contract--extended_attributes)) Optional: @@ -282,7 +282,7 @@ Optional: Read-Only: -- `core_attributes` (Attributes List) A list of core token attributes that are associated with the access token management plugin type. This field is read-only and is ignored on POST/PUT. (see [below for nested schema](#nestedatt--attribute_contract--core_attributes)) +- `core_attributes` (Attributes Set) A list of core token attributes that are associated with the access token management plugin type. This field is read-only and is ignored on POST/PUT. (see [below for nested schema](#nestedatt--attribute_contract--core_attributes)) ### Nested Schema for `attribute_contract.extended_attributes` diff --git a/internal/acctest/config/oauth/accesstokenmanager/json_web_oauth_access_token_manager_test.go b/internal/acctest/config/oauth/accesstokenmanager/json_web_oauth_access_token_manager_test.go index 24f980d18..5367ac9ae 100644 --- a/internal/acctest/config/oauth/accesstokenmanager/json_web_oauth_access_token_manager_test.go +++ b/internal/acctest/config/oauth/accesstokenmanager/json_web_oauth_access_token_manager_test.go @@ -32,6 +32,7 @@ type jsonWebTokenOauthAccessTokenManagerResourceModel struct { func TestAccJsonWebTokenOauthAccessTokenManager(t *testing.T) { resourceName := "myJsonWebTokenOauthAccessTokenManager" + initialResourceModel := jsonWebTokenOauthAccessTokenManagerResourceModel{ id: jsonWebTokenOauthAccessTokenManagerId, name: jsonWebTokenOauthAccessTokenManagerName, @@ -323,6 +324,26 @@ resource "pingfederate_oauth_access_token_manager" "%[1]s" { { name = "contract" multi_valued = false + }, + { + name = "contract1" + multi_valued = false + }, + { + name = "contract2" + multi_valued = false + }, + { + name = "contract3" + multi_valued = false + }, + { + name = "contract4" + multi_valued = false + }, + { + name = "contract5" + multi_valued = false } ] } @@ -364,14 +385,6 @@ func testAccCheckExpectedJsonWebOauthAccessTokenManagerAttributes(config jsonWeb return err } - // Check for the always-defined extended attribute - for _, extendedAttr := range response.AttributeContract.ExtendedAttributes { - err = acctest.TestAttributesMatchString(resourceType, &config.id, "extended_attribute.name", "contract", extendedAttr.Name) - if err != nil { - return err - } - } - // Verify that attributes have expected values getTables := response.Configuration.Tables for _, table := range getTables { diff --git a/internal/resource/config/oauth/accesstokenmanager/oauth_access_token_manager_resource.go b/internal/resource/config/oauth/accesstokenmanager/oauth_access_token_manager_resource.go index 877251779..b32e1c9f5 100644 --- a/internal/resource/config/oauth/accesstokenmanager/oauth_access_token_manager_resource.go +++ b/internal/resource/config/oauth/accesstokenmanager/oauth_access_token_manager_resource.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" @@ -13,10 +14,11 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" client "github.com/pingidentity/pingfederate-go-client/v1200/configurationapi" internaljson "github.com/pingidentity/terraform-provider-pingfederate/internal/json" @@ -41,8 +43,8 @@ var ( } attributeContractTypes = map[string]attr.Type{ - "core_attributes": types.ListType{ElemType: types.ObjectType{AttrTypes: attrType}}, - "extended_attributes": types.ListType{ElemType: types.ObjectType{AttrTypes: attrType}}, + "core_attributes": types.SetType{ElemType: types.ObjectType{AttrTypes: attrType}}, + "extended_attributes": types.SetType{ElemType: types.ObjectType{AttrTypes: attrType}}, "inherited": types.BoolType, "default_subject_attribute": types.StringType, } @@ -144,12 +146,12 @@ func oauthAccessTokenManagerResourceSchema(ctx context.Context, req resource.Sch Description: "The list of attributes that will be added to an access token.", Required: true, Attributes: map[string]schema.Attribute{ - "core_attributes": schema.ListNestedAttribute{ + "core_attributes": schema.SetNestedAttribute{ Description: "A list of core token attributes that are associated with the access token management plugin type. This field is read-only and is ignored on POST/PUT.", Computed: true, Optional: false, - PlanModifiers: []planmodifier.List{ - listplanmodifier.UseStateForUnknown(), + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ @@ -172,9 +174,12 @@ func oauthAccessTokenManagerResourceSchema(ctx context.Context, req resource.Sch }, }, }, - "extended_attributes": schema.ListNestedAttribute{ + "extended_attributes": schema.SetNestedAttribute{ Description: "A list of additional token attributes that are associated with this access token management plugin instance.", Required: true, + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "name": schema.StringAttribute{ @@ -313,20 +318,7 @@ func oauthAccessTokenManagerResourceSchema(ctx context.Context, req resource.Sch resp.Schema = schema } -func (r *oauthAccessTokenManagerResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - var model oauthAccessTokenManagerResourceModel - resp.Diagnostics.Append(req.Config.Get(ctx, &model)...) - - if internaltypes.IsDefined(model.AttributeContract) { - extendedAttributes := model.AttributeContract.Attributes()["extended_attributes"].(types.List) - if internaltypes.IsDefined(extendedAttributes) && len(extendedAttributes.Elements()) == 0 { - resp.Diagnostics.AddError("Empty attribute_contract.extended_attributes", "Please provide valid properties within attribute_contract.extended_attributes. The set cannot be empty if defined.") - } - } -} - func addOptionalOauthAccessTokenManagerFields(ctx context.Context, addRequest *client.AccessTokenManager, plan oauthAccessTokenManagerResourceModel) error { - if internaltypes.IsDefined(plan.ParentRef) { if plan.ParentRef.Attributes()["id"].(types.String).ValueString() != "" { addRequest.ParentRef = client.NewResourceLinkWithDefaults() @@ -438,7 +430,7 @@ func readOauthAccessTokenManagerResponse(ctx context.Context, r *client.AccessTo coreAttribute.MultiValued = ca.MultiValued coreAttrs = append(coreAttrs, coreAttribute) } - attributeContractCoreAttributes, respDiags := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: attrType}, coreAttrs) + attributeContractCoreAttributes, respDiags := types.SetValueFrom(ctx, types.ObjectType{AttrTypes: attrType}, coreAttrs) diags.Append(respDiags...) // state.AttributeContract extended_attributes @@ -450,7 +442,7 @@ func readOauthAccessTokenManagerResponse(ctx context.Context, r *client.AccessTo extendedAttr.MultiValued = ea.MultiValued extdAttrs = append(extdAttrs, extendedAttr) } - attributeContractExtendedAttributes, respDiags := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: attrType}, extdAttrs) + attributeContractExtendedAttributes, respDiags := types.SetValueFrom(ctx, types.ObjectType{AttrTypes: attrType}, extdAttrs) diags.Append(respDiags...) inherited := false