mirror of
https://github.com/kubernetes-sigs/kubespray.git
synced 2026-10-31 14:36:20 -02:30
Add contrib/terraform/opennebula: provision Kubespray VMs on OpenNebula (#13390)
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
locals {
|
||||
masters = {
|
||||
for name, machine in var.machines :
|
||||
name => machine
|
||||
if machine.node_type == "master"
|
||||
}
|
||||
workers = {
|
||||
for name, machine in var.machines :
|
||||
name => machine
|
||||
if machine.node_type == "worker"
|
||||
}
|
||||
context = {
|
||||
NETWORK = "YES"
|
||||
SET_HOSTNAME = "$NAME"
|
||||
SSH_PUBLIC_KEY = join("\n", var.ssh_public_keys)
|
||||
}
|
||||
node_network_id = var.network_reservation_size > 0 ? opennebula_virtual_network.reservation[0].id : var.network_id
|
||||
}
|
||||
|
||||
# Optional reservation carved out of the parent network (one AR only —
|
||||
# provider issue #625)
|
||||
resource "opennebula_virtual_network" "reservation" {
|
||||
count = var.network_reservation_size > 0 ? 1 : 0
|
||||
name = "${var.prefix}-reservation"
|
||||
reservation_vnet = var.network_id
|
||||
reservation_size = var.network_reservation_size
|
||||
reservation_first_ip = var.network_reservation_first_ip != "" ? var.network_reservation_first_ip : null
|
||||
reservation_ar_id = var.network_reservation_ar_id
|
||||
|
||||
lifecycle {
|
||||
precondition {
|
||||
condition = var.network_reservation_size >= length(var.machines)
|
||||
error_message = "network_reservation_size must be at least the number of machines (each node leases one address from the reservation)."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Optional shared non-persistent DATABLOCK image; every VM attaching it gets
|
||||
# its own clone, deleted together with the VM
|
||||
data "opennebula_datastore" "image" {
|
||||
count = var.additional_disk_size > 0 ? 1 : 0
|
||||
name = var.image_datastore_name
|
||||
|
||||
lifecycle {
|
||||
precondition {
|
||||
condition = var.image_datastore_name != ""
|
||||
error_message = "image_datastore_name must be set when additional_disk_size > 0."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "opennebula_image" "extra_disk" {
|
||||
count = var.additional_disk_size > 0 ? 1 : 0
|
||||
name = "${var.prefix}-extra-disk"
|
||||
datastore_id = data.opennebula_datastore.image[0].id
|
||||
type = "DATABLOCK"
|
||||
size = var.additional_disk_size
|
||||
persistent = false
|
||||
permissions = "600"
|
||||
}
|
||||
|
||||
# Anti-affinity: spread control-plane VMs across hosts
|
||||
resource "opennebula_virtual_machine_group" "cluster" {
|
||||
count = var.masters_anti_affinity ? 1 : 0
|
||||
name = "${var.prefix}-vm-group"
|
||||
|
||||
role {
|
||||
name = "master"
|
||||
policy = "ANTI_AFFINED"
|
||||
}
|
||||
}
|
||||
|
||||
resource "opennebula_virtual_machine" "master" {
|
||||
for_each = local.masters
|
||||
|
||||
name = "${var.prefix}-${each.key}"
|
||||
template_id = var.template_id
|
||||
cpu = var.master_cpu
|
||||
vcpu = var.master_vcpu
|
||||
memory = var.master_memory
|
||||
|
||||
context = local.context
|
||||
|
||||
nic {
|
||||
model = "virtio"
|
||||
network_id = local.node_network_id
|
||||
ip = each.value.ip != "" ? each.value.ip : null
|
||||
}
|
||||
|
||||
# Any disk block replaces ALL of the template's disks (provider merge
|
||||
# semantics), so the OS disk must be re-declared whenever another disk
|
||||
# block is emitted.
|
||||
dynamic "disk" {
|
||||
for_each = var.master_disk_size > 0 || var.additional_disk_size > 0 ? [1] : []
|
||||
content {
|
||||
image_id = var.template_disk_image_id
|
||||
size = var.master_disk_size > 0 ? var.master_disk_size : (var.template_disk_size > 0 ? var.template_disk_size : null)
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "disk" {
|
||||
for_each = var.additional_disk_size > 0 ? [1] : []
|
||||
content {
|
||||
image_id = opennebula_image.extra_disk[0].id
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "vmgroup" {
|
||||
for_each = var.masters_anti_affinity ? [1] : []
|
||||
content {
|
||||
vmgroup_id = opennebula_virtual_machine_group.cluster[0].id
|
||||
role = "master"
|
||||
}
|
||||
}
|
||||
|
||||
timeouts {
|
||||
create = var.vm_create_timeout
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
precondition {
|
||||
condition = (var.master_disk_size <= 0 && var.additional_disk_size <= 0) || var.template_disk_image_id != null
|
||||
error_message = "master_disk_size/additional_disk_size require the template's first disk to reference its image by numeric IMAGE_ID (templates referencing the image by name are not readable through the provider data source)."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "opennebula_virtual_machine" "worker" {
|
||||
for_each = local.workers
|
||||
|
||||
name = "${var.prefix}-${each.key}"
|
||||
template_id = var.template_id
|
||||
cpu = var.worker_cpu
|
||||
vcpu = var.worker_vcpu
|
||||
memory = var.worker_memory
|
||||
|
||||
context = local.context
|
||||
|
||||
nic {
|
||||
model = "virtio"
|
||||
network_id = local.node_network_id
|
||||
ip = each.value.ip != "" ? each.value.ip : null
|
||||
}
|
||||
|
||||
# Any disk block replaces ALL of the template's disks (provider merge
|
||||
# semantics), so the OS disk must be re-declared whenever another disk
|
||||
# block is emitted.
|
||||
dynamic "disk" {
|
||||
for_each = var.worker_disk_size > 0 || var.additional_disk_size > 0 ? [1] : []
|
||||
content {
|
||||
image_id = var.template_disk_image_id
|
||||
size = var.worker_disk_size > 0 ? var.worker_disk_size : (var.template_disk_size > 0 ? var.template_disk_size : null)
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "disk" {
|
||||
for_each = var.additional_disk_size > 0 ? [1] : []
|
||||
content {
|
||||
image_id = opennebula_image.extra_disk[0].id
|
||||
}
|
||||
}
|
||||
|
||||
timeouts {
|
||||
create = var.vm_create_timeout
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
precondition {
|
||||
condition = (var.worker_disk_size <= 0 && var.additional_disk_size <= 0) || var.template_disk_image_id != null
|
||||
error_message = "worker_disk_size/additional_disk_size require the template's first disk to reference its image by numeric IMAGE_ID (templates referencing the image by name are not readable through the provider data source)."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
output "master_ip" {
|
||||
value = {
|
||||
for name, vm in opennebula_virtual_machine.master :
|
||||
vm.name => vm.nic[0].computed_ip
|
||||
}
|
||||
}
|
||||
|
||||
output "worker_ip" {
|
||||
value = {
|
||||
for name, vm in opennebula_virtual_machine.worker :
|
||||
vm.name => vm.nic[0].computed_ip
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
variable "prefix" {}
|
||||
|
||||
variable "machines" {
|
||||
description = "Cluster machines"
|
||||
type = map(object({
|
||||
node_type = string
|
||||
ip = optional(string, "")
|
||||
}))
|
||||
}
|
||||
|
||||
variable "template_id" {
|
||||
description = "ID of the existing contextualized OpenNebula VM template"
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "template_disk_image_id" {
|
||||
description = "Image ID of the template's first disk (null when the template defines no image disk); required only for disk resizing"
|
||||
type = number
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "template_disk_size" {
|
||||
description = "SIZE (MB) declared on the template's first disk (0 = image default); used when re-declaring the OS disk"
|
||||
type = number
|
||||
default = 0
|
||||
}
|
||||
|
||||
variable "network_id" {
|
||||
description = "ID of the OpenNebula Virtual Network the nodes attach to"
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "master_cpu" {}
|
||||
variable "master_vcpu" {}
|
||||
variable "master_memory" {}
|
||||
variable "master_disk_size" {}
|
||||
|
||||
variable "worker_cpu" {}
|
||||
variable "worker_vcpu" {}
|
||||
variable "worker_memory" {}
|
||||
variable "worker_disk_size" {}
|
||||
|
||||
variable "ssh_public_keys" {
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable "vm_create_timeout" {}
|
||||
|
||||
variable "additional_disk_size" {
|
||||
default = 0
|
||||
}
|
||||
|
||||
variable "image_datastore_name" {
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "masters_anti_affinity" {
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "network_reservation_size" {
|
||||
default = 0
|
||||
}
|
||||
|
||||
variable "network_reservation_first_ip" {
|
||||
description = "First IP of the reservation carved from the parent network (empty = let OpenNebula choose)"
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "network_reservation_ar_id" {
|
||||
description = "Address-range ID of the parent network to reserve from (null = provider default)"
|
||||
type = number
|
||||
default = null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
opennebula = {
|
||||
source = "OpenNebula/opennebula"
|
||||
version = "~> 1.5"
|
||||
}
|
||||
}
|
||||
required_version = ">= 1.3.0"
|
||||
}
|
||||
Reference in New Issue
Block a user