Add Terraform with Equinix Metal:
This gets the Tinkerbell Sandbox up and running with Terraform on Equinix Metal. Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
This commit is contained in:
1
deploy/terraform/.gitignore
vendored
1
deploy/terraform/.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
terraform.tfstate
|
||||
terraform.tfstate.backup
|
||||
terraform.tfvars
|
||||
.terraform.lock.hcl
|
||||
|
@ -1,32 +0,0 @@
|
||||
{
|
||||
"id": "${id}",
|
||||
"metadata": {
|
||||
"facility": {
|
||||
"facility_code": "${facility_code}",
|
||||
"plan_slug": "${plan_slug}",
|
||||
"plan_version_slug": ""
|
||||
},
|
||||
"instance": {},
|
||||
"state": ""
|
||||
},
|
||||
"network": {
|
||||
"interfaces": [
|
||||
{
|
||||
"dhcp": {
|
||||
"arch": "x86_64",
|
||||
"ip": {
|
||||
"address": "${address}",
|
||||
"gateway": "192.168.1.1",
|
||||
"netmask": "255.255.255.248"
|
||||
},
|
||||
"mac": "${mac}",
|
||||
"uefi": false
|
||||
},
|
||||
"netboot": {
|
||||
"allow_pxe": true,
|
||||
"allow_workflow": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
YUM="yum"
|
||||
APT="apt"
|
||||
PIP3="pip3"
|
||||
YUM_CONFIG_MGR="yum-config-manager"
|
||||
WHICH_YUM=$(command -v $YUM)
|
||||
WHICH_APT=$(command -v $APT)
|
||||
YUM_INSTALL="$YUM install"
|
||||
APT_INSTALL="$APT install"
|
||||
PIP3_INSTALL="$PIP3 install"
|
||||
declare -a YUM_LIST=("https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm"
|
||||
"docker-ce"
|
||||
"docker-ce-cli"
|
||||
"epel-release"
|
||||
"pass"
|
||||
"python3")
|
||||
declare -a APT_LIST=("docker"
|
||||
"docker-compose" "pass")
|
||||
|
||||
add_yum_repo() (
|
||||
$YUM_CONFIG_MGR --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
||||
)
|
||||
|
||||
update_yum() (
|
||||
$YUM_INSTALL -y yum-utils
|
||||
add_yum_repo
|
||||
)
|
||||
|
||||
update_apt() (
|
||||
$APT update
|
||||
DEBIAN_FRONTEND=noninteractive $APT --yes --force-yes -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade
|
||||
)
|
||||
|
||||
restart_docker_service() (
|
||||
service docker restart
|
||||
)
|
||||
install_yum_packages() (
|
||||
$YUM_INSTALL "${YUM_LIST[@]}" -y
|
||||
)
|
||||
|
||||
install_pip3_packages() (
|
||||
$PIP3_INSTALL docker-compose
|
||||
)
|
||||
|
||||
install_apt_packages() (
|
||||
$APT_INSTALL "${APT_LIST[@]}" -y
|
||||
)
|
||||
|
||||
main() (
|
||||
if [[ -n $WHICH_YUM ]]; then
|
||||
update_yum
|
||||
install_yum_packages
|
||||
install_pip3_packages
|
||||
restart_docker_service
|
||||
elif [[ -n $WHICH_APT ]]; then
|
||||
update_apt
|
||||
install_apt_packages
|
||||
restart_docker_service
|
||||
else
|
||||
echo "Unknown platform. Error while installing the required packages"
|
||||
exit 1
|
||||
fi
|
||||
)
|
||||
|
||||
main
|
@ -3,7 +3,7 @@ terraform {
|
||||
required_providers {
|
||||
metal = {
|
||||
source = "equinix/metal"
|
||||
version = "1.0.0"
|
||||
version = "3.1.0"
|
||||
}
|
||||
null = {
|
||||
source = "hashicorp/null"
|
||||
@ -27,72 +27,9 @@ resource "metal_vlan" "provisioning_vlan" {
|
||||
project_id = var.project_id
|
||||
}
|
||||
|
||||
# Create a device and add it to tf_project_1
|
||||
resource "metal_device" "tink_provisioner" {
|
||||
hostname = "tink-provisioner"
|
||||
plan = var.device_type
|
||||
facilities = [var.facility]
|
||||
operating_system = "ubuntu_18_04"
|
||||
billing_cycle = "hourly"
|
||||
project_id = var.project_id
|
||||
user_data = file("install_package.sh")
|
||||
}
|
||||
|
||||
resource "null_resource" "tink_directory" {
|
||||
connection {
|
||||
type = "ssh"
|
||||
user = var.ssh_user
|
||||
host = metal_device.tink_provisioner.network[0].address
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
"mkdir -p /root/tink/deploy"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = "../../setup.sh"
|
||||
destination = "/root/tink/setup.sh"
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = "../../generate-env.sh"
|
||||
destination = "/root/tink/generate-env.sh"
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = "../../current_versions.sh"
|
||||
destination = "/root/tink/current_versions.sh"
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = "../../deploy"
|
||||
destination = "/root/tink"
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = "nat_interface"
|
||||
destination = "/root/tink/.nat_interface"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
"chmod +x /root/tink/*.sh /root/tink/deploy/tls/*.sh"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
resource "metal_device_network_type" "tink_provisioner_network_type" {
|
||||
device_id = metal_device.tink_provisioner.id
|
||||
type = "hybrid"
|
||||
}
|
||||
|
||||
# Create a device and add it to tf_project_1
|
||||
resource "metal_device" "tink_worker" {
|
||||
count = var.worker_count
|
||||
|
||||
hostname = "tink-worker-${count.index}"
|
||||
hostname = "tink-worker"
|
||||
plan = var.device_type
|
||||
facilities = [var.facility]
|
||||
operating_system = "custom_ipxe"
|
||||
@ -103,12 +40,36 @@ resource "metal_device" "tink_worker" {
|
||||
}
|
||||
|
||||
resource "metal_device_network_type" "tink_worker_network_type" {
|
||||
count = var.worker_count
|
||||
|
||||
device_id = metal_device.tink_worker[count.index].id
|
||||
device_id = metal_device.tink_worker.id
|
||||
type = "layer2-individual"
|
||||
}
|
||||
|
||||
# Attach VLAN to worker
|
||||
resource "metal_port_vlan_attachment" "worker" {
|
||||
depends_on = [metal_device_network_type.tink_worker_network_type]
|
||||
|
||||
device_id = metal_device.tink_worker.id
|
||||
port_name = "eth0"
|
||||
vlan_vnid = metal_vlan.provisioning_vlan.vxlan
|
||||
}
|
||||
|
||||
|
||||
# Create a device and add it to tf_project_1
|
||||
resource "metal_device" "tink_provisioner" {
|
||||
hostname = "tink-provisioner"
|
||||
plan = var.device_type
|
||||
facilities = [var.facility]
|
||||
operating_system = "ubuntu_20_04"
|
||||
billing_cycle = "hourly"
|
||||
project_id = var.project_id
|
||||
user_data = file("setup.sh")
|
||||
}
|
||||
|
||||
resource "metal_device_network_type" "tink_provisioner_network_type" {
|
||||
device_id = metal_device.tink_provisioner.id
|
||||
type = "hybrid"
|
||||
}
|
||||
|
||||
# Attach VLAN to provisioner
|
||||
resource "metal_port_vlan_attachment" "provisioner" {
|
||||
depends_on = [metal_device_network_type.tink_provisioner_network_type]
|
||||
@ -117,40 +78,30 @@ resource "metal_port_vlan_attachment" "provisioner" {
|
||||
vlan_vnid = metal_vlan.provisioning_vlan.vxlan
|
||||
}
|
||||
|
||||
# Attach VLAN to worker
|
||||
resource "metal_port_vlan_attachment" "worker" {
|
||||
count = var.worker_count
|
||||
depends_on = [metal_device_network_type.tink_worker_network_type]
|
||||
|
||||
device_id = metal_device.tink_worker[count.index].id
|
||||
port_name = "eth0"
|
||||
vlan_vnid = metal_vlan.provisioning_vlan.vxlan
|
||||
}
|
||||
|
||||
data "template_file" "worker_hardware_data" {
|
||||
count = var.worker_count
|
||||
template = file("${path.module}/hardware_data.tpl")
|
||||
vars = {
|
||||
id = metal_device.tink_worker[count.index].id
|
||||
facility_code = metal_device.tink_worker[count.index].deployed_facility
|
||||
plan_slug = metal_device.tink_worker[count.index].plan
|
||||
address = "192.168.1.${count.index + 5}"
|
||||
mac = metal_device.tink_worker[count.index].ports[1].mac
|
||||
}
|
||||
}
|
||||
|
||||
resource "null_resource" "hardware_data" {
|
||||
count = var.worker_count
|
||||
depends_on = [null_resource.tink_directory]
|
||||
|
||||
resource "null_resource" "setup" {
|
||||
connection {
|
||||
type = "ssh"
|
||||
user = var.ssh_user
|
||||
host = metal_device.tink_provisioner.network[0].address
|
||||
type = "ssh"
|
||||
user = "root"
|
||||
host = metal_device.tink_provisioner.network[0].address
|
||||
private_key = file("~/.ssh/id_rsa")
|
||||
}
|
||||
|
||||
# need to tar the compose directory because the 'provisioner "file"' does not preserve file permissions
|
||||
provisioner "local-exec" {
|
||||
command = "cd ../ && tar zcvf compose.tar.gz compose"
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
content = data.template_file.worker_hardware_data[count.index].rendered
|
||||
destination = "/root/tink/deploy/hardware-data-${count.index}.json"
|
||||
source = "../compose.tar.gz"
|
||||
destination = "/root/compose.tar.gz"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
"cd /root && tar zxvf /root/compose.tar.gz -C /root/sandbox",
|
||||
"cd /root/sandbox/compose && TINKERBELL_CLIENT_MAC=${metal_device.tink_worker.ports[1].mac} TINKERBELL_TEMPLATE_MANIFEST=/manifests/template/ubuntu-equinix-metal.yaml TINKERBELL_HARDWARE_MANIFEST=/manifests/hardware/hardware-equinix-metal.json docker-compose up -d"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
bond0
|
@ -1,15 +1,7 @@
|
||||
output "provisioner_dns_name" {
|
||||
value = "${split("-", metal_device.tink_provisioner.id)[0]}.packethost.net"
|
||||
}
|
||||
|
||||
output "provisioner_ip" {
|
||||
value = metal_device.tink_provisioner.network[0].address
|
||||
}
|
||||
|
||||
output "worker_mac_addr" {
|
||||
value = formatlist("%s", metal_device.tink_worker[*].ports[1].mac)
|
||||
}
|
||||
|
||||
output "worker_sos" {
|
||||
value = formatlist("%s@sos.%s.platformequinix.com", metal_device.tink_worker[*].id, metal_device.tink_worker[*].deployed_facility)
|
||||
value = formatlist("%s@sos.%s.platformequinix.com", metal_device.tink_worker[*].id, metal_device.tink_worker.deployed_facility)
|
||||
}
|
||||
|
66
deploy/terraform/setup.sh
Executable file
66
deploy/terraform/setup.sh
Executable file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -xo pipefail
|
||||
|
||||
install_docker() {
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
||||
update_apt
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y apt-transport-https ca-certificates curl gnupg-agent gnupg2 software-properties-common docker-ce docker-ce-cli containerd.io
|
||||
}
|
||||
|
||||
install_docker_compose() {
|
||||
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
}
|
||||
|
||||
update_apt() (
|
||||
$APT update
|
||||
DEBIAN_FRONTEND=noninteractive $APT --yes --force-yes -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade
|
||||
)
|
||||
|
||||
restart_docker_service() (
|
||||
service docker restart
|
||||
)
|
||||
|
||||
# get_second_interface_from_bond0 returns the second interface of the bond0 interface
|
||||
get_second_interface_from_bond0() {
|
||||
local return_value
|
||||
return_value=$(cut -d' ' -f2 /sys/class/net/bond0/bonding/slaves | xargs)
|
||||
echo "${return_value}"
|
||||
}
|
||||
|
||||
# setup_layer2_network removes the second interface from bond0 and uses it for the layer2 network
|
||||
# https://metal.equinix.com/developers/docs/layer2-networking/hybrid-unbonded-mode/
|
||||
setup_layer2_network() {
|
||||
local layer2_interface="$1"
|
||||
#local ip_addr="$2"
|
||||
ifenslave -d bond0 "${layer2_interface}"
|
||||
#ip addr add ${ip_addr}/24 dev "${layer2_interface}"
|
||||
ip addr add 192.168.50.4/24 dev "${layer2_interface}"
|
||||
ip link set dev "${layer2_interface}" up
|
||||
}
|
||||
|
||||
# make_host_gw_server makes the host a gateway server
|
||||
make_host_gw_server() {
|
||||
local incoming_interface="$1"
|
||||
local outgoing_interface="$2"
|
||||
iptables -t nat -A POSTROUTING -o "${outgoing_interface}" -j MASQUERADE
|
||||
iptables -A FORWARD -i "${outgoing_interface}" -o "${incoming_interface}" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i "${incoming_interface}" -o "${outgoing_interface}" -j ACCEPT
|
||||
}
|
||||
|
||||
main() (
|
||||
#local provisioner_ip="$1"
|
||||
|
||||
install_docker
|
||||
install_docker_compose
|
||||
restart_docker_service
|
||||
mkdir -p /root/sandbox/compose
|
||||
local layer2_interface
|
||||
layer2_interface="$(get_second_interface_from_bond0)"
|
||||
setup_layer2_network "${layer2_interface}" #"${provisioner_ip}"
|
||||
make_host_gw_server "${layer2_interface}" "bond0"
|
||||
)
|
||||
|
||||
main #"$1"
|
@ -8,11 +8,6 @@ variable "project_id" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "worker_count" {
|
||||
description = "Number of Workers"
|
||||
type = number
|
||||
default = 1
|
||||
}
|
||||
variable "facility" {
|
||||
description = "Packet facility to provision in"
|
||||
type = string
|
||||
@ -24,9 +19,3 @@ variable "device_type" {
|
||||
description = "Type of device to provision"
|
||||
default = "c3.small.x86"
|
||||
}
|
||||
|
||||
variable "ssh_user" {
|
||||
description = "Username that will be used to transfer file from your local environment to the provisioner"
|
||||
type = string
|
||||
default = "root"
|
||||
}
|
||||
|
Reference in New Issue
Block a user