IBM-Cloud / terraform-provider-ibm

https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs
Mozilla Public License 2.0
342 stars 673 forks source link

ibm_is_floating_ip does not support association to an existing network interface #3740

Open powellquiring opened 2 years ago

powellquiring commented 2 years ago

Community Note

Terraform CLI and Terraform IBM Provider Version

tf2 $ tf version
Terraform v1.1.8
on darwin_amd64
+ provider registry.terraform.io/ibm-cloud/ibm v1.40.1

Your version of Terraform is out of date! The latest version
is 1.1.9. You can update by downloading from https://www.terraform.io/downloads.html

Affected Resource(s)

Expected

I expect to be able to associate an existing floating_ip to an existing network interface.

resource "ibm_is_instance" "onprem" {
  name           = "${local.BASENAME_ONPREM}-onprem-vsi"
  image          = data.ibm_is_image.os.id
  profile        = var.profile
  vpc            = ibm_is_vpc.onprem.id
  zone           = var.zone
  keys           = [data.ibm_is_ssh_key.sshkey.id]
  resource_group = data.ibm_resource_group.all_rg.id
  user_data      = local.onprem_user_data
  primary_network_interface {
    subnet = ibm_is_subnet.onprem.id
    # floating_ip = ibm_is_floating_ip.onprem.id
  }
}

resource "ibm_is_floating_ip" "onprem" {
  tags           = local.tags
  resource_group = data.ibm_resource_group.all_rg.id
  name           = "${local.BASENAME_ONPREM}-onprem-vsi"
  #target         = ibm_is_instance.onprem.primary_network_interface[0].id
  zone = var.zone
}

/*------------------------------------------------
resource "ibm_is_floating_ip_associate" "onprem" {
  floating_ip       = ibm_is_floating_ip.onprem.id
  network_interface = ibm_is_instance.onprem.primary_network_interface[0].id
}
*/

Use Case - Create floating ip before instance

My use case was to pass the floating ip as user_data argument to a ibm_is_instance resource. This can not be accomplished using the ibm_is_floating_ip resource with a target argument because the floating ip would be created after the is_instance.

It is also not possible to specify the ibm_is_instance_network_interface for the primary network interface of an is_instance.

Use case - use an existing floating ip for a new ibm_is_instance

I may have reserved a floating_ip manually and then wish to use the data:

data "ibm_is_floating_ip" "onprem" {
  name = "example-floating-ip"
}

resource "ibm_is_floating_ip_associate" "onprem" {
  floating_ip = data.ibm_is_floating_ip.onprem.id
  network_interface         = ibm_is_instance.onprem.primary_network_interface[0].id
}
powellquiring commented 2 years ago

example: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip_association

powellquiring commented 2 years ago

Workaround:

/*------------------------------------------------
resource "ibm_is_floating_ip_associate" "onprem" {
  floating_ip       = ibm_is_floating_ip.onprem.id
  network_interface = ibm_is_instance.onprem.primary_network_interface[0].id
}
*/
resource "null_resource" "ibm_is_floating_ip_associate" {
  triggers = {
    path_module = path.module
    INSTANCE    = ibm_is_instance.onprem.id
    NIC         = ibm_is_instance.onprem.primary_network_interface[0].id
    FLOATING_IP = ibm_is_floating_ip.onprem.id
  }
  provisioner "local-exec" {
    command = <<-EOS
      INSTANCE=${self.triggers.INSTANCE} \
      NIC=${self.triggers.NIC} \
      FLOATING_IP=${self.triggers.FLOATING_IP} \
      COMMAND=create \
      ${self.triggers.path_module}/bin/localexec.sh
    EOS
  }
  provisioner "local-exec" {
    when    = destroy
    command = <<-EOS
      INSTANCE=${self.triggers.INSTANCE} \
      NIC=${self.triggers.NIC} \
      FLOATING_IP=${self.triggers.FLOATING_IP} \
      COMMAND=destroy \
      ${self.triggers.path_module}/bin/localexec.sh
    EOS
  }
}

localexec.sh

#!/bin/sh
set -e

#ibmcloud is instance-network-interface-floating-ip-add

inifi_create() {
  ibmcloud is instance-network-interface-floating-ip-add $INSTANCE $NIC $FLOATING_IP
}

inifi_destroy() {
  ibmcloud is instance-network-interface-floating-ip-add $INSTANCE $NIC $FLOATING_IP
}

if [ $COMMAND = create ]; then
  inifi_create
fi

if [ $COMMAND = destroy ]; then
  inifi_destroy
fi
blafois commented 2 years ago

Hello @powellquiring !

Encountering the same issue. I found a bypass for the use case of passing the external floating IP to the user-data: I actually retrieve the floating IP through the metadata in the cloudinit user-data script:

#!/bin/bash

apt-get update && apt-get install -y curl jq

# Retrieve metadata auth token
instance_identity_token=`curl -X PUT "http://169.254.169.254/instance_identity/v1/token?version=2022-03-08" -H "Metadata-Flavor: ibm" -d '{ "expires_in": 3600 }' | jq -r .access_token`

# Retrieve floating IP
external_floating_ip=`curl -X GET "http://169.254.169.254/metadata/v1/instance/network_interfaces?version=2022-05-24" -H "Authorization: Bearer $instance_identity_token" | jq -r .network_interfaces[0].floating_ips[0].address`

It allows me to only keep Terraform code without mixing/messing with other scripts. Hope this helps !