linode/terraform-provider-linode

[Bug]: Inconsistent plan

REBELinBLUE opened this issue · 2 comments

Terraform Version

1.6.6

Linode Provider Version

2.13.0

Effected Terraform Resources

linode_instance

Terraform Config Files

data "linode_kernel" "latest" {
  id = "linode/latest-64bit"
}

data "linode_instance_type" "default" {
  id = "g6-nanode-1"
}

data "linode_region" "london" {
  id = "eu-west"
}

data "linode_image" "ubuntu_23_10" {
  id = "linode/ubuntu23.10"
}

resource "linode_instance" "ubuntu_23_10" {

  type   = data.linode_instance_type.default.id
  region = data.linode_region.london.id

  tags = []

  backups_enabled = false
  swap_size       = 512

  alerts {
    cpu            = 90
    io             = 10000
    network_in     = 10
    network_out    = 10
    transfer_quota = 80
  }

  watchdog_enabled = true
}

resource "linode_instance_disk" "ubuntu_23_10_boot" {
  linode_id = linode_instance.ubuntu_23_10.id

  label      = "Boot"
  size       = data.linode_instance_type.default.disk - linode_instance.ubuntu_23_10.swap_size
  filesystem = "ext4"

  image = data.linode_image.ubuntu_23_10.id

  authorized_keys = []

  authorized_users = []

  root_pass = "foobarbazqux"
}

resource "linode_instance_disk" "ubuntu_23_10_swap" {
  linode_id = linode_instance.ubuntu_23_10.id

  label      = "Swap Image"
  size       = linode_instance.ubuntu_23_10.swap_size
  filesystem = "swap"
}

resource "linode_instance_config" "ubuntu_23_10" {
  linode_id = linode_instance.ubuntu_23_10.id

  booted = true

  label = "Ubuntu 23.10 Profile"

  virt_mode    = "paravirt"
  kernel       = data.linode_kernel.latest.id
  run_level    = "default"
  memory_limit = 0

  device {
    device_name = "sda"
    disk_id     = linode_instance_disk.ubuntu_23_10_boot.id
  }

  device {
    device_name = "sdb"
    disk_id     = linode_instance_disk.ubuntu_23_10_swap.id
  }

  root_device = "/dev/sda"

  interface {
    primary = true
    purpose = "public"
  }

  helpers {
    devtmpfs_automount = true
    distro             = true
    modules_dep        = true
    network            = true
    updatedb_disabled  = true
  }
}

