Compare commits
8 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be9259918c | ||
|
|
c12b9d763a | ||
|
|
0696ad874a | ||
|
|
9e0f88dec7 | ||
|
|
cda1fde1ae | ||
|
|
c736f367b0 | ||
|
|
7d4bb621e6 | ||
|
|
67f2edbc4d |
|
|
@ -26,56 +26,15 @@ resource "null_resource" "stage_talos_image" {
|
||||||
storage = var.talos_image_storage
|
storage = var.talos_image_storage
|
||||||
talos_version = var.talos_version
|
talos_version = var.talos_version
|
||||||
filename = local.node_iso_filenames[each.key]
|
filename = local.node_iso_filenames[each.key]
|
||||||
|
stager = filesha256("${path.module}/scripts/stage_talos_image.py")
|
||||||
}
|
}
|
||||||
|
|
||||||
provisioner "local-exec" {
|
provisioner "local-exec" {
|
||||||
interpreter = ["python", "-c"]
|
interpreter = ["python", "-c"]
|
||||||
command = "import subprocess; subprocess.run(['python', r'${path.module}/scripts/stage_talos_image.py', '--api-url', '${var.proxmox_api_url}', '--api-token', '${var.proxmox_api_token}', '--node', '${self.triggers.proxmox_node}', '--storage', '${var.talos_image_storage}', '--image-url', '${local.talos_iso_download_url}', '--filename', '${self.triggers.filename}'], check=True)"
|
command = "import subprocess; subprocess.run(['python', r'${path.module}/scripts/stage_talos_image.py', '--api-url', '${var.proxmox_api_url}', '--api-token', '${var.proxmox_api_token}', '--node', '${self.triggers.proxmox_node}', '--storage', '${var.talos_image_storage}', '--image-url', '${local.talos_iso_download_url}', '--filename', '${self.triggers.filename}', '--force'], check=True)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "proxmox_virtual_environment_file" "nocloud_network_config" {
|
|
||||||
for_each = { for node in var.nodes : node.name => node }
|
|
||||||
|
|
||||||
node_name = lookup(each.value, "proxmox_node", var.proxmox_node)
|
|
||||||
datastore_id = var.talos_image_storage
|
|
||||||
content_type = "snippets"
|
|
||||||
|
|
||||||
source_raw {
|
|
||||||
data = local_file.metal_network_config[each.key].content
|
|
||||||
file_name = "${each.key}-network-config.yaml"
|
|
||||||
}
|
|
||||||
|
|
||||||
depends_on = [local_file.metal_network_config]
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "proxmox_virtual_environment_file" "nocloud_metadata" {
|
|
||||||
for_each = { for node in var.nodes : node.name => node }
|
|
||||||
|
|
||||||
node_name = lookup(each.value, "proxmox_node", var.proxmox_node)
|
|
||||||
datastore_id = var.talos_image_storage
|
|
||||||
content_type = "snippets"
|
|
||||||
|
|
||||||
source_raw {
|
|
||||||
data = "instance-id: ${each.key}\nlocal-hostname: ${each.key}\n"
|
|
||||||
file_name = "${each.key}-meta-data.yaml"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "proxmox_virtual_environment_file" "nocloud_user_data" {
|
|
||||||
for_each = { for node in var.nodes : node.name => node }
|
|
||||||
|
|
||||||
node_name = lookup(each.value, "proxmox_node", var.proxmox_node)
|
|
||||||
datastore_id = var.talos_image_storage
|
|
||||||
content_type = "snippets"
|
|
||||||
|
|
||||||
source_raw {
|
|
||||||
data = "#cloud-config\n"
|
|
||||||
file_name = "${each.key}-user-data.yaml"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Create all required network bridges
|
# Create all required network bridges
|
||||||
resource "proxmox_virtual_environment_network_linux_bridge" "cluster_bridge" {
|
resource "proxmox_virtual_environment_network_linux_bridge" "cluster_bridge" {
|
||||||
for_each = local.unique_bridges
|
for_each = local.unique_bridges
|
||||||
|
|
@ -162,21 +121,29 @@ resource "proxmox_virtual_environment_vm" "vm" {
|
||||||
|
|
||||||
# Talos reads this Proxmox-generated cidata disk through its NoCloud platform.
|
# Talos reads this Proxmox-generated cidata disk through its NoCloud platform.
|
||||||
initialization {
|
initialization {
|
||||||
datastore_id = var.talos_image_storage
|
datastore_id = var.disk_storage
|
||||||
interface = "ide3"
|
interface = "ide3"
|
||||||
type = "nocloud"
|
type = "nocloud"
|
||||||
meta_data_file_id = proxmox_virtual_environment_file.nocloud_metadata[each.key].id
|
|
||||||
network_data_file_id = proxmox_virtual_environment_file.nocloud_network_config[each.key].id
|
dynamic "ip_config" {
|
||||||
user_data_file_id = proxmox_virtual_environment_file.nocloud_user_data[each.key].id
|
for_each = each.value.ip != null ? [each.value] : []
|
||||||
|
content {
|
||||||
|
ipv4 {
|
||||||
|
address = "${ip_config.value.ip}/${split("/", ip_config.value.network_cidr)[1]}"
|
||||||
|
gateway = ip_config.value.gateway
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dns {
|
||||||
|
servers = var.dns_servers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ensure image staging and bridge setup complete before VMs
|
# Ensure image staging and bridge setup complete before VMs
|
||||||
depends_on = [
|
depends_on = [
|
||||||
proxmox_virtual_environment_network_linux_bridge.cluster_bridge,
|
proxmox_virtual_environment_network_linux_bridge.cluster_bridge,
|
||||||
null_resource.stage_talos_image,
|
null_resource.stage_talos_image,
|
||||||
proxmox_virtual_environment_file.nocloud_network_config,
|
|
||||||
proxmox_virtual_environment_file.nocloud_metadata,
|
|
||||||
proxmox_virtual_environment_file.nocloud_user_data,
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,18 @@ def api_request(base_url, token, method, path, data=None):
|
||||||
return json.loads(response.read().decode())
|
return json.loads(response.read().decode())
|
||||||
|
|
||||||
|
|
||||||
def ensure_image(base_url, token, node, storage, image_url, filename):
|
def ensure_image(base_url, token, node, storage, image_url, filename, force=False):
|
||||||
content_path = f"/api2/json/nodes/{node}/storage/{storage}/content"
|
content_path = f"/api2/json/nodes/{node}/storage/{storage}/content"
|
||||||
response = api_request(base_url, token, "GET", content_path)
|
response = api_request(base_url, token, "GET", content_path)
|
||||||
|
|
||||||
for item in response.get("data", []):
|
for item in response.get("data", []):
|
||||||
if item.get("volid", "").endswith(filename):
|
if item.get("volid", "").endswith(filename):
|
||||||
return filename, False
|
if not force:
|
||||||
|
return filename, False
|
||||||
|
volume_path = urllib.parse.quote(f"iso/{filename}", safe="")
|
||||||
|
task = api_request(base_url, token, "DELETE", f"{content_path}/{volume_path}")
|
||||||
|
wait_for_task(base_url, token, node, task.get("data"))
|
||||||
|
break
|
||||||
|
|
||||||
download_path = f"/api2/json/nodes/{node}/storage/{storage}/download-url"
|
download_path = f"/api2/json/nodes/{node}/storage/{storage}/download-url"
|
||||||
task = api_request(base_url, token, "POST", download_path, {
|
task = api_request(base_url, token, "POST", download_path, {
|
||||||
|
|
@ -82,10 +87,11 @@ def main():
|
||||||
parser.add_argument("--storage", required=True)
|
parser.add_argument("--storage", required=True)
|
||||||
parser.add_argument("--image-url", required=True)
|
parser.add_argument("--image-url", required=True)
|
||||||
parser.add_argument("--filename", required=True)
|
parser.add_argument("--filename", required=True)
|
||||||
|
parser.add_argument("--force", action="store_true")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
filename, downloaded = ensure_image(args.api_url, args.api_token, args.node, args.storage, args.image_url, args.filename)
|
filename, downloaded = ensure_image(args.api_url, args.api_token, args.node, args.storage, args.image_url, args.filename, args.force)
|
||||||
except urllib.error.HTTPError as exc:
|
except urllib.error.HTTPError as exc:
|
||||||
sys.stderr.write(exc.read().decode())
|
sys.stderr.write(exc.read().decode())
|
||||||
raise
|
raise
|
||||||
|
|
|
||||||
|
|
@ -58,16 +58,6 @@ resource "local_file" "talconfig" {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "local_file" "metal_network_config" {
|
|
||||||
for_each = { for node in var.nodes : node.name => node }
|
|
||||||
|
|
||||||
filename = "${path.module}/../generated/metal-network/${each.key}.yaml"
|
|
||||||
content = templatefile("${path.module}/templates/talos-metal-network.yaml.tpl", {
|
|
||||||
node = each.value
|
|
||||||
dns_servers = var.dns_servers
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
# (The output block is already correct from the last fix)
|
# (The output block is already correct from the last fix)
|
||||||
output "node_organization" {
|
output "node_organization" {
|
||||||
description = "How your nodes are organized for Talos configuration"
|
description = "How your nodes are organized for Talos configuration"
|
||||||
|
|
@ -85,4 +75,4 @@ output "node_organization" {
|
||||||
name = node.name, ip = node.networks[0].ip, tags = lookup(node, "tags", [])
|
name = node.name, ip = node.networks[0].ip, tags = lookup(node, "tags", [])
|
||||||
} if node.role == "worker" && contains(lookup(node, "tags", []), "gpu")]
|
} if node.role == "worker" && contains(lookup(node, "tags", []), "gpu")]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,13 @@ nodes:
|
||||||
machineSpec:
|
machineSpec:
|
||||||
mode: metal
|
mode: metal
|
||||||
arch: amd64
|
arch: amd64
|
||||||
talosImageURL: "factory.talos.dev/installer/${talos_factory_schematic_id}/${talos_version}"
|
talosImageURL: "factory.talos.dev/installer/${talos_factory_schematic_id}"
|
||||||
|
patches:
|
||||||
|
- |-
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: LinkConfig
|
||||||
|
name: eth0
|
||||||
|
up: true
|
||||||
nodeLabels:
|
nodeLabels:
|
||||||
node-role.kubernetes.io/control-plane: ""
|
node-role.kubernetes.io/control-plane: ""
|
||||||
cluster.local/node-pool: "control-plane"
|
cluster.local/node-pool: "control-plane"
|
||||||
|
|
@ -59,7 +65,13 @@ nodes:
|
||||||
machineSpec:
|
machineSpec:
|
||||||
mode: metal
|
mode: metal
|
||||||
arch: amd64
|
arch: amd64
|
||||||
talosImageURL: "factory.talos.dev/installer/${talos_factory_schematic_id}/${talos_version}"
|
talosImageURL: "factory.talos.dev/installer/${talos_factory_schematic_id}"
|
||||||
|
patches:
|
||||||
|
- |-
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: LinkConfig
|
||||||
|
name: eth0
|
||||||
|
up: true
|
||||||
nodeLabels:
|
nodeLabels:
|
||||||
node-role.kubernetes.io/worker: ""
|
node-role.kubernetes.io/worker: ""
|
||||||
cluster.local/node-pool: "compute"
|
cluster.local/node-pool: "compute"
|
||||||
|
|
@ -92,7 +104,13 @@ nodes:
|
||||||
machineSpec:
|
machineSpec:
|
||||||
mode: metal
|
mode: metal
|
||||||
arch: amd64
|
arch: amd64
|
||||||
talosImageURL: "factory.talos.dev/installer/${talos_factory_schematic_id}/${talos_version}"
|
talosImageURL: "factory.talos.dev/installer/${talos_factory_schematic_id}"
|
||||||
|
patches:
|
||||||
|
- |-
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: LinkConfig
|
||||||
|
name: eth0
|
||||||
|
up: true
|
||||||
nodeLabels:
|
nodeLabels:
|
||||||
node-role.kubernetes.io/worker: ""
|
node-role.kubernetes.io/worker: ""
|
||||||
cluster.local/node-pool: "storage"
|
cluster.local/node-pool: "storage"
|
||||||
|
|
@ -125,7 +143,13 @@ nodes:
|
||||||
machineSpec:
|
machineSpec:
|
||||||
mode: metal
|
mode: metal
|
||||||
arch: amd64
|
arch: amd64
|
||||||
talosImageURL: "factory.talos.dev/installer/${talos_factory_schematic_id}/${talos_version}"
|
talosImageURL: "factory.talos.dev/installer/${talos_factory_schematic_id}"
|
||||||
|
patches:
|
||||||
|
- |-
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: LinkConfig
|
||||||
|
name: eth0
|
||||||
|
up: true
|
||||||
nodeLabels:
|
nodeLabels:
|
||||||
node-role.kubernetes.io/worker: ""
|
node-role.kubernetes.io/worker: ""
|
||||||
cluster.local/node-pool: "gpu"
|
cluster.local/node-pool: "gpu"
|
||||||
|
|
@ -195,4 +219,4 @@ controlPlane:
|
||||||
- ${network_cidr}
|
- ${network_cidr}
|
||||||
proxy: {}
|
proxy: {}
|
||||||
discovery:
|
discovery:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
version: 2
|
|
||||||
ethernets:
|
|
||||||
%{ for i, net in node.networks ~}
|
|
||||||
eth${i}:
|
|
||||||
match:
|
|
||||||
macaddress: "${net.mac_address}"
|
|
||||||
dhcp4: false
|
|
||||||
%{ if i == 0 && net.vlan_id == 0 ~}
|
|
||||||
addresses:
|
|
||||||
- ${net.ip}/${split("/", net.cidr)[1]}
|
|
||||||
gateway4: ${net.gateway}
|
|
||||||
nameservers:
|
|
||||||
addresses:
|
|
||||||
%{ for dns in dns_servers ~}
|
|
||||||
- ${dns}
|
|
||||||
%{ endfor ~}
|
|
||||||
%{ endif ~}
|
|
||||||
%{ endfor ~}
|
|
||||||
%{ if node.networks[0].vlan_id > 0 ~}
|
|
||||||
vlans:
|
|
||||||
eth0.${node.networks[0].vlan_id}:
|
|
||||||
id: ${node.networks[0].vlan_id}
|
|
||||||
link: eth0
|
|
||||||
addresses:
|
|
||||||
- ${node.networks[0].ip}/${split("/", node.networks[0].cidr)[1]}
|
|
||||||
gateway4: ${node.networks[0].gateway}
|
|
||||||
nameservers:
|
|
||||||
addresses:
|
|
||||||
%{ for dns in dns_servers ~}
|
|
||||||
- ${dns}
|
|
||||||
%{ endfor ~}
|
|
||||||
%{ endif ~}
|
|
||||||
Loading…
Reference in a new issue