diff --git a/environments/.stackhpc/terraform/main.tf b/environments/.stackhpc/terraform/main.tf index 4284ec132..d14896dd1 100644 --- a/environments/.stackhpc/terraform/main.tf +++ b/environments/.stackhpc/terraform/main.tf @@ -54,6 +54,10 @@ variable "volume_backed_instances" { default = false } +variable "root_volume_size" { + default = 15 +} + variable "k3s_token" { type = string } @@ -76,13 +80,16 @@ module "cluster" { k3s_token = var.k3s_token login_nodes = { - login-0: var.other_node_flavor + login-0 = { + flavor: var.other_node_flavor + } } compute = { standard: { # NB: can't call this default! nodes: ["compute-0", "compute-1"] flavor: var.other_node_flavor } + # Example of how to add another partition: # extra: { # nodes: ["compute-2", "compute-3"] @@ -91,6 +98,7 @@ module "cluster" { } volume_backed_instances = var.volume_backed_instances + root_volume_size = var.root_volume_size environment_root = var.environment_root # Can reduce volume size a lot for short-lived CI clusters: diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/compute.tf b/environments/skeleton/{{cookiecutter.environment}}/terraform/compute.tf index eb2139eba..abc3494f0 100644 --- a/environments/skeleton/{{cookiecutter.environment}}/terraform/compute.tf +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/compute.tf @@ -18,4 +18,7 @@ module "compute" { k3s_token = var.k3s_token k3s_server = [for n in openstack_compute_instance_v2.control["control"].network: n.fixed_ip_v4 if n.access_network][0] security_group_ids = [for o in data.openstack_networking_secgroup_v2.nonlogin: o.id] + baremetal_nodes = data.external.baremetal_nodes.result + volume_backed_instances = var.volume_backed_instances + root_volume_size = var.root_volume_size } diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/compute/nodes.tf b/environments/skeleton/{{cookiecutter.environment}}/terraform/compute/nodes.tf index e64a2162c..6ad510840 100644 --- a/environments/skeleton/{{cookiecutter.environment}}/terraform/compute/nodes.tf +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/compute/nodes.tf @@ -50,6 +50,8 @@ resource "openstack_compute_instance_v2" "compute" { k3s_server = var.k3s_server } + availability_zone = var.match_ironic_node ? "${var.availability_zone}::${var.baremetal_nodes[each.key]}" : null + user_data = <<-EOF #cloud-config fqdn: ${var.cluster_name}-${each.key}.${var.cluster_name}.${var.cluster_domain_suffix} diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/compute/variables.tf b/environments/skeleton/{{cookiecutter.environment}}/terraform/compute/variables.tf index 9d2c2e47c..98992322d 100644 --- a/environments/skeleton/{{cookiecutter.environment}}/terraform/compute/variables.tf +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/compute/variables.tf @@ -1,6 +1,9 @@ +# NB: Only variables which may be set directly on the compute group are +# have descriptions here (and defaults if optional) - others are just passed in + variable "nodes" { type = list(string) - description = "list of node names for partition" + description = "List of node names for this compute group" } variable "flavor" { @@ -14,7 +17,6 @@ variable "cluster_name" { variable "cluster_domain_suffix" { type = string - default = "invalid" } variable "cluster_net_id" { @@ -27,41 +29,35 @@ variable "cluster_subnet_id" { variable "key_pair" { type = string - description = "Name of an existing keypair in OpenStack" } variable "image_id" { type = string - description = "ID of image for the partition" + description = "ID of image for this compute node group" } variable "environment_root" { type = string - description = "Path to environment root, automatically set by activate script" } variable "vnic_type" { type = string - description = "VNIC type, see https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_port_v2#vnic_type" + description = "VNIC type for this compute group, see https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_port_v2#vnic_type" default = "normal" } variable "vnic_profile" { type = string - description = "VNIC binding profile as json string, see https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_port_v2#profile." + description = "VNIC binding profile for this compute group as json string, see https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_port_v2#profile." default = "{}" } variable "volume_backed_instances" { - description = "Whether to use volumes for root disks" type = bool - default = false } variable "root_volume_size" { - description = "Size of volume for root volumes if using volume backed instances, in Gb" type = number - default = 40 } variable "security_group_ids" { @@ -73,6 +69,22 @@ variable "k3s_token" { } variable "k3s_server" { - description = "Name/address of k3s server" type = string } + +variable "match_ironic_node" { + description = "Whether to launch instances on the Ironic node of the same name as this cluster node" + type = bool + default = false + +} + +variable availability_zone { + description = "Name of availability zone - ignored unless match_ironic_node is true" + type = string + default = "nova" +} + +variable "baremetal_nodes" { + type = map(string) +} diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/nodes.tf b/environments/skeleton/{{cookiecutter.environment}}/terraform/nodes.tf index bfbd1c532..5b12f4354 100644 --- a/environments/skeleton/{{cookiecutter.environment}}/terraform/nodes.tf +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/nodes.tf @@ -1,5 +1,24 @@ locals { control_volumes = concat([openstack_blockstorage_volume_v3.state], var.home_volume_size > 0 ? [openstack_blockstorage_volume_v3.home][0] : []) + + login_node_defaults = { + availability_zone = "nova" + match_ironic_node = false + } + + login_nodes = { + for nodename, cfg in var.login_nodes: + nodename => merge(local.login_node_defaults, cfg) + } +} + +data "external" "baremetal_nodes" { + # returns an empty map if cannot list baremetal nodes + program = ["bash", "-c", <<-EOT + openstack baremetal node list --limit 0 -f json 2>/dev/null | \ + jq -r 'try map( { (.Name|tostring): .UUID } ) | add catch {}' || echo '{}' + EOT + ] } resource "openstack_networking_port_v2" "login" { @@ -99,11 +118,11 @@ resource "openstack_compute_instance_v2" "control" { resource "openstack_compute_instance_v2" "login" { - for_each = var.login_nodes + for_each = local.login_nodes name = "${var.cluster_name}-${each.key}" image_id = var.cluster_image_id - flavor_name = each.value + flavor_name = each.value.flavor key_pair = var.key_pair dynamic "block_device" { @@ -129,6 +148,8 @@ resource "openstack_compute_instance_v2" "login" { k3s_server = [for n in openstack_compute_instance_v2.control["control"].network: n.fixed_ip_v4 if n.access_network][0] } + availability_zone = each.value.match_ironic_node ? "${each.value.availability_zone}::${data.external.baremetal_nodes.result[each.key]}" : null + user_data = <<-EOF #cloud-config fqdn: ${var.cluster_name}-${each.key}.${var.cluster_name}.${var.cluster_domain_suffix} diff --git a/environments/skeleton/{{cookiecutter.environment}}/terraform/variables.tf b/environments/skeleton/{{cookiecutter.environment}}/terraform/variables.tf index 0f5eefa18..5fa262128 100644 --- a/environments/skeleton/{{cookiecutter.environment}}/terraform/variables.tf +++ b/environments/skeleton/{{cookiecutter.environment}}/terraform/variables.tf @@ -31,7 +31,14 @@ variable "control_node_flavor" { variable "login_nodes" { type = map - description = "Mapping defining login nodes: key -> (str) nodename suffix, value -> (str) flavor name" + description = <<-EOF + Mapping defining login nodes. Keys are the node name suffix. Values are a mapping as follows: + Required: + flavor: String flavor name + Optional: + match_ironic_node: Bool, whether to launch instances on the Ironic node of the same name as this cluster node + availability_zone: String, name of availability zone - ignored unless match_ironic_node is true + EOF } variable "cluster_image_id" {