Debug Output

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # linode_instance.ubuntu_23_10 will be created
  + resource "linode_instance" "ubuntu_23_10" {
      + backups            = (known after apply)
      + backups_enabled    = false
      + boot_config_label  = (known after apply)
      + booted             = (known after apply)
      + has_user_data      = (known after apply)
      + host_uuid          = (known after apply)
      + id                 = (known after apply)
      + ip_address         = (known after apply)
      + ipv4               = (known after apply)
      + ipv6               = (known after apply)
      + label              = (known after apply)
      + migration_type     = "cold"
      + private_ip_address = (known after apply)
      + region             = "eu-west"
      + resize_disk        = false
      + shared_ipv4        = (known after apply)
      + specs              = (known after apply)
      + status             = (known after apply)
      + swap_size          = 512
      + tags               = []
      + type               = "g6-nanode-1"
      + watchdog_enabled   = true

      + alerts {
          + cpu            = 90
          + io             = 10000
          + network_in     = 10
          + network_out    = 10
          + transfer_quota = 80
        }
    }

  # linode_instance_config.ubuntu_23_10 will be created
  + resource "linode_instance_config" "ubuntu_23_10" {
      + booted       = true
      + id           = (known after apply)
      + kernel       = "linode/latest-64bit"
      + label        = "Ubuntu 23.10 Profile"
      + linode_id    = (known after apply)
      + memory_limit = 0
      + root_device  = "/dev/sda"
      + run_level    = "default"
      + virt_mode    = "paravirt"

      + device {
          + device_name = "sda"
          + disk_id     = (known after apply)
        }
      + device {
          + device_name = "sdb"
          + disk_id     = (known after apply)
        }

      + helpers {
          + devtmpfs_automount = true
          + distro             = true
          + modules_dep        = true
          + network            = true
          + updatedb_disabled  = true
        }

      + interface {
          + active  = (known after apply)
          + id      = (known after apply)
          + primary = true
          + purpose = "public"
          + vpc_id  = (known after apply)
        }
    }

  # linode_instance_disk.ubuntu_23_10_boot will be created
  + resource "linode_instance_disk" "ubuntu_23_10_boot" {
      + created    = (known after apply)
      + filesystem = "ext4"
      + id         = (known after apply)
      + image      = "linode/ubuntu23.10"
      + label      = "Boot"
      + linode_id  = (known after apply)
      + root_pass  = (sensitive value)
      + size       = 25088
      + status     = (known after apply)
      + updated    = (known after apply)
    }

  # linode_instance_disk.ubuntu_23_10_swap will be created
  + resource "linode_instance_disk" "ubuntu_23_10_swap" {
      + created    = (known after apply)
      + filesystem = "swap"
      + id         = (known after apply)
      + label      = "Swap Image"
      + linode_id  = (known after apply)
      + size       = 512
      + status     = (known after apply)
      + updated    = (known after apply)
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

linode_instance.ubuntu_23_10: Creating...
linode_instance.ubuntu_23_10: Still creating... [10s elapsed]
linode_instance.ubuntu_23_10: Creation complete after 15s [id=54251740]
╷
│ Error: Provider produced inconsistent final plan
│ 
│ When expanding the plan for linode_instance_disk.ubuntu_23_10_swap to
│ include new values learned so far during apply, provider
│ "registry.terraform.io/linode/linode" produced an invalid new value for
│ .size: was cty.NumberIntVal(512), but now cty.NumberIntVal(0).
│ 
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵
╷
│ Error: Provider produced inconsistent final plan
│ 
│ When expanding the plan for linode_instance_disk.ubuntu_23_10_boot to
│ include new values learned so far during apply, provider
│ "registry.terraform.io/linode/linode" produced an invalid new value for
│ .size: was cty.NumberIntVal(512), but now cty.NumberIntVal(0).
│ 
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵

Panic Output

No response

Expected Behavior

The plan to be consistent between plan and apply

Actual Behavior

The swap size used to calculate the size for linode_instance_disk was 512 during the plan and 0 during the apply

Steps to Reproduce

Just apply

@REBELinBLUE Thanks for the report!

I was able to reproduce this issue locally and it seems to be the result of the size of the swap disk relying on the linode_instance.swap_size attribute. Since the swap_size attribute dictates the size of the implicitly swap disk (i.e. when linode_instance.image is defined) it should not be defined when explicit disks (linode_instance_disk) are defined.

It looks like we're missing validation for this and our docs are a bit unclear, so I'll create a ticket in our internal tracker to revise them both accordingly.

In the meantime, you should be able to provision your instance as expected using the following configuration:

locals {
  default_swap_size = 512
}

data "linode_kernel" "latest" {
  id = "linode/latest-64bit"
}

data "linode_instance_type" "default" {
  id = "g6-nanode-1"
}

data "linode_region" "london" {
  id = "eu-west"
}

data "linode_image" "ubuntu_23_10" {
  id = "linode/ubuntu23.10"
}

resource "linode_instance" "ubuntu_23_10" {

  type   = data.linode_instance_type.default.id
  region = data.linode_region.london.id

  tags = []

  backups_enabled = false

  alerts {
    cpu            = 90
    io             = 10000
    network_in     = 10
    network_out    = 10
    transfer_quota = 80
  }

  watchdog_enabled = true
}

resource "linode_instance_disk" "ubuntu_23_10_boot" {
  linode_id = linode_instance.ubuntu_23_10.id

  label      = "Boot"
  size       = data.linode_instance_type.default.disk - local.default_swap_size
  filesystem = "ext4"

  image = data.linode_image.ubuntu_23_10.id

  authorized_keys = []

  authorized_users = []

  root_pass = "foobarbazqux"
}

resource "linode_instance_disk" "ubuntu_23_10_swap" {
  linode_id = linode_instance.ubuntu_23_10.id

  label      = "Swap Image"
  size       = local.default_swap_size
  filesystem = "swap"
}

resource "linode_instance_config" "ubuntu_23_10" {
  linode_id = linode_instance.ubuntu_23_10.id

  booted = true

  label = "Ubuntu 23.10 Profile"

  virt_mode    = "paravirt"
  kernel       = data.linode_kernel.latest.id
  run_level    = "default"
  memory_limit = 0

  device {
    device_name = "sda"
    disk_id     = linode_instance_disk.ubuntu_23_10_boot.id
  }

  device {
    device_name = "sdb"
    disk_id     = linode_instance_disk.ubuntu_23_10_swap.id
  }

  root_device = "/dev/sda"

  interface {
    primary = true
    purpose = "public"
  }

  helpers {
    devtmpfs_automount = true
    distro             = true
    modules_dep        = true
    network            = true
    updatedb_disabled  = true
  }
}

thanks, that is what I have actually done using a local but I wasn't sure if it should work or not, so I guess I shouldn't define it on the instance.

Thanks