Skip to content

Define login nodes using an opentofu module #547

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 23, 2025
Merged
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
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,19 @@ Create an OpenTofu variables file to define the required infrastructure, e.g.:
cluster_subnet = "some_subnet" # *
key_pair = "my_key" # *
control_node_flavor = "some_flavor_name"
login_nodes = {
login-0: "login_flavor_name"
login = {
# Arbitrary group name for these login nodes
interactive = {
nodes: ["login-0"]
flavor: "login_flavor_name" # *
}
}
cluster_image_id = "rocky_linux_9_image_uuid"
compute = {
# Group name used for compute node partition definition
general = {
nodes: ["compute-0", "compute-1"]
flavor: "compute_flavor_name"
flavor: "compute_flavor_name" # *
}
}

Expand Down
7 changes: 5 additions & 2 deletions environments/.stackhpc/tofu/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ module "cluster" {
# are not in the same environment for stackhpc
inventory_secrets_path = "${path.module}/../inventory/group_vars/all/secrets.yml"

login_nodes = {
login-0: var.other_node_flavor
login = {
login: {
nodes: ["login-0"]
flavor: var.other_node_flavor
}
}
compute = {
standard: { # NB: can't call this default!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module "compute" {
source = "./compute"
source = "./node_group"

for_each = var.compute

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,6 @@ locals {
control_volumes = concat([openstack_blockstorage_volume_v3.state], var.home_volume_size > 0 ? [openstack_blockstorage_volume_v3.home][0] : [])
}

resource "openstack_networking_port_v2" "login" {

for_each = var.login_nodes

name = "${var.cluster_name}-${each.key}"
network_id = data.openstack_networking_network_v2.cluster_net.id
admin_state_up = "true"

fixed_ip {
subnet_id = data.openstack_networking_subnet_v2.cluster_subnet.id
}

security_group_ids = [for o in data.openstack_networking_secgroup_v2.login: o.id]

binding {
vnic_type = var.vnic_type
profile = var.vnic_profile
}
}

resource "openstack_networking_port_v2" "control" {

name = "${var.cluster_name}-control"
Expand Down Expand Up @@ -96,42 +76,3 @@ resource "openstack_compute_instance_v2" "control" {
EOF

}

resource "openstack_compute_instance_v2" "login" {

for_each = var.login_nodes

name = "${var.cluster_name}-${each.key}"
image_id = var.cluster_image_id
flavor_name = each.value
key_pair = var.key_pair

dynamic "block_device" {
for_each = var.volume_backed_instances ? [1]: []
content {
uuid = var.cluster_image_id
source_type = "image"
destination_type = "volume"
volume_size = var.root_volume_size
boot_index = 0
delete_on_termination = true
}
}

network {
port = openstack_networking_port_v2.login[each.key].id
access_network = true
}

metadata = {
environment_root = var.environment_root
k3s_token = local.k3s_token
control_address = [for n in openstack_compute_instance_v2.control["control"].network: n.fixed_ip_v4 if n.access_network][0]
}

user_data = <<-EOF
#cloud-config
fqdn: ${var.cluster_name}-${each.key}.${var.cluster_name}.${var.cluster_domain_suffix}
EOF

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ resource "local_file" "hosts" {
"cluster_name": var.cluster_name,
"cluster_domain_suffix": var.cluster_domain_suffix,
"control_instances": openstack_compute_instance_v2.control
"login_instances": openstack_compute_instance_v2.login
"login_groups": module.login
"compute_groups": module.compute
"state_dir": var.state_dir
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,22 @@ control:
vars:
appliances_state_dir: ${state_dir} # NB needs to be set on group not host otherwise it is ignored in packer build!

login:

%{ for group_name in keys(login_groups) ~}
${cluster_name}_${group_name}:
hosts:
%{ for login in login_instances ~}
${ login.name }:
ansible_host: ${[for n in login.network: n.fixed_ip_v4 if n.access_network][0]}
instance_id: ${ login.id }
%{ for node in login_groups[group_name]["compute_instances"] ~}
${ node.name }:
ansible_host: ${node.access_ip_v4}
instance_id: ${ node.id }
image_id: ${ node.image_id }
%{ endfor ~}
%{ endfor ~}

login:
children:
%{ for group_name in keys(login_groups) ~}
${cluster_name}_${group_name}:
%{ endfor ~}

%{ for group_name in keys(compute_groups) ~}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module "login" {
source = "./node_group"

for_each = var.login

# must be set for group:
nodes = each.value.nodes
flavor = each.value.flavor

cluster_name = var.cluster_name
cluster_domain_suffix = var.cluster_domain_suffix
cluster_net_id = data.openstack_networking_network_v2.cluster_net.id
cluster_subnet_id = data.openstack_networking_subnet_v2.cluster_subnet.id

# can be set for group, defaults to top-level value:
image_id = lookup(each.value, "image_id", var.cluster_image_id)
vnic_type = lookup(each.value, "vnic_type", var.vnic_type)
vnic_profile = lookup(each.value, "vnic_profile", var.vnic_profile)
volume_backed_instances = lookup(each.value, "volume_backed_instances", var.volume_backed_instances)
root_volume_size = lookup(each.value, "root_volume_size", var.root_volume_size)
extra_volumes = lookup(each.value, "extra_volumes", {})

compute_init_enable = []
ignore_image_changes = false

key_pair = var.key_pair
environment_root = var.environment_root
k3s_token = local.k3s_token
control_address = [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.login: o.id]
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,31 @@ variable "control_node_flavor" {
description = "Flavor name for control name"
}

variable "login_nodes" {
type = map
description = "Mapping defining login nodes: key -> (str) nodename suffix, value -> (str) flavor name"
variable "login" {
type = any
description = <<-EOF
Mapping defining homogenous groups of login nodes. Multiple groups may
be useful for e.g. separating nodes for ssh and Open Ondemand usage, or
to define login nodes with different capabilities such as high-memory.

Keys are names of groups.
Values are a mapping as follows:

Required:
nodes: List of node names
flavor: String flavor name
Optional:
image_id: Overrides variable cluster_image_id
vnic_type: Overrides variable vnic_type
vnic_profile: Overrides variable vnic_profile
volume_backed_instances: Overrides variable volume_backed_instances
root_volume_size: Overrides variable root_volume_size
extra_volumes: Mapping defining additional volumes to create and attach
Keys are unique volume name.
Values are a mapping with:
size: Size of volume in GB
**NB**: The order in /dev is not guaranteed to match the mapping
EOF
}

variable "cluster_image_id" {
Expand All @@ -42,8 +64,11 @@ variable "cluster_image_id" {
variable "compute" {
type = any
description = <<-EOF
Mapping defining compute infrastructure. Keys are names of groups. Values are a
mapping as follows:
Mapping defining homogenous groups of compute nodes. Groups are used
in Slurm partition definitions.

Keys are names of groups.
Values are a mapping as follows:

Required:
nodes: List of node names
Expand Down