terraform-provider-stackit icon indicating copy to clipboard operation
terraform-provider-stackit copied to clipboard

Adding labels to a stackit_server resource is causing a replacement

Open NilsGriebner opened this issue 2 months ago • 4 comments

Description

When adding a label to a existing stackit_server resource, terraform plan wants to replace the whole resource.

Steps to reproduce

First add a stackit_server resource like

resource "stackit_server" "my_server" {
  project_id = "my-project"
  name       = "myserver"
  boot_volume = {
    source_type = "volume"
    source_id   = "my-volume-id"
  }
  availability_zone = "my favorite az"
  machine_type      = "c1.2"
}

After that run terraform plan and terraform apply so that the resource is created. Now add the labels map to the resource like this:

resource "stackit_server" "my_server" {
  project_id = "my-project"
  name       = "myserver"
  labels = {
    mylabel = "foo"
 }
  boot_volume = {
    source_type = "volume"
    source_id   = "my-volume-id"
  }
  availability_zone = "my favorite az"
  machine_type      = "c1.2"
}

Run terraform plan again and observe the output. In my case Terraform wants to recreate the whole server.

Actual behavior

Terraform wants to replace the server.

Expected behavior

I'd expect that the labels are just added, without a resource replacement.

Environment

  • OS: Debian sid
  • OpenTofu version: v1.10.6
  • Version of the STACKIT Terraform provider: v0.69.0

NilsGriebner avatar Nov 20 '25 12:11 NilsGriebner

Hi @NilsGriebner,

I wasn't able to reproduce this. From looking at the code changes to the labels field shouldn't trigger a replace (there's no "requires replace" statement present):

https://github.com/stackitcloud/terraform-provider-stackit/blob/25134e8fe9e21a732980cddefca4fc7cdf43d710/stackit/internal/services/iaas/server/resource.go#L327-L331

Maybe the replace is related to your boot_volume field definition. It's not clear to me from the example how the volume is managed, maybe you can provide the full example here. Because changes to the boot_volume require a replacement of the whole server resource:

https://github.com/stackitcloud/terraform-provider-stackit/blob/25134e8fe9e21a732980cddefca4fc7cdf43d710/stackit/internal/services/iaas/server/resource.go#L229-L234

You can also see which field of the server resource triggers the replacement of the whole resource in the plan output:

Image

E.g. in this case the replacement is related to the boot_volume, not to the labels.

Looking forward to hear from you 😊

Best regards Ruben from STACKIT Developer Tools team

rubenhoenle avatar Nov 24 '25 08:11 rubenhoenle

Hi @rubenhoenle,

thanks for your quick reply. I checked a second time and you're totally right. The replacement is caused by the boot volume. Here's the Terraform output.

Image

NilsGriebner avatar Nov 24 '25 10:11 NilsGriebner

Ok, the replacement is expected in that case at least 😄

But did I get that correct, there are no changes on the boot volume, right? So you wouldn't expect a replacement of the server resource?

Is the boot volume also managed via Terraform? Could you maybe provide us the Terraform config including the boot volume resource so we can check?

rubenhoenle avatar Nov 24 '25 14:11 rubenhoenle

Right, there are no changes (at least no intentional ones). The boot volume is also managed by Terraform. My setup is basically the code provided in https://github.com/stackitcloud/terraform-pfsense-appliance with another image. Here's my code.

resource "stackit_image" "opnsense_image" {
  project_id      = var.STACKIT_PROJECT_ID
  name            = "opnsense"
  local_file_path = "./OPNsense-25.7-nano-amd64.qcow2" 
  disk_format     = "qcow2"
  min_disk_size   = 10
  min_ram         = 2
  config = {
    uefi = false
  }
  lifecycle {
    ignore_changes = [local_file_path]
  }
}

resource "stackit_volume" "opnsense_vol" {
  project_id        = var.STACKIT_PROJECT_ID
  name              = "opnsense-root"
  availability_zone = var.opnsense_zone
  size              = 16
  performance_class = "storage_premium_perf4"
  source = {
    id   = stackit_image.opnsense_image.image_id
    type = "image"
  }
}

resource "stackit_server" "opnsense_server" {
  project_id = var.STACKIT_PROJECT_ID
  name       = "opnSense"
  boot_volume = {
    source_type = "volume"
    source_id   = stackit_volume.opnsense_vol.volume_id
  }
  availability_zone = var.opnsense_zone
  machine_type      = "c1.2"
}

NilsGriebner avatar Nov 24 '25 19:11 NilsGriebner