Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic type attribute does not work with sets #1008

Open
mawasile opened this issue Jun 12, 2024 · 1 comment
Open

Dynamic type attribute does not work with sets #1008

mawasile opened this issue Jun 12, 2024 · 1 comment
Labels
bug Something isn't working waiting-response Issues or pull requests waiting for an external response

Comments

@mawasile
Copy link

Module version

1.9.0

Relevant provider source code

resource implementation:
https://github.com/microsoft/terraform-provider-power-platform/blob/main/internal/powerplatform/services/data_record/resource_data_record.go

func (r *DataRecordResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
	resp.Schema = schema.Schema{
		Description:         "The Power Platform Data Record Resource allows the management of configuration records that are stored in Dataverse as records. This resource is not recommended for managing business data or other data that may be changed by Dataverse users in the context of normal business activities.",
		MarkdownDescription: "The Power Platform Data Record Resource allows the management of configuration records that are stored in Dataverse as records. This resource is not recommended for managing business data or other data that may be changed by Dataverse users in the context of normal business activities.",
		Attributes: map[string]schema.Attribute{
			"id": schema.StringAttribute{
				MarkdownDescription: "Unique id (guid)",
				Description:         "Unique id (guid)",
				Computed:            true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.UseStateForUnknown(),
				},
			},
			"environment_id": schema.StringAttribute{
				Description: "Id of the Dynamics 365 environment",
				Required:    true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.RequiresReplace(),
				},
			},
			"table_logical_name": schema.StringAttribute{
				Description: "Logical name of the data record table",
				Required:    true,
				PlanModifiers: []planmodifier.String{
					stringplanmodifier.RequiresReplace(),
				},
			},
			"columns": schema.DynamicAttribute{
				Description: "Columns of the data record table",
				Required:    true,
			},
		},
	}
}

Terraform Configuration Files

terraform {
  required_providers {
    powerplatform = {
      source = "microsoft/power-platform"
    }
  }
}

provider "powerplatform" {
  use_cli = true
}



resource "powerplatform_environment" "data_record_example_env" {
  display_name     = "powerplatform_data_record_example"
  location         = "europe"
  environment_type = "Sandbox"
  dataverse = {
    language_code     = "1033"
    currency_code     = "USD"
    security_group_id = "00000000-0000-0000-0000-000000000000"
  }
}


resource "powerplatform_data_record" "account" {
  environment_id     = powerplatform_environment.data_record_example_env.id
  table_logical_name = "account"

  columns = {
    name = "Contoso"

    contact_customer_accounts = toset([
      {
        table_logical_name = "contact",
        data_record_id     = powerplatform_data_record.contact.id
      }
    ])

  }
}

resource "powerplatform_data_record" "contact" {
  environment_id     = powerplatform_environment.data_record_example_env.id
  table_logical_name = "contact"

  columns = {
    firstname = "John"
    lastname  = "Doe"
  }
}

Debug Output

apply.log and plan.log can be found here: https://gist.github.com/mawasile/f61ce8807e1011983b9089f97dba542b

Expected Behavior

We use dynamic type for "columns" attribute and inside that we also allow to create collection of values. if that collection is a list everything is working fine but when we use toset() then in terraform plan we get in-place update which is incorrect as nothing had changed. Just by removing toset in contact_customer_accounts from the above example, fixes that issue.

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # powerplatform_data_record.account will be updated in-place
  ~ resource "powerplatform_data_record" "account" {
        id                 = "830dc891-9b28-ef11-840a-000d3ab60f37"
        # (3 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Actual Behavior

toset should not generate dirty state when used in dynamic attribute

Steps to Reproduce

  1. have a terraform resource with dynamic attribute with a set attribute inside that dynamic type
  2. terraform apply
  3. terraform plan => plan is not empty
@mawasile mawasile added the bug Something isn't working label Jun 12, 2024
@austinvalle
Copy link
Member

austinvalle commented Jul 19, 2024

Hey there @mawasile 👋🏻, thanks for reporting the issue with an example and sorry you're running into trouble here.

I wasn't able to recreate this behavior with the dynamic attribute isolated in a sandbox, but the CLI output you shared seems to indicate that Terraform core is detecting a difference, but the plan renderer cannot find where the difference is. With dynamic schemas it can be a little difficult to pinpoint where that difference is being introduced.

Looking through your provider code, I do see some code that could be a good place to start investigating.

So columns is a Required attribute, which to Terraform means that the value that is set in the Terraform configuration must be preserved during plan/apply. One piece of code I found interesting is here:

https://github.com/microsoft/terraform-provider-power-platform/blob/291015bd65b7a712eab20a56c92c7bcc275480c4/internal/powerplatform/services/data_record/resource_data_record.go#L163-L168

This code is attempting to refresh a configuration value, so if the value being refreshed is not an exact match, Terraform will detect drift continuously, until the practitioner updates their configuration to match the new refreshed value. I would expect, since this value is not Computed, that it should not be refreshed.

Regardless, I'd be interested to know if there is a difference being generated by the r.convertColumnsToState function. With sets that contain objects in particular, Terraform core has difficulties with it's proposed new state algorithm that you might be inadvertently running into by refreshing the config value, even if the updated value should match.

I'd start by looking at that piece of code, but I'd think that removing that refresh of the columns config value should prevent that state drift.

Let me know what you find!

@austinvalle austinvalle added the waiting-response Issues or pull requests waiting for an external response label Jul 19, 2024
@github-actions github-actions bot removed the waiting-response Issues or pull requests waiting for an external response label Jul 19, 2024
@austinvalle austinvalle added the waiting-response Issues or pull requests waiting for an external response label Jul 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working waiting-response Issues or pull requests waiting for an external response
Projects
None yet
Development

No branches or pull requests

2 participants