Skip to content

tailscale_acl v0.29.x: semantic changes produce unreadable full-file formatting diff#798

Description

@dsander

Hi 馃憢 !

Description

Since upgrading the Tailscale provider from 0.28.0 to 0.29.2, any semantic change to a tailscale_acl resource causes Terraform/OpenTofu to display almost the entire policy file as changed.

Most displayed changes are formatting differences between:

  • the canonical HuJSON returned by the Tailscale API, using tabs and canonical line wrapping; and
  • the original HuJSON supplied through templatefile, using spaces.

Whitespace-only changes are correctly suppressed. However, once there is a genuine policy change, the plan compares the API-formatted state against the raw configured string, making the plan practically impossible to review.

This worked correctly with provider 0.28.0.

Provider and OpenTofu versions

  • tailscale/tailscale: 0.29.2
  • previous working provider: 0.28.0
  • OpenTofu: 1.11.2
  • Platform: darwin_arm64

Configuration

We are using it similar to the documented example but use the result of templatefile.

resource "tailscale_acl" "main" {
  acl = templatefile("${path.module}/tailscale_acl.hujson", {
    installation_names = local.installation_names
  })
}

Simplified policy:

{
  "hosts": {
    "vector": "100.64.0.1",
  },

  "ipsets": {
    "ipset:monitoring-endpoints": ["add host:vector"],
  },
}

Making this small semantic change:

 "hosts": {
   "vector": "100.64.0.1",
+  "vector-stage": "100.64.0.2",
 },

-"ipset:monitoring-endpoints": ["add host:vector"],
+"ipset:monitoring-endpoints": ["add host:vector", "add host:vector-stage"],

causes the plan to show the complete policy as removed and re-added, primarily changing tabs, spaces, wrapping, alignment, and trailing commas. Excerpt from the plan output:

-     "ipsets": {
-             "ipset:monitoring-endpoints": ["add host:vector"],
-     },
+   "ipsets": {
+     "ipset:monitoring-endpoints": ["add host:vector", "add host:vector-stage"],
+   },

Expected behavior

The plan should show only the semantic HuJSON changes, as it did with provider 0.28.0.

Regression analysis

Not done personally, the LLMs knew the version it worked with before and came up with this:

This appears to be a regression from the plugin-framework migration in: #721

Provider 0.28.0 used StateFunc with hujson.Format and DiffSuppressOnRefresh: https://github.com/tailscale/terraform-provider-tailscale/blob/v0.28.0/tailscale/resource_acl.go#L64-L89

In 0.29.2, Read stores the raw API HuJSON in state: https://github.com/tailscale/terraform-provider-tailscale/blob/v0.29.2/tailscale/resource_acl.go#L86-L100

The new plan modifier suppresses the diff when canonical state and configuration are identical. If they differ semantically, however, it leaves the raw configured value in the plan: https://github.com/tailscale/terraform-provider-tailscale/blob/v0.29.2/tailscale/plan_modifiers.go#L64-L82

This means that any real change causes Terraform to compare the server-formatted state with the differently formatted configuration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions