ionos-cloud/terraform-provider-ionoscloud

"image_name" not mandatory for "plan" but for "apply"

larsen0815 opened this issue · 21 comments

Description

"terraform plan" doesn't complain when a server resource doesn't contain "image_name" but fails to "apply" because of it missing.

Expected behavior

  • "plan" should show that "image_name" is missing (if this is really necessary, see next point)
  • This shouldn't be necessary in the first place, as it's possible to add storages without an image via DCD. So, this should also be possible via terraform.

Environment

Terraform v1.0.0
on linux_amd64
provider registry.terraform.io/ionos-cloud/ionoscloud v5.1.7
Debian GNU/Linux 10 (buster)

Configuration Files

terraform {
  required_providers {
    ionoscloud = {
      source  = "ionos-cloud/ionoscloud"
    }
  }
}

provider "ionoscloud" {
  username = "${var.api_user}"
  password = "${var.api_password}"
  endpoint = "${var.api_endpoint}"
}

resource "ionoscloud_datacenter" "example" {
  name        = "example"
  location    = "de/fra"
}

resource "ionoscloud_lan" "LAN_10" {
  datacenter_id = ionoscloud_datacenter.example.id
  public        = true
}

resource "ionoscloud_ipblock" "SouthDakota" {
  location = "${ionoscloud_datacenter.example.location}"
  size     = 1
  name     = "SouthDakota" 
}


resource "ionoscloud_server" "SouthDakota" {
  name              = "SouthDakota Server"
  datacenter_id     = "${ionoscloud_datacenter.example.id}"
  cores             = 1
  ram               = 1024
  availability_zone = "AUTO"
  cpu_family        = "AMD_OPTERON"

  volume {
    name           = "SouthDakota HDD-Storage"
    size           = 20
    disk_type      = "HDD"
  }

  nic {
    lan             = "${ionoscloud_lan.LAN_10.id}"
    dhcp            = true
    ip              = "${ionoscloud_ipblock.SouthDakota.ips[0]}"
  }
}

How to Reproduce

I have imported a server from Nexinto. Adapted the main.tf to resemble the current state, so "plan" doesn't show any differences.
Then I removed terraform.tfstate and switched the endpoint from Nexinto to Ionos to create this server on Ionos.

When I run "terraform plan", I get this:

# terraform plan
ionoscloud_datacenter.example: Refreshing state... [id=123]

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:

  # ionoscloud_ipblock.SouthDakota will be created
  + resource "ionoscloud_ipblock" "SouthDakota" {
      + id       = (known after apply)
      + ips      = (known after apply)
      + location = "de/fra"
      + name     = "SouthDakota"
      + size     = 1
    }

  # ionoscloud_lan.LAN_10 will be created
  + resource "ionoscloud_lan" "LAN_10" {
      + datacenter_id = "123"
      + id            = (known after apply)
      + public        = true
    }

  # ionoscloud_server.SouthDakota will be created
  + resource "ionoscloud_server" "SouthDakota" {
      + availability_zone = "AUTO"
      + boot_image        = (known after apply)
      + boot_volume       = (known after apply)
      + cores             = 1
      + cpu_family        = "AMD_OPTERON"
      + datacenter_id     = "123"
      + firewallrule_id   = (known after apply)
      + id                = (known after apply)
      + image_name        = (known after apply)
      + image_password    = (sensitive value)
      + name              = "SouthDakota Server"
      + primary_ip        = (known after apply)
      + primary_nic       = (known after apply)
      + ram               = 1024
      + ssh_key_path      = (known after apply)

      + nic {
          + dhcp = true
          + ip   = (known after apply)
          + ips  = (known after apply)
          + lan  = (known after apply)
          + mac  = (known after apply)
        }

      + volume {
          + availability_zone = (known after apply)
          + bus               = (known after apply)
          + disk_type         = "HDD"
          + image_aliases     = (known after apply)
          + licence_type      = (known after apply)
          + name              = "SouthDakota HDD-Storage"
          + size              = 20
        }
    }

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

Error and Debug Output

On "terraform apply":

ionoscloud_server.SouthDakota: Creating...
?
¦ Error: either 'image_name' or 'volume.0.image_name' must be provided
¦
¦   with ionoscloud_server.SouthDakota,
¦   on main.tf line 32, in resource "ionoscloud_server" "SouthDakota":
¦   32: resource "ionoscloud_server" "SouthDakota" {
¦
?

Additional Notes

Workaround:

  • Create dummy image and upload it to Ionos:
dd if=/dev/zero of=/root/dummy.img bs=1k count=1
  • Use image_name = "dummy.img" in your main.tf

@larsen0815 - please try v5.2.0-beta.2 - please note this is a beta - since we've just upgraded the terraform sdk to v2.4.3

Will test it within next week.

Tested with v5.2.0 (not beta) after removing "image_name":
Error: either 'image_name', 'licence_type', or 'image_alias' must be set
"plan" show no error upfront.

Using "image_name" as before, the plugin crashes:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x108b9ad]

goroutine 32 [running]:
github.com/ionos-cloud/terraform-provider-ionoscloud/ionoscloud.resourceDatacenterRead(0x17380e0, 0xc00058b080, 0xc00059ac00, 0x12f76e0, 0xc00058e1e0, 0xc00059f5f0, 0xc0000198f0, 0x40cbe8)
    github.com/ionos-cloud/terraform-provider-ionoscloud/ionoscloud/resource_datacenter.go:110 +0x25d
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*Resource).read(0xc0000c29c0, 0x1738060, 0xc000596640, 0xc00059ac00, 0x12f76e0, 0xc00058e1e0, 0x0, 0x0, 0x0)
    github.com/hashicorp/terraform-plugin-sdk/v2@v2.4.3/helper/schema/resource.go:297 +0x1ec
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*Resource).RefreshWithoutUpgrade(0xc0000c29c0, 0x1738060, 0xc000596640, 0xc000587b20, 0x12f76e0, 0xc00058e1e0, 0xc00000ecb8, 0x0, 0x0, 0x0)
    github.com/hashicorp/terraform-plugin-sdk/v2@v2.4.3/helper/schema/resource.go:564 +0x1c2
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*GRPCProviderServer).ReadResource(0xc0004cd100, 0x1738060, 0xc000596640, 0xc000596680, 0xc000596640, 0x1312600, 0x13707a0)
    github.com/hashicorp/terraform-plugin-sdk/v2@v2.4.3/helper/schema/grpc_provider.go:575 +0x42f
github.com/hashicorp/terraform-plugin-go/tfprotov5/server.(*server).ReadResource(0xc00017c160, 0x1738060, 0xc000596640, 0xc00058ab40, 0xc00017c160, 0xc0005626c0, 0xc000082ba0)
    github.com/hashicorp/terraform-plugin-go@v0.2.1/tfprotov5/server/server.go:298 +0x101
github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/tfplugin5._Provider_ReadResource_Handler(0x13707a0, 0xc00017c160, 0x1738120, 0xc0005626c0, 0xc00058aae0, 0x0, 0x1738120, 0xc0005626c0, 0xc0008a0300, 0x16b)
    github.com/hashicorp/terraform-plugin-go@v0.2.1/tfprotov5/internal/tfplugin5/tfplugin5_grpc.pb.go:344 +0x217
google.golang.org/grpc.(*Server).processUnaryRPC(0xc00017bc00, 0x17460e0, 0xc00089f080, 0xc0001ca400, 0xc0004cb290, 0x2029e10, 0x0, 0x0, 0x0)
    google.golang.org/grpc@v1.32.0/server.go:1194 +0x50a
google.golang.org/grpc.(*Server).handleStream(0xc00017bc00, 0x17460e0, 0xc00089f080, 0xc0001ca400, 0x0)
    google.golang.org/grpc@v1.32.0/server.go:1517 +0xcfd
google.golang.org/grpc.(*Server).serveStreams.func1.2(0xc000034240, 0xc00017bc00, 0x17460e0, 0xc00089f080, 0xc0001ca400)
    google.golang.org/grpc@v1.32.0/server.go:859 +0xa1
created by google.golang.org/grpc.(*Server).serveStreams.func1
    google.golang.org/grpc@v1.32.0/server.go:857 +0x204

Tested with v5.2.0 (not beta) after removing "image_name":
Error: either 'image_name', 'licence_type', or 'image_alias' must be set
"plan" show no error upfront.

yes, you need to specify licence_type OTHER or UNKNOWN if you're not using an image name

Shouldn't "plan" already show a warning in that case?

Regarding the crash mentioned before: Could be caused by the current DCD outage.
Also received this when trying another time:
The plugin encountered an error, and failed to respond to the plugin.(*GRPCProvider).ReadResource call. The plugin logs may contain more details.
Maybe handle situations like this in the provider?

Regarding the crash mentioned before: Could be caused by the current DCD outage.
Also received this when trying another time:
The plugin encountered an error, and failed to respond to the plugin.(*GRPCProvider).ReadResource call. The plugin logs may contain more details.
Maybe handle situations like this in the provider?

if it's a crash than we definitely should avoid it, I'll look into it if I can manage to replicate the issue.

Shouldn't "plan" already show a warning in that case?

Not necessarily. There are two issues here:

  1. plan usually reports syntax errors and attribute validation errors. Here this is not the case since either one of the three must be specified
  2. we can't tell in the provider whether we're in plan or apply phase - only terraform knows and orchestrates that

I'll look into how we can implement some custom validation (if possible) that would catch that in the plan phase.

To replicate you could possibly use your HOSTS to redirect traffic to the endpoint to e.g. localhost.

DCD seems to be running again and the crash is gone. However, I have set licence_type = "OTHER" and still get the same warning either 'image_name', 'licence_type', or 'image_alias' must be set

To replicate you could possibly use your HOSTS to redirect traffic to the endpoint to e.g. localhost.

DCD seems to be running again and the crash is gone. However, I have set licence_type = "OTHER" and still get the same warning either 'image_name', 'licence_type', or 'image_alias' must be set

can you paste here your plan?

see "Configuration Files" above plus licence_type = "OTHER" (below resource "ionoscloud_server")

you should specify the licence_type in the volume definition that's part of the server definition

ok, will test with the next server that is up for migration (next week).

off-topic: Would it be possible to not start the VM when creating a new one?

It's up to the api, afaik there's no option for that, I'll see if there's a workaround.

Yes, there is no option at the API. And if the API does not support this we should not workaround here at this level.
The only way would be to create the sever, let it start and use API calls to stop it again which will be a hard stop and may cause more problems.

agreed, I was thinking more in terms of a hidden, undocumented option of the api, if there's any :)

Ok. Where should I open a ticket to ask for this feature in the API?

that would be the vdc-bundles repo but I'm not sure if the guys are actually monitoring the github issues. We're using their internal Jira queue to report issues, on the VDC project

@larsen0815 : I'm not happy to say this, but I think the best way where you can keep track of this FR would be to write a mail to our support that Servers should allow for being created without starting in API and DCD. And please describe the use case behind it.

For the background: API and SDK/tooling are done by different teams. SDK/Tooling uses this public repo. The API team has no public repo - the API implementation is closed source. And it does also affect the DCD (another development team).

you should specify the licence_type in the volume definition that's part of the server definition

Ok, this did work now. Thanks =)

Noticed another similar thing and a minor typo for which I am going to open separate tickets.