Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 0 additions & 90 deletions terraform/devnet-0/.terraform.lock.hcl

This file was deleted.

2 changes: 1 addition & 1 deletion terraform/devnet-0/ansible_inventory.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ethereum_network_name=${ethereum_network_name}
[${replace(gid, "-", "_")}]
%{ for key, host in hosts ~}
%{ if host.group == gid ~}
${host.hostname} ansible_host=${host.ip} ipv6=${host.ipv6} cloud=${host.cloud} cloud_region=${host.region} ethereum_node_cl_supernode_enabled=${title(host.supernode)} %{ if tonumber(host.validator_end) > 0 }validator_start=${host.validator_start} validator_end=${host.validator_end}%{ endif }
${host.hostname} ansible_host=${host.ip} ipv6=${host.ipv6} cloud=${host.cloud} cloud_region=${host.region} arch=${host.arch} ethereum_node_cl_supernode_enabled=${title(host.supernode)} %{ if tonumber(host.validator_end) > 0 }validator_start=${host.validator_start} validator_end=${host.validator_end}%{ endif }
%{ endif ~}
%{ endfor ~}
%{ if gid == "lighthouse-reth" ~}
Expand Down
69 changes: 41 additions & 28 deletions terraform/devnet-0/cloudflare.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,52 @@ data "cloudflare_zone" "default" {
name = "ethpandaops.io"
}

locals {
# Combine bootnodes from both providers
bootnodes = merge(
{
for vm in local.digitalocean_vms : vm.id => {
name = vm.name
ipv4 = digitalocean_droplet.main[vm.id].ipv4_address
ipv6 = try(digitalocean_droplet.main[vm.id].ipv6_address, null)
} if can(regex("bootnode", vm.name))
},
{
for vm in local.hcloud_vms : vm.id => {
name = vm.name
ipv4 = hcloud_server.main[vm.id].ipv4_address
ipv6 = try(hcloud_server.main[vm.id].ipv6_address, null)
} if can(regex("bootnode", vm.name))
}
)
}

resource "cloudflare_record" "server_record_v4" {
for_each = {
for vm in local.digitalocean_vms : "${vm.id}" => vm if can(regex("bootnode", vm.name))
}
zone_id = data.cloudflare_zone.default.id
name = "${each.value.name}.${var.ethereum_network}"
type = "A"
value = digitalocean_droplet.main[each.value.id].ipv4_address
proxied = false
ttl = 120
for_each = local.bootnodes
zone_id = data.cloudflare_zone.default.id
name = "${each.value.name}.${var.ethereum_network}"
type = "A"
value = each.value.ipv4
proxied = false
ttl = 120
}

resource "cloudflare_record" "server_record_v6" {
for_each = {
for vm in local.digitalocean_vms : "${vm.id}" => vm if vm.ipv6 && can(regex("bootnode", vm.name))
}
zone_id = data.cloudflare_zone.default.id
name = "${each.value.name}.${var.ethereum_network}"
type = "AAAA"
value = digitalocean_droplet.main[each.value.id].ipv6_address
proxied = false
ttl = 120
for_each = { for k, v in local.bootnodes : k => v if v.ipv6 != null }
zone_id = data.cloudflare_zone.default.id
name = "${each.value.name}.${var.ethereum_network}"
type = "AAAA"
value = each.value.ipv6
proxied = false
ttl = 120
}

resource "cloudflare_record" "server_record_ns" {
for_each = {
for vm in local.digitalocean_vms : "${vm.id}" => vm if can(regex("bootnode", vm.name))
}
zone_id = data.cloudflare_zone.default.id
name = "srv.${var.ethereum_network}"
type = "NS"
value = "${each.value.name}.${var.ethereum_network}.${data.cloudflare_zone.default.name}"
proxied = false
ttl = 120
for_each = local.bootnodes
zone_id = data.cloudflare_zone.default.id
name = "srv.${var.ethereum_network}"
type = "NS"
value = "${each.value.name}.${var.ethereum_network}.${data.cloudflare_zone.default.name}"
proxied = false
ttl = 120
}

170 changes: 48 additions & 122 deletions terraform/devnet-0/digitalocean.tf
Original file line number Diff line number Diff line change
Expand Up @@ -40,40 +40,45 @@ variable "digitalocean_regions" {
// LOCALS
////////////////////////////////////////////////////////////////////////////////////////
locals {
base_cidr_block = var.base_cidr_block
digitalocean_vpcs = {
for region in var.digitalocean_regions : region => {
name = "${var.ethereum_network}-${region}"
region = region
ip_range = cidrsubnet(local.base_cidr_block, 8, index(var.digitalocean_regions, region))
ip_range = cidrsubnet(var.base_cidr_block, 8, index(var.digitalocean_regions, region))
}
}
}

locals {
digitalocean_vm_groups = flatten([
for vm_group in local.vm_groups :
vm_group.count > 0 ? [
for i in range(0, vm_group.count) : {
group_name = "${vm_group.name}"
id = "${vm_group.name}-${i + 1}"
for node in local.digitalocean_nodes : [
for i in range(0, node.count) : {
group_name = node.name
id = "${node.name}-${node.start_index + i + 1}"
vms = {
"${i + 1}" = {
tags = join(",", compact([
"group_name:${vm_group.name}",
"val_start:${vm_group.validator_start + (i * (vm_group.validator_end - vm_group.validator_start) / vm_group.count)}",
"val_end:${min(vm_group.validator_start + ((i + 1) * (vm_group.validator_end - vm_group.validator_start) / vm_group.count), vm_group.validator_end)}",
"supernode:${try(vm_group.supernode, can(regex("(super|bootnode|mev)", vm_group.name))) ? "True" : "False"}",
can(regex("bootnode", vm_group.name)) ? "bootnode:${var.ethereum_network}" : null,
can(regex("mev-relay", vm_group.name)) ? "mev-relay:${var.ethereum_network}" : null
]))
region = try(vm_group.region, var.digitalocean_regions[i % length(var.digitalocean_regions)])
size = try(vm_group.size, can(regex("(super|bootnode)", vm_group.name)) ? var.digitalocean_supernode_size : var.digitalocean_fullnode_size)
ipv6 = try(vm_group.ipv6, true)
# Validator range for this instance
val_start = node.validator_start + (i * (node.validator_end - node.validator_start) / node.count)
val_end = min(
node.validator_start + ((i + 1) * (node.validator_end - node.validator_start) / node.count),
node.validator_end
)
validator_count = node.count > 0 ? (node.validator_end - node.validator_start) / node.count : 0

# Supernode: explicit > bootnode/mev > validator_count >= 128
supernode = (
node.supernode != null ? node.supernode :
can(regex("(bootnode|mev)", node.name)) ? true :
(node.count > 0 ? (node.validator_end - node.validator_start) / node.count >= 128 : false)
)

region = node.region != null ? node.region : var.digitalocean_regions[i % length(var.digitalocean_regions)]
ipv6 = node.ipv6
arch = "amd64"
}
}
}
] : []
]
])
}

Expand All @@ -86,30 +91,34 @@ locals {
"EthNetwork:${var.ethereum_network}"
]

# flatten vm_groups so that we can use it with for_each()
digitalocean_vms = flatten([
for group in local.digitalocean_vm_groups : [
for vm_key, vm in group.vms : {
id = "${group.id}"
group_key = "${group.group_name}"
id = group.id
group_key = group.group_name
vm_key = vm_key

name = try(vm.name, "${group.id}")
ssh_keys = try(vm.ssh_keys, [data.digitalocean_ssh_key.main.fingerprint])
region = try(vm.region, try(group.region, local.digitalocean_default_region))
image = try(vm.image, local.digitalocean_default_image)
size = try(vm.size, local.digitalocean_default_size)
resize_disk = try(vm.resize_disk, true)
monitoring = try(vm.monitoring, true)
backups = try(vm.backups, false)
ipv6 = try(vm.ipv6, true)
ansible_vars = try(vm.ansible_vars, null)
vpc_uuid = try(vm.vpc_uuid, try(
digitalocean_vpc.main[vm.region].id,
digitalocean_vpc.main[try(group.region, local.digitalocean_default_region)].id
))

tags = concat(local.digitalocean_global_tags, try(split(",", group.tags), []), try(split(",", vm.tags), []))
name = group.id
ssh_keys = [data.digitalocean_ssh_key.main.fingerprint]
region = vm.region
image = local.digitalocean_default_image
size = vm.supernode ? var.digitalocean_supernode_size : var.digitalocean_fullnode_size
resize_disk = true
monitoring = true
backups = false
ipv6 = vm.ipv6
vpc_uuid = digitalocean_vpc.main[vm.region].id

tags = concat(local.digitalocean_global_tags, [
"group_name:${group.group_name}",
"val_start:${vm.val_start}",
"val_end:${vm.val_end}",
"supernode:${vm.supernode ? "True" : "False"}",
"arch:${vm.arch}",
], compact([
can(regex("bootnode", group.group_name)) ? "bootnode:${var.ethereum_network}" : null,
can(regex("mev-relay", group.group_name)) ? "mev-relay:${var.ethereum_network}" : null
]))
}
]
])
Expand All @@ -136,7 +145,7 @@ resource "digitalocean_vpc" "main" {

resource "digitalocean_droplet" "main" {
for_each = {
for vm in local.digitalocean_vms : "${vm.id}" => vm
for vm in local.digitalocean_vms : vm.id => vm
}
name = "${var.ethereum_network}-${each.value.name}"
region = each.value.region
Expand All @@ -156,86 +165,3 @@ resource "digitalocean_project_resources" "droplets" {
project = data.digitalocean_project.main.id
resources = [each.value.urn]
}



////////////////////////////////////////////////////////////////////////////////////////
// GENERATED FILES AND OUTPUTS
////////////////////////////////////////////////////////////////////////////////////////

resource "local_file" "ansible_inventory" {
content = templatefile("ansible_inventory.tmpl",
{
ethereum_network_name = "${var.ethereum_network}"
groups = merge(
{ for group in local.digitalocean_vm_groups : "${group.group_name}" => true... },
)
hosts = merge(
{
for key, server in digitalocean_droplet.main : "do.${key}" => {
ip = "${server.ipv4_address}"
ipv6 = try(server.ipv6_address, "none")
group = try([for tag in tolist(server.tags) : split(":", tag)[1] if can(regex("^group_name:", tag))][0], "unknown")
validator_start = try([for tag in tolist(server.tags) : split(":", tag)[1] if can(regex("^val_start:", tag))][0], 0)
validator_end = try([for tag in tolist(server.tags) : split(":", tag)[1] if can(regex("^val_end:", tag))][0], 0)
supernode = try(title([for tag in tolist(server.tags) : split(":", tag)[1] if can(regex("^supernode:", tag))][0]), "undefined")
tags = "${server.tags}"
hostname = "${split(".", key)[0]}"
cloud = "digitalocean"
region = "${server.region}"
}
}
)
}
)
filename = "../../ansible/inventories/devnet-0/inventory.ini"
}

locals {
ssh_config_path = pathexpand("~/.ssh/config.d/ssh_config.${var.ethereum_network}.digitalocean")
}

resource "local_file" "ssh_config" {
content = templatefile("${path.module}/ssh_config.tmpl",
{
ethereum_network = var.ethereum_network
hosts = merge(
{
for key, server in digitalocean_droplet.main : "${var.ethereum_network}-${key}" => {
hostname = server.ipv4_address
private_ip = server.ipv4_address_private
name = key
user = "devops"
}
}
)
}
)
filename = local.ssh_config_path

depends_on = [digitalocean_droplet.main]

lifecycle {
create_before_destroy = true
}
}

# Ensure cleanup on destroy
resource "null_resource" "ssh_config_cleanup" {
triggers = {
ssh_config_path = local.ssh_config_path
}

# This provisioner runs on destroy
provisioner "local-exec" {
when = destroy
command = "rm -f ${self.triggers.ssh_config_path} || true"
}

depends_on = [local_file.ssh_config]
}

output "ssh_config_file" {
value = "SSH config generated at: ${local.ssh_config_path}"
description = "Path to the generated SSH config file"
}
Loading