Terraform tigger a module after a resouce is created

Viewed 447

Very new to Terraform so give all the simple advice you got.

I want to setup a RKE-Cluster using/getting the Digital Ocean's newly created droplet IP address. I've setup a local_file to create a txt file in the RKE module (a real weird way to do it but not sure what else I can do.) When I try to terraform plan it I get

on modules/rke/rke.tf line 14, in data "template_file" "rkeip":
│   14:   template = file("${path.module}/rkeip.txt")
│     ├────────────────
│     │ path.module is "modules/rke"
│ 
│ Invalid value for "path" parameter: no file exists at modules/rke/rkeip.txt; this function works only with files
│ that are distributed as part of the configuration source code, so if this file will be created by a resource in
│ this configuration you must instead obtain this result from an attribute of that resource.

Here's what my droplet file looks like

 terraform {
  required_providers {
    digitalocean = {
      source = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}

variable "do_token" {}
variable "ssh_key_name" {}

provider "digitalocean" {
  token = var.do_token
}

data "digitalocean_ssh_key" "default" {
  name = "${var.ssh_key_name}"
}
#this installs Docker
data "template_file" "cloud-yaml" {
  template = file("${path.module}/modules/cloud.yaml")
}

resource "digitalocean_droplet" "terra" {
  image  = "ubuntu-20-04-x64"
  name   = "terra"
  region = "sfo3"
  size   = "s-1vcpu-1gb"
  ssh_keys = ["${data.digitalocean_ssh_key.default.fingerprint}"]
  user_data = data.template_file.cloud-yaml.rendered
}

resource "local_file" "rkeip" {
    content  = "${digitalocean_droplet.terra.ipv4_address}"
    filename = "${path.module}/modules/rke/rkeip.txt"
}

module "RKE" {
    source = "./modules/rke/"
}

and my RKE module

terraform {
  required_providers {
    rke = {
      source  = "rancher/rke"
      version = "1.2.4"
    }
  }
}

data "template_file" "rkeip" {
  template = file("${path.module}/rkeip.txt")
}

provider "rke" {
  log_file = "rke_debug.log"
}

resource "rke_cluster" "test" {
   nodes {
     address = data.template_file.rkeip.rendered
     user    = "root"
     role    = ["controlplane", "etcd", "worker"]
     ssh_key = file("~/.ssh/id_rsa")
    }
}

I've tried to use depends_on in rke.tf and droplet.tf but still same error.

2 Answers

Alrighty it seems that Terraform's rke cannot be made via a droplet in a one-shot so I have decided to use Provisioners to deal with all the mini-steps so for folks in similar positions here's my added code in the droplet.tf.

resource "null_resource" "rke" {
  connection {
            host = "${digitalocean_droplet.terra.ipv4_address}"
            type = "ssh"
            user = "root"
            private_key = file("${path.module}/YOURDOKEY")
            agent = false
        }

    provisioner "file" {
    source      = "${path.module}/keys.sh"
    destination = "/root/keys.sh"
  }
  
  provisioner "remote-exec" {
    inline = [
    "chmod +x /root/keys.sh",
    "./keys.sh",
    "rm keys.sh",
    "wget https://github.com/rancher/rke/releases/download/v1.3.2/rke_linux-amd64",
    "mv rke_linux-amd64 rke",
    "chmod +x rke",
    "printf '%s\n' 'nodes:' '  - address:' '    user: root' '    docker_socket: /var/run/docker.sock' '    role:' '      - controlplane' '      - etcd' '      - worker' '    ssh_key_path: ~/.ssh/id_rsa' >cluster.yml",
    "myip=$(curl ifconfig.co)",
    "sed -i \"s/address:/address: $myip/\" cluster.yml",
    ]
  }
}

Unfortunately it throws an error if you try ./rke up in remote-exec so you have to run it in the droplet.

Also I made keys.sh to bypass errors in inline since it did not like the commands. If you managed to place these commands without any errors feel free to comment.

#!/bin/bash
# keys.sh
# create ssh keys without direct input
ssh-keygen -t rsa -b 4096 -N '' <<<$'\n'
# so the droplet can ssh itself
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
sed -i '/AllowTcpForwarding/d' /etc/ssh/sshd_config
echo "AllowTcpForwarding yes" >> /etc/ssh/sshd_config
# not needed but I wanted to see the output
grep AllowTcpForwarding /etc/ssh/sshd_config

this is to fix docker errors in rke.

Your RKE module has different capitalization than the "rke" directory in the path. Do you think that might have something to do with it?

resource "local_file" "rkeip" {
    content  = "${digitalocean_droplet.terra.ipv4_address}"
    filename = "${path.module}/modules/rke/rkeip.txt"
}

module "RKE" {
    source = "./modules/rke/"
}

I would go one step further and say that, if all you're doing is passing a value which the child module requires, pass it in as a variable. Creating static files to pass information is an IAC anti-pattern IMO.

Note that "depends_on" is meant to be used as a last resort, and should include notation about why such a work-around was required.

Related