From 4da9248c0489fa1af48735ab765f17b0ff935aa5 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 15:24:25 +0000 Subject: [PATCH 01/27] feat(k8s): Make name prefix optional --- .../examples/openstack-kubernetes/k3s-cluster/main.tf | 1 + .../terraform/modules/openstack-kubernetes-infra/compute.tf | 6 +++--- .../modules/openstack-kubernetes-infra/shared-locals.tf | 5 +++-- .../modules/openstack-kubernetes-infra/variables.tf | 6 ++++++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 437d004..42996fd 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -11,4 +11,5 @@ module "openstack_cogstack_infra" { ] allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr ubuntu_immage_name = var.ubuntu_immage_name + generate_random_id = false } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index b5a5551..b8af094 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -1,6 +1,6 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { - name = "${local.random_prefix}-${local.controller_host.name}" + name = var.generate_random_name_prefix ? "${local.random_prefix}-${local.controller_host.name}" : local.controller_host.name flavor_id = data.openstack_compute_flavor_v2.available_compute_flavors[local.controller_host.flavour].id key_pair = openstack_compute_keypair_v2.compute_keypair.name region = "RegionOne" @@ -39,7 +39,7 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { resource "openstack_compute_instance_v2" "kubernetes_nodes" { depends_on = [openstack_compute_instance_v2.kubernetes_server] for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } - name = "${local.random_prefix}-${each.value.name}" + name = var.generate_random_name_prefix ? "${local.random_prefix}-${each.value.name}" : each.value.name flavor_id = data.openstack_compute_flavor_v2.available_compute_flavors[each.value.flavour].id key_pair = openstack_compute_keypair_v2.compute_keypair.name region = "RegionOne" @@ -54,7 +54,7 @@ resource "openstack_compute_instance_v2" "kubernetes_nodes" { } block_device { - uuid = each.value.image_uuid == null ? data.openstack_images_image_v2.ubuntu.id : each.value.image_uuid + uuid = each.value.image_uuid == null ? data.openstack_images_image_v2.ubuntu.id : each.value.image_uuid source_type = "image" volume_size = each.value.volume_size boot_index = 0 diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index e2d95c2..4689761 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -1,6 +1,6 @@ locals { - random_prefix = random_id.server.b64_url + random_prefix = var.generate_random_name_prefix ? random_id.server[0].b64_url : "" } @@ -20,10 +20,11 @@ locals { } resource "random_id" "server" { + count = var.generate_random_name_prefix ? 1 : 0 keepers = { # Generate a new id each time we recreate the hosts cloud_init_config_controller = data.cloudinit_config.init_docker_controller.id } byte_length = 4 -} \ No newline at end of file +} diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf index f89f65b..d2821c3 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf @@ -62,4 +62,10 @@ variable "output_file_directory" { type = string default = null description = "Optional path to write output files to. If directory doesnt exist it will be created" +} + +variable "generate_random_name_prefix" { + type = bool + default = true + description = "Whether to generate a random prefix for hostnames. If false, hostnames will use only the name from host_instances" } \ No newline at end of file From ffab9058864dec1e8a60d460908515351de38c60 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 15:30:21 +0000 Subject: [PATCH 02/27] feat(k8s): Make name prefix optional --- .../examples/openstack-kubernetes/k3s-cluster/main.tf | 2 +- .../modules/openstack-kubernetes-infra/shared-locals.tf | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 42996fd..dc4ab63 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -11,5 +11,5 @@ module "openstack_cogstack_infra" { ] allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr ubuntu_immage_name = var.ubuntu_immage_name - generate_random_id = false + generate_random_name_prefix = true } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index 4689761..75e7e30 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -1,6 +1,6 @@ locals { - random_prefix = var.generate_random_name_prefix ? random_id.server[0].b64_url : "" + random_prefix = random_id.server.b64_url } @@ -20,7 +20,6 @@ locals { } resource "random_id" "server" { - count = var.generate_random_name_prefix ? 1 : 0 keepers = { # Generate a new id each time we recreate the hosts cloud_init_config_controller = data.cloudinit_config.init_docker_controller.id From 9d2c33d99ee851a914ada4e0f2b3e42b763a1977 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 15:35:56 +0000 Subject: [PATCH 03/27] feat(k8s): Make name prefix optional --- .../examples/openstack-kubernetes/k3s-cluster/main.tf | 1 + .../modules/openstack-kubernetes-infra/compute-keypair.tf | 4 ++-- .../terraform/modules/openstack-kubernetes-infra/compute.tf | 4 ++-- .../modules/openstack-kubernetes-infra/networking.tf | 2 +- .../modules/openstack-kubernetes-infra/shared-locals.tf | 1 + .../modules/openstack-kubernetes-infra/variables.tf | 6 ++++++ 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index dc4ab63..8956687 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -12,4 +12,5 @@ module "openstack_cogstack_infra" { allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr ubuntu_immage_name = var.ubuntu_immage_name generate_random_name_prefix = true + name_prefix = "dev" } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute-keypair.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute-keypair.tf index 7089791..7d18a30 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute-keypair.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute-keypair.tf @@ -14,7 +14,7 @@ locals { } resource "openstack_compute_keypair_v2" "compute_keypair" { - name = "${local.random_prefix}-cogstack_keypair" + name = local.prefix != "" ? "${local.prefix}-cogstack_keypair" : "cogstack_keypair" public_key = local.is_using_existing_ssh_keypair ? file(var.ssh_key_pair.public_key_file) : null } @@ -30,4 +30,4 @@ resource "local_file" "public_key" { content = openstack_compute_keypair_v2.compute_keypair.public_key filename = "${local.output_file_directory}/${openstack_compute_keypair_v2.compute_keypair.name}-rsa.pub" file_permission = "0600" -} \ No newline at end of file +} diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index b8af094..3279074 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -1,6 +1,6 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { - name = var.generate_random_name_prefix ? "${local.random_prefix}-${local.controller_host.name}" : local.controller_host.name + name = local.prefix != "" ? "${local.prefix}-${local.controller_host.name}" : local.controller_host.name flavor_id = data.openstack_compute_flavor_v2.available_compute_flavors[local.controller_host.flavour].id key_pair = openstack_compute_keypair_v2.compute_keypair.name region = "RegionOne" @@ -39,7 +39,7 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { resource "openstack_compute_instance_v2" "kubernetes_nodes" { depends_on = [openstack_compute_instance_v2.kubernetes_server] for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } - name = var.generate_random_name_prefix ? "${local.random_prefix}-${each.value.name}" : each.value.name + name = local.prefix != "" ? "${local.prefix}-${each.value.name}" : each.value.name flavor_id = data.openstack_compute_flavor_v2.available_compute_flavors[each.value.flavour].id key_pair = openstack_compute_keypair_v2.compute_keypair.name region = "RegionOne" diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf index 2b1c073..8eb7abb 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf @@ -13,7 +13,7 @@ locals { } resource "openstack_networking_secgroup_v2" "cogstack_apps_security_group" { - name = "${local.random_prefix}-cogstack-services" + name = local.prefix != "" ? "${local.prefix}-cogstack-services" : "cogstack-services" description = "Cogstack Apps and Services Group" } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index 75e7e30..40ee067 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -1,6 +1,7 @@ locals { random_prefix = random_id.server.b64_url + prefix = var.name_prefix != null ? var.name_prefix : (var.generate_random_name_prefix ? local.random_prefix : "") } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf index d2821c3..486ba6c 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf @@ -68,4 +68,10 @@ variable "generate_random_name_prefix" { type = bool default = true description = "Whether to generate a random prefix for hostnames. If false, hostnames will use only the name from host_instances" +} + +variable "name_prefix" { + type = string + default = null + description = "Optional custom prefix for resource names. If provided and generate_random_name_prefix is false, this will be used instead of a random prefix" } \ No newline at end of file From 9dcfca57a1c2ea2f0d6b463d8f645a8b4270c654 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 15:43:04 +0000 Subject: [PATCH 04/27] feat(k8s): Make name prefix optional --- .../examples/openstack-kubernetes/k3s-cluster/main.tf | 8 ++++---- .../modules/openstack-kubernetes-infra/shared-locals.tf | 2 +- .../modules/openstack-kubernetes-infra/variables.tf | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 8956687..41e5beb 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -9,8 +9,8 @@ module "openstack_cogstack_infra" { is_controller = false }, ] - allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr - ubuntu_immage_name = var.ubuntu_immage_name - generate_random_name_prefix = true - name_prefix = "dev" + allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr + ubuntu_immage_name = var.ubuntu_immage_name + # generate_random_name_prefix = false + # prefix = "dev" } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index 40ee067..f12dd16 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -1,7 +1,7 @@ locals { random_prefix = random_id.server.b64_url - prefix = var.name_prefix != null ? var.name_prefix : (var.generate_random_name_prefix ? local.random_prefix : "") + prefix = var.prefix != null ? var.prefix : (var.generate_random_name_prefix ? local.random_prefix : "") } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf index 486ba6c..e0c17e7 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf @@ -70,8 +70,8 @@ variable "generate_random_name_prefix" { description = "Whether to generate a random prefix for hostnames. If false, hostnames will use only the name from host_instances" } -variable "name_prefix" { +variable "prefix" { type = string default = null - description = "Optional custom prefix for resource names. If provided and generate_random_name_prefix is false, this will be used instead of a random prefix" -} \ No newline at end of file + description = "Optional custom prefix for resource names. If provided will override generate_random_name_prefix" +} From 448d97757235b8646c2b38d36929b31a16d75666 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 15:49:34 +0000 Subject: [PATCH 05/27] feat(iac): Output the security group --- .../terraform/modules/openstack-kubernetes-infra/outputs.tf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/outputs.tf b/deployment/terraform/modules/openstack-kubernetes-infra/outputs.tf index 6289ed1..a20e171 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/outputs.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/outputs.tf @@ -29,3 +29,8 @@ output "kubeconfig_file" { value = abspath(local.kubeconfig_file) description = "Path to the generated KUBECONFIG file used to connect to kubernetes" } + +output "created_security_group" { + value = openstack_networking_secgroup_v2.cogstack_apps_security_group + description = "Security group associated to the created hosts" +} \ No newline at end of file From cc0d83c7e82ba9403c11fd904d38633828a64ef7 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 16:38:18 +0000 Subject: [PATCH 06/27] feat(iac): In k8s module, added support for network configuration through a new variable 'network' --- .../openstack-kubernetes/k3s-cluster/main.tf | 3 +++ .../openstack-kubernetes-infra/compute.tf | 9 +++++---- .../openstack-kubernetes-infra/shared-locals.tf | 1 + .../openstack-kubernetes-infra/variables.tf | 17 +++++++++++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 41e5beb..2d03084 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -13,4 +13,7 @@ module "openstack_cogstack_infra" { ubuntu_immage_name = var.ubuntu_immage_name # generate_random_name_prefix = false # prefix = "dev" + # network = { + # network_id = "some-id" + # } } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 3279074..dbae4af 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -11,7 +11,7 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { ] network { - uuid = data.openstack_networking_network_v2.external_4003.id + uuid = local.network_id } block_device { @@ -50,7 +50,7 @@ resource "openstack_compute_instance_v2" "kubernetes_nodes" { ] network { - uuid = data.openstack_networking_network_v2.external_4003.id + uuid = local.network_id } block_device { @@ -123,8 +123,9 @@ data "openstack_compute_flavor_v2" "available_compute_flavors" { } -data "openstack_networking_network_v2" "external_4003" { - name = "external_4003" +data "openstack_networking_network_v2" "network" { + count = var.network.network_id != null ? 0 : 1 + name = var.network.name } data "openstack_images_image_v2" "ubuntu" { diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index f12dd16..51180a2 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -18,6 +18,7 @@ locals { locals { output_file_directory = var.output_file_directory != null ? var.output_file_directory : "${path.root}/.build" kubeconfig_file = "${local.output_file_directory}/downloaded-kubeconfig.yaml" + network_id = var.network.network_id != null ? var.network.network_id : data.openstack_networking_network_v2.network[0].id } resource "random_id" "server" { diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf index e0c17e7..675989d 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf @@ -75,3 +75,20 @@ variable "prefix" { default = null description = "Optional custom prefix for resource names. If provided will override generate_random_name_prefix" } + +variable "network" { + type = object({ + name = optional(string) + network_id = optional(string) + }) + default = { name = "external_4003" } + description = "Network configuration. Either provide 'name' to lookup the network by name, or 'network_id' to use a network UUID directly. Defaults to name 'external_4003'" + validation { + condition = var.network.name != null || var.network.network_id != null + error_message = "Either network.name or network.network_id must be provided" + } + validation { + condition = var.network.name == null || var.network.network_id == null + error_message = "Only one of network.name or network.network_id should be provided, not both" + } +} From e48afe251cd47f22002fe9b89d35c3c65cf6da55 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 17:30:45 +0000 Subject: [PATCH 07/27] feat(iac): Support network id input --- .../examples/openstack-kubernetes/k3s-cluster/main.tf | 6 +++--- .../terraform/modules/openstack-kubernetes-infra/compute.tf | 4 ++-- .../modules/openstack-kubernetes-infra/shared-locals.tf | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 2d03084..e8724be 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -13,7 +13,7 @@ module "openstack_cogstack_infra" { ubuntu_immage_name = var.ubuntu_immage_name # generate_random_name_prefix = false # prefix = "dev" - # network = { - # network_id = "some-id" - # } + network = { + network_id = "some-id" + } } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index dbae4af..86b7a8a 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -124,8 +124,8 @@ data "openstack_compute_flavor_v2" "available_compute_flavors" { data "openstack_networking_network_v2" "network" { - count = var.network.network_id != null ? 0 : 1 - name = var.network.name + for_each = toset(var.network.network_id != null ? [] : ["lookup"]) + name = var.network.name } data "openstack_images_image_v2" "ubuntu" { diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index 51180a2..c240bce 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -2,6 +2,7 @@ locals { random_prefix = random_id.server.b64_url prefix = var.prefix != null ? var.prefix : (var.generate_random_name_prefix ? local.random_prefix : "") + network_id = var.network.network_id != null ? var.network.network_id : data.openstack_networking_network_v2.network["lookup"].id } @@ -18,7 +19,6 @@ locals { locals { output_file_directory = var.output_file_directory != null ? var.output_file_directory : "${path.root}/.build" kubeconfig_file = "${local.output_file_directory}/downloaded-kubeconfig.yaml" - network_id = var.network.network_id != null ? var.network.network_id : data.openstack_networking_network_v2.network[0].id } resource "random_id" "server" { From b4e0d33c6c2b637f25457f439d1f3de07c9f66b3 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 17:35:14 +0000 Subject: [PATCH 08/27] feat(iac): Support network id input --- .../terraform/modules/openstack-kubernetes-infra/compute.tf | 1 - .../modules/openstack-kubernetes-infra/shared-locals.tf | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 86b7a8a..966f488 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -124,7 +124,6 @@ data "openstack_compute_flavor_v2" "available_compute_flavors" { data "openstack_networking_network_v2" "network" { - for_each = toset(var.network.network_id != null ? [] : ["lookup"]) name = var.network.name } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index c240bce..515a9c0 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -2,7 +2,7 @@ locals { random_prefix = random_id.server.b64_url prefix = var.prefix != null ? var.prefix : (var.generate_random_name_prefix ? local.random_prefix : "") - network_id = var.network.network_id != null ? var.network.network_id : data.openstack_networking_network_v2.network["lookup"].id + network_id = var.network.network_id != null ? var.network.network_id : data.openstack_networking_network_v2.network.id } From c61cadc549e687cad1d70a29f419fdb84c5252fe Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 17:47:56 +0000 Subject: [PATCH 09/27] feat(iac): Extract provisioner to null_resource in order to make optional --- .../openstack-kubernetes-infra/compute.tf | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 966f488..e87e34a 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -22,10 +22,14 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { destination_type = "volume" delete_on_termination = true } +} + +resource "null_resource" "kubernetes_server_provisioner" { + depends_on = [openstack_compute_instance_v2.kubernetes_server] connection { user = "ubuntu" - host = self.access_ip_v4 + host = openstack_compute_instance_v2.kubernetes_server.access_ip_v4 private_key = file(local.ssh_keys.private_key_file) } @@ -61,10 +65,16 @@ resource "openstack_compute_instance_v2" "kubernetes_nodes" { destination_type = "volume" delete_on_termination = true } +} + +resource "null_resource" "kubernetes_nodes_provisioner" { + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } + + depends_on = [openstack_compute_instance_v2.kubernetes_nodes] connection { user = "ubuntu" - host = self.access_ip_v4 + host = openstack_compute_instance_v2.kubernetes_nodes[each.key].access_ip_v4 private_key = file(local.ssh_keys.private_key_file) } @@ -124,7 +134,7 @@ data "openstack_compute_flavor_v2" "available_compute_flavors" { data "openstack_networking_network_v2" "network" { - name = var.network.name + name = var.network.name } data "openstack_images_image_v2" "ubuntu" { From 5e88032e5e0f9bc77143ee303e1462cfe595f914 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 18:06:51 +0000 Subject: [PATCH 10/27] feat(iac): fix nullable network name --- .../openstack-kubernetes/k3s-cluster/main.tf | 6 ++-- .../openstack-kubernetes-infra/compute.tf | 4 +-- .../openstack-kubernetes-infra/networking.tf | 28 +++++++++++++++++++ .../shared-locals.tf | 2 +- .../openstack-kubernetes-infra/variables.tf | 14 ++++------ 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index e8724be..2d03084 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -13,7 +13,7 @@ module "openstack_cogstack_infra" { ubuntu_immage_name = var.ubuntu_immage_name # generate_random_name_prefix = false # prefix = "dev" - network = { - network_id = "some-id" - } + # network = { + # network_id = "some-id" + # } } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index e87e34a..bae736f 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -85,8 +85,6 @@ resource "null_resource" "kubernetes_nodes_provisioner" { } } - - # TODO: Read content from files and put into cloud-init config # data "local_file" "install_docker_sh" { # filename = "${path.module}/resources/install-docker.sh" @@ -134,7 +132,7 @@ data "openstack_compute_flavor_v2" "available_compute_flavors" { data "openstack_networking_network_v2" "network" { - name = var.network.name + name = var.network != null && var.network.name != null ? var.network.name : "external_4003" } data "openstack_images_image_v2" "ubuntu" { diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf index 8eb7abb..c9630b0 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf @@ -29,3 +29,31 @@ resource "openstack_networking_secgroup_rule_v2" "cogstack_apps_port_rules" { security_group_id = openstack_networking_secgroup_v2.cogstack_apps_security_group.id } + + +# Look up ports by fixed IP address +data "openstack_networking_port_v2" "server_port" { + count = local.controller_host.floating_ip != null ? 1 : 0 + network_id = local.network_id + fixed_ip = openstack_compute_instance_v2.kubernetes_server.network[0].fixed_ip_v4 +} + +data "openstack_networking_port_v2" "nodes_port" { + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null } + network_id = local.network_id + fixed_ip = openstack_compute_instance_v2.kubernetes_nodes[each.key].network[0].fixed_ip_v4 +} + +# Associate floating IP with kubernetes server +resource "openstack_networking_floatingip_associate_v2" "kubernetes_server_fip" { + count = local.controller_host.floating_ip != null ? 1 : 0 + floating_ip = local.controller_host.floating_ip + port_id = data.openstack_networking_port_v2.server_port[0].id +} + +# Associate floating IPs with kubernetes nodes +resource "openstack_networking_floatingip_associate_v2" "kubernetes_nodes_fip" { + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null } + floating_ip = each.value.floating_ip + port_id = data.openstack_networking_port_v2.nodes_port[each.key].id +} diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index 515a9c0..9a0e58a 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -2,7 +2,7 @@ locals { random_prefix = random_id.server.b64_url prefix = var.prefix != null ? var.prefix : (var.generate_random_name_prefix ? local.random_prefix : "") - network_id = var.network.network_id != null ? var.network.network_id : data.openstack_networking_network_v2.network.id + network_id = var.network != null && var.network.network_id != null ? var.network.network_id : data.openstack_networking_network_v2.network.id } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf index 675989d..c75582f 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf @@ -17,13 +17,15 @@ is_controller = Must be true for exactly one host. This will run the k3s "server flavour = The openstack_compute_flavor_v2 for the host volume_size = Size in GB for the disk volume for the node image_uuid = (Optional) The Openstack image you want to run, to override the default in ubuntu_immage_name +floating_ip = (Optional) Floating IP address to associate with this host EOT type = list(object({ name = string, flavour = optional(string, "2cpu4ram"), volume_size = optional(number, 20), is_controller = optional(bool, false), - image_uuid = optional(string, null) + image_uuid = optional(string, null), + floating_ip = optional(string, null) })) default = [ @@ -78,17 +80,13 @@ variable "prefix" { variable "network" { type = object({ - name = optional(string) + name = optional(string, "external_4003") network_id = optional(string) }) default = { name = "external_4003" } - description = "Network configuration. Either provide 'name' to lookup the network by name, or 'network_id' to use a network UUID directly. Defaults to name 'external_4003'" + description = "Network configuration. Either provide 'name' to lookup the network by name, or 'network_id' to use a network UUID directly. Defaults to name 'external_4003' if null" validation { - condition = var.network.name != null || var.network.network_id != null + condition = var.network == null || var.network.name != null || var.network.network_id != null error_message = "Either network.name or network.network_id must be provided" } - validation { - condition = var.network.name == null || var.network.network_id == null - error_message = "Only one of network.name or network.network_id should be provided, not both" - } } From 0330f4d588738c5f2a52665e45043da3d0bed8e3 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 18:23:26 +0000 Subject: [PATCH 11/27] feat(iac): set floating ip for k8s nodes --- .../examples/openstack-kubernetes/k3s-cluster/main.tf | 3 ++- .../modules/openstack-kubernetes-infra/compute.tf | 2 +- .../kubeconfig-extraction.tf | 8 ++++---- .../modules/openstack-kubernetes-infra/networking.tf | 10 +++++----- .../openstack-kubernetes-infra/shared-locals.tf | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 2d03084..81e2df5 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -6,7 +6,8 @@ module "openstack_cogstack_infra" { name = "cogstack-k3s-node-2" flavour = "2cpu4ram" volume_size = 20 - is_controller = false + is_controller = false, + # floating_ip = "10.10.10.10" }, ] allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index bae736f..9aaaa49 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -29,7 +29,7 @@ resource "null_resource" "kubernetes_server_provisioner" { connection { user = "ubuntu" - host = openstack_compute_instance_v2.kubernetes_server.access_ip_v4 + host = local.controller_host_instance.ip_address private_key = file(local.ssh_keys.private_key_file) } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/kubeconfig-extraction.tf b/deployment/terraform/modules/openstack-kubernetes-infra/kubeconfig-extraction.tf index 7a7d3ef..7e3fafe 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/kubeconfig-extraction.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/kubeconfig-extraction.tf @@ -1,5 +1,5 @@ resource "null_resource" "copy_kubeconfig" { - depends_on = [openstack_compute_instance_v2.kubernetes_server] + depends_on = [openstack_compute_instance_v2.kubernetes_server, null_resource.kubernetes_server_provisioner] provisioner "local-exec" { # Copy the kubeconfig file from the host to a local file using SCP. @@ -7,12 +7,12 @@ resource "null_resource" "copy_kubeconfig" { # Use sed to replace the localhost address in the KUBECONFIG file with the actual IP adddress of the created VM. command = <> ${path.root}/.build/.known_hosts_cogstack && \ +ssh-keyscan -H ${local.controller_host_instance.ip_address} >> ${path.root}/.build/.known_hosts_cogstack && \ ssh -o UserKnownHostsFile=${path.root}/.build/.known_hosts_cogstack -o StrictHostKeyChecking=yes \ -i ${local.ssh_keys.private_key_file} \ - ubuntu@${openstack_compute_instance_v2.kubernetes_server.access_ip_v4} \ + ubuntu@${local.controller_host_instance.ip_address} \ "sudo cat /etc/rancher/k3s/k3s.yaml" > ${local.kubeconfig_file} && \ -sed -i "s/127.0.0.1/${openstack_compute_instance_v2.kubernetes_server.access_ip_v4}/" ${local.kubeconfig_file} +sed -i "s/127.0.0.1/${local.controller_host_instance.ip_address}/" ${local.kubeconfig_file} EOT } } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf index c9630b0..a789c9b 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf @@ -31,17 +31,17 @@ resource "openstack_networking_secgroup_rule_v2" "cogstack_apps_port_rules" { -# Look up ports by fixed IP address +# Look up ports by device_id and network_id data "openstack_networking_port_v2" "server_port" { count = local.controller_host.floating_ip != null ? 1 : 0 - network_id = local.network_id - fixed_ip = openstack_compute_instance_v2.kubernetes_server.network[0].fixed_ip_v4 + device_id = openstack_compute_instance_v2.kubernetes_server.id + network_id = openstack_compute_instance_v2.kubernetes_server.network[0].uuid } data "openstack_networking_port_v2" "nodes_port" { for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null } - network_id = local.network_id - fixed_ip = openstack_compute_instance_v2.kubernetes_nodes[each.key].network[0].fixed_ip_v4 + device_id = openstack_compute_instance_v2.kubernetes_nodes[each.key].id + network_id = openstack_compute_instance_v2.kubernetes_nodes[each.key].network[0].uuid } # Associate floating IP with kubernetes server diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index 9a0e58a..0012c67 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -11,7 +11,7 @@ locals { created_controller_host = openstack_compute_instance_v2.kubernetes_server controller_host_instance = { name = local.controller_host.name - ip_address = local.created_controller_host.access_ip_v4 + ip_address = local.controller_host.floating_ip != null ? local.controller_host.floating_ip : openstack_compute_instance_v2.kubernetes_server.access_ip_v4 unique_name = local.created_controller_host.name } } From a7ea58262096819e2b605520f84f3da70d34853d Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 18:32:02 +0000 Subject: [PATCH 12/27] feat(iac): set floating ip for k8s nodes --- .../modules/openstack-kubernetes-infra/networking.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf index a789c9b..73c1689 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf @@ -33,7 +33,7 @@ resource "openstack_networking_secgroup_rule_v2" "cogstack_apps_port_rules" { # Look up ports by device_id and network_id data "openstack_networking_port_v2" "server_port" { - count = local.controller_host.floating_ip != null ? 1 : 0 + for_each = toset(local.controller_host.floating_ip != null ? ["server"] : []) device_id = openstack_compute_instance_v2.kubernetes_server.id network_id = openstack_compute_instance_v2.kubernetes_server.network[0].uuid } @@ -46,9 +46,9 @@ data "openstack_networking_port_v2" "nodes_port" { # Associate floating IP with kubernetes server resource "openstack_networking_floatingip_associate_v2" "kubernetes_server_fip" { - count = local.controller_host.floating_ip != null ? 1 : 0 + for_each = toset(local.controller_host.floating_ip != null ? ["server"] : []) floating_ip = local.controller_host.floating_ip - port_id = data.openstack_networking_port_v2.server_port[0].id + port_id = data.openstack_networking_port_v2.server_port["server"].id } # Associate floating IPs with kubernetes nodes From 0dd6aaaa1e4515648798a1c7d7fe884cb742a1cb Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 18:35:40 +0000 Subject: [PATCH 13/27] feat(iac): set floating ip for k8s nodes --- .../modules/openstack-kubernetes-infra/networking.tf | 4 ++-- .../modules/openstack-kubernetes-infra/shared-locals.tf | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf index 73c1689..67576bd 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf @@ -33,7 +33,7 @@ resource "openstack_networking_secgroup_rule_v2" "cogstack_apps_port_rules" { # Look up ports by device_id and network_id data "openstack_networking_port_v2" "server_port" { - for_each = toset(local.controller_host.floating_ip != null ? ["server"] : []) + for_each = toset(local.controller_host_has_floating_ip ? ["server"] : []) device_id = openstack_compute_instance_v2.kubernetes_server.id network_id = openstack_compute_instance_v2.kubernetes_server.network[0].uuid } @@ -46,7 +46,7 @@ data "openstack_networking_port_v2" "nodes_port" { # Associate floating IP with kubernetes server resource "openstack_networking_floatingip_associate_v2" "kubernetes_server_fip" { - for_each = toset(local.controller_host.floating_ip != null ? ["server"] : []) + for_each = toset(local.controller_host_has_floating_ip ? ["server"] : []) floating_ip = local.controller_host.floating_ip port_id = data.openstack_networking_port_v2.server_port["server"].id } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index 0012c67..e72dce8 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -7,8 +7,9 @@ locals { locals { - controller_host = one([for host in var.host_instances : host if host.is_controller]) - created_controller_host = openstack_compute_instance_v2.kubernetes_server + controller_host = one([for host in var.host_instances : host if host.is_controller]) + controller_host_has_floating_ip = local.controller_host.floating_ip != null + created_controller_host = openstack_compute_instance_v2.kubernetes_server controller_host_instance = { name = local.controller_host.name ip_address = local.controller_host.floating_ip != null ? local.controller_host.floating_ip : openstack_compute_instance_v2.kubernetes_server.access_ip_v4 From 176b64a09c0701efb27fb95d34faf48b69d8cc6b Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 18:50:01 +0000 Subject: [PATCH 14/27] feat(iac): set floating ip for k8s nodes --- .../modules/openstack-kubernetes-infra/networking.tf | 12 ++++++------ .../openstack-kubernetes-infra/shared-locals.tf | 4 ++-- .../modules/openstack-kubernetes-infra/variables.tf | 7 +++++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf index 67576bd..9cbc09f 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf @@ -33,27 +33,27 @@ resource "openstack_networking_secgroup_rule_v2" "cogstack_apps_port_rules" { # Look up ports by device_id and network_id data "openstack_networking_port_v2" "server_port" { - for_each = toset(local.controller_host_has_floating_ip ? ["server"] : []) + count = local.controller_host_has_floating_ip ? 1 : 0 device_id = openstack_compute_instance_v2.kubernetes_server.id network_id = openstack_compute_instance_v2.kubernetes_server.network[0].uuid } data "openstack_networking_port_v2" "nodes_port" { - for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null } + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null && vm.floating_ip.use_floating_ip } device_id = openstack_compute_instance_v2.kubernetes_nodes[each.key].id network_id = openstack_compute_instance_v2.kubernetes_nodes[each.key].network[0].uuid } # Associate floating IP with kubernetes server resource "openstack_networking_floatingip_associate_v2" "kubernetes_server_fip" { - for_each = toset(local.controller_host_has_floating_ip ? ["server"] : []) - floating_ip = local.controller_host.floating_ip + count = local.controller_host_has_floating_ip ? 1 : 0 + floating_ip = local.controller_host.floating_ip.address port_id = data.openstack_networking_port_v2.server_port["server"].id } # Associate floating IPs with kubernetes nodes resource "openstack_networking_floatingip_associate_v2" "kubernetes_nodes_fip" { - for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null } - floating_ip = each.value.floating_ip + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null && vm.floating_ip.use_floating_ip} + floating_ip = each.value.floating_ip.address port_id = data.openstack_networking_port_v2.nodes_port[each.key].id } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index e72dce8..e7530a3 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -8,11 +8,11 @@ locals { locals { controller_host = one([for host in var.host_instances : host if host.is_controller]) - controller_host_has_floating_ip = local.controller_host.floating_ip != null + controller_host_has_floating_ip = local.controller_host.floating_ip != null && local.controller_host.floating_ip.use_floating_ip created_controller_host = openstack_compute_instance_v2.kubernetes_server controller_host_instance = { name = local.controller_host.name - ip_address = local.controller_host.floating_ip != null ? local.controller_host.floating_ip : openstack_compute_instance_v2.kubernetes_server.access_ip_v4 + ip_address = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : openstack_compute_instance_v2.kubernetes_server.access_ip_v4 unique_name = local.created_controller_host.name } } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf index c75582f..a58a8a6 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf @@ -17,7 +17,7 @@ is_controller = Must be true for exactly one host. This will run the k3s "server flavour = The openstack_compute_flavor_v2 for the host volume_size = Size in GB for the disk volume for the node image_uuid = (Optional) The Openstack image you want to run, to override the default in ubuntu_immage_name -floating_ip = (Optional) Floating IP address to associate with this host +floating_ip = (Optional) Floating IP configuration. Set use_floating_ip to true and provide address to associate a floating IP with this host EOT type = list(object({ name = string, @@ -25,7 +25,10 @@ EOT volume_size = optional(number, 20), is_controller = optional(bool, false), image_uuid = optional(string, null), - floating_ip = optional(string, null) + floating_ip = optional(object({ + use_floating_ip = optional(bool, false) # Using a boolean to make it a plan time value. + address = optional(string) + }), null) })) default = [ From 5ef9591ae0149293e0ad66daa1069d0e26b66cfa Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 18:52:03 +0000 Subject: [PATCH 15/27] feat(iac): set floating ip for k8s nodes --- .../terraform/modules/openstack-kubernetes-infra/networking.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf index 9cbc09f..3468230 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf @@ -48,7 +48,7 @@ data "openstack_networking_port_v2" "nodes_port" { resource "openstack_networking_floatingip_associate_v2" "kubernetes_server_fip" { count = local.controller_host_has_floating_ip ? 1 : 0 floating_ip = local.controller_host.floating_ip.address - port_id = data.openstack_networking_port_v2.server_port["server"].id + port_id = data.openstack_networking_port_v2.server_port[0].id } # Associate floating IPs with kubernetes nodes From 90abe7dbca4cf9051be423d2ce991d672253695c Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Tue, 13 Jan 2026 19:14:06 +0000 Subject: [PATCH 16/27] feat(iac): set floating ip for k8s nodes --- .../openstack-kubernetes-infra/compute.tf | 19 ++++++++++++------- .../openstack-kubernetes-infra/networking.tf | 6 +++--- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 9aaaa49..9f0020b 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -25,7 +25,7 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { } resource "null_resource" "kubernetes_server_provisioner" { - depends_on = [openstack_compute_instance_v2.kubernetes_server] + depends_on = [openstack_compute_instance_v2.kubernetes_server, openstack_networking_floatingip_associate_v2.kubernetes_server_fip] connection { user = "ubuntu" @@ -41,12 +41,17 @@ resource "null_resource" "kubernetes_server_provisioner" { } resource "openstack_compute_instance_v2" "kubernetes_nodes" { - depends_on = [openstack_compute_instance_v2.kubernetes_server] - for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } - name = local.prefix != "" ? "${local.prefix}-${each.value.name}" : each.value.name - flavor_id = data.openstack_compute_flavor_v2.available_compute_flavors[each.value.flavour].id - key_pair = openstack_compute_keypair_v2.compute_keypair.name - region = "RegionOne" + depends_on = [ + openstack_compute_instance_v2.kubernetes_server, + openstack_networking_floatingip_associate_v2.kubernetes_nodes_fip + ] + + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } + + name = local.prefix != "" ? "${local.prefix}-${each.value.name}" : each.value.name + flavor_id = data.openstack_compute_flavor_v2.available_compute_flavors[each.value.flavour].id + key_pair = openstack_compute_keypair_v2.compute_keypair.name + region = "RegionOne" user_data = data.cloudinit_config.init_docker.rendered security_groups = ["default", diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf index 3468230..3cb08d0 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/networking.tf @@ -33,7 +33,7 @@ resource "openstack_networking_secgroup_rule_v2" "cogstack_apps_port_rules" { # Look up ports by device_id and network_id data "openstack_networking_port_v2" "server_port" { - count = local.controller_host_has_floating_ip ? 1 : 0 + count = local.controller_host_has_floating_ip ? 1 : 0 device_id = openstack_compute_instance_v2.kubernetes_server.id network_id = openstack_compute_instance_v2.kubernetes_server.network[0].uuid } @@ -46,14 +46,14 @@ data "openstack_networking_port_v2" "nodes_port" { # Associate floating IP with kubernetes server resource "openstack_networking_floatingip_associate_v2" "kubernetes_server_fip" { - count = local.controller_host_has_floating_ip ? 1 : 0 + count = local.controller_host_has_floating_ip ? 1 : 0 floating_ip = local.controller_host.floating_ip.address port_id = data.openstack_networking_port_v2.server_port[0].id } # Associate floating IPs with kubernetes nodes resource "openstack_networking_floatingip_associate_v2" "kubernetes_nodes_fip" { - for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null && vm.floating_ip.use_floating_ip} + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller && vm.floating_ip != null && vm.floating_ip.use_floating_ip } floating_ip = each.value.floating_ip.address port_id = data.openstack_networking_port_v2.nodes_port[each.key].id } From 2be1a667a66a34b38a376937f83d9a5f1fedacbd Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 10:29:18 +0000 Subject: [PATCH 17/27] feat(iac): set floating ip for k8s nodes - fix provisioner --- .../openstack-kubernetes/k3s-cluster/main.tf | 5 ++++- .../modules/openstack-kubernetes-infra/compute.tf | 13 ++++++------- .../modules/openstack-kubernetes-infra/outputs.tf | 6 +----- .../openstack-kubernetes-infra/shared-locals.tf | 11 +++++++++++ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 81e2df5..5a53642 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -7,7 +7,10 @@ module "openstack_cogstack_infra" { flavour = "2cpu4ram" volume_size = 20 is_controller = false, - # floating_ip = "10.10.10.10" + # floating_ip = { + # use_floating_ip = true, + # address = "10.10.10.10" + # } }, ] allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 9f0020b..48c1bc9 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -42,12 +42,11 @@ resource "null_resource" "kubernetes_server_provisioner" { resource "openstack_compute_instance_v2" "kubernetes_nodes" { depends_on = [ - openstack_compute_instance_v2.kubernetes_server, - openstack_networking_floatingip_associate_v2.kubernetes_nodes_fip + openstack_compute_instance_v2.kubernetes_server ] - for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } - + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } + name = local.prefix != "" ? "${local.prefix}-${each.value.name}" : each.value.name flavor_id = data.openstack_compute_flavor_v2.available_compute_flavors[each.value.flavour].id key_pair = openstack_compute_keypair_v2.compute_keypair.name @@ -73,13 +72,13 @@ resource "openstack_compute_instance_v2" "kubernetes_nodes" { } resource "null_resource" "kubernetes_nodes_provisioner" { - for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } + for_each = local.created_nodes - depends_on = [openstack_compute_instance_v2.kubernetes_nodes] + depends_on = [openstack_compute_instance_v2.kubernetes_nodes, openstack_networking_floatingip_associate_v2.kubernetes_nodes_fip] connection { user = "ubuntu" - host = openstack_compute_instance_v2.kubernetes_nodes[each.key].access_ip_v4 + host = each.value.ip_address private_key = file(local.ssh_keys.private_key_file) } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/outputs.tf b/deployment/terraform/modules/openstack-kubernetes-infra/outputs.tf index a20e171..e794092 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/outputs.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/outputs.tf @@ -1,10 +1,6 @@ output "created_hosts" { - value = merge({ for k, value in openstack_compute_instance_v2.kubernetes_nodes : k => { - ip_address = value.access_ip_v4 - unique_name = value.name - name = k - } }, + value = merge(local.created_nodes, { (local.controller_host.name) : local.controller_host_instance }) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index e7530a3..cd69b1e 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -15,6 +15,17 @@ locals { ip_address = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : openstack_compute_instance_v2.kubernetes_server.access_ip_v4 unique_name = local.created_controller_host.name } + + created_nodes = { + for node in var.host_instances : + node.name => { + ip_address = node.floating_ip != null && node.floating_ip.use_floating_ip ? node.floating_ip.address : openstack_compute_instance_v2.kubernetes_nodes[node.name].access_ip_v4 + unique_name = openstack_compute_instance_v2.kubernetes_nodes[node.name].name + name = node.name + } + if !node.is_controller + } + } locals { From 7e8ab12f7e48f970f4c7dd2d4eb1451a4e744b87 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 13:21:38 +0000 Subject: [PATCH 18/27] feat(iac): set floating ip for k8s nodes - fix provisioner for nodes --- .../modules/openstack-kubernetes-infra/compute.tf | 9 ++++++++- .../modules/openstack-kubernetes-infra/shared-locals.tf | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 48c1bc9..9c10412 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -71,8 +71,15 @@ resource "openstack_compute_instance_v2" "kubernetes_nodes" { } } +locals { + is_default_network = var.network != null && var.network == { name = "external_4003" } + nodes_with_exernal_ip = { for node in local.created_nodes : node.name => node if local.is_default_network || node.use_floating_ip } + +} resource "null_resource" "kubernetes_nodes_provisioner" { - for_each = local.created_nodes + # Provisioner is only used to check for node readiness. Skip for any nodes that are not in the external network, + # TODO: Filter this provisioner to only run on nodes that have a floating IP if the network is not default + for_each = local.nodes_with_exernal_ip depends_on = [openstack_compute_instance_v2.kubernetes_nodes, openstack_networking_floatingip_associate_v2.kubernetes_nodes_fip] diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index cd69b1e..3a55eb2 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -14,6 +14,8 @@ locals { name = local.controller_host.name ip_address = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : openstack_compute_instance_v2.kubernetes_server.access_ip_v4 unique_name = local.created_controller_host.name + use_floating_ip = local.controller_host_has_floating_ip + internal_ip_address = openstack_compute_instance_v2.kubernetes_server.access_ip_v4 } created_nodes = { @@ -22,6 +24,8 @@ locals { ip_address = node.floating_ip != null && node.floating_ip.use_floating_ip ? node.floating_ip.address : openstack_compute_instance_v2.kubernetes_nodes[node.name].access_ip_v4 unique_name = openstack_compute_instance_v2.kubernetes_nodes[node.name].name name = node.name + use_floating_ip = node.floating_ip != null && node.floating_ip.use_floating_ip + internal_ip_address = openstack_compute_instance_v2.kubernetes_nodes[node.name].access_ip_v4 } if !node.is_controller } From 0b0ec950a161545f1b06324ed80e3081f025a86e Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 13:37:25 +0000 Subject: [PATCH 19/27] feat(iac): floating_ip for k8s server. Set SAN --- .../openstack-kubernetes-infra/cloud-init-k3s-server.yaml | 7 ++++++- .../modules/openstack-kubernetes-infra/compute.tf | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml b/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml index a7c379a..04c476e 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml +++ b/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml @@ -37,7 +37,12 @@ runcmd: # Run K3s - echo "Installing K3S" - - sudo curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" K3S_TOKEN="${TF_K3S_TOKEN}" sh - + - | + if [ -n "${TF_K3S_TLS_SAN}" ]; then + sudo curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --tls-san ${TF_K3S_TLS_SAN}" K3S_TOKEN="${TF_K3S_TOKEN}" sh - + else + sudo curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" K3S_TOKEN="${TF_K3S_TOKEN}" sh - + fi - echo "Completed Installing K3S" - sudo chmod 644 /etc/rancher/k3s/k3s.yaml diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 9c10412..3a64c6e 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -72,7 +72,7 @@ resource "openstack_compute_instance_v2" "kubernetes_nodes" { } locals { - is_default_network = var.network != null && var.network == { name = "external_4003" } + is_default_network = var.network != null && var.network == { name = "external_4003" } nodes_with_exernal_ip = { for node in local.created_nodes : node.name => node if local.is_default_network || node.use_floating_ip } } @@ -130,7 +130,8 @@ data "cloudinit_config" "init_docker_controller" { content_type = "text/cloud-config" content = templatefile("${path.module}/cloud-init-k3s-server.yaml", { - TF_K3S_TOKEN = random_password.k3s_token.result + TF_K3S_TOKEN = random_password.k3s_token.result + TF_K3S_TLS_SAN = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : "" } ) } From 349b57da99a764c69a3bf986c323a3a9b07905f9 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 13:57:00 +0000 Subject: [PATCH 20/27] feat(iac): format --- .../openstack-kubernetes/k3s-cluster/main.tf | 4 ++-- .../shared-locals.tf | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 5a53642..3525a5e 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -13,8 +13,8 @@ module "openstack_cogstack_infra" { # } }, ] - allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr - ubuntu_immage_name = var.ubuntu_immage_name + allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr + ubuntu_immage_name = var.ubuntu_immage_name # generate_random_name_prefix = false # prefix = "dev" # network = { diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf index 3a55eb2..cff1b88 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/shared-locals.tf @@ -11,23 +11,23 @@ locals { controller_host_has_floating_ip = local.controller_host.floating_ip != null && local.controller_host.floating_ip.use_floating_ip created_controller_host = openstack_compute_instance_v2.kubernetes_server controller_host_instance = { - name = local.controller_host.name - ip_address = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : openstack_compute_instance_v2.kubernetes_server.access_ip_v4 - unique_name = local.created_controller_host.name - use_floating_ip = local.controller_host_has_floating_ip + name = local.controller_host.name + ip_address = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : openstack_compute_instance_v2.kubernetes_server.access_ip_v4 + unique_name = local.created_controller_host.name + use_floating_ip = local.controller_host_has_floating_ip internal_ip_address = openstack_compute_instance_v2.kubernetes_server.access_ip_v4 } - created_nodes = { - for node in var.host_instances : + created_nodes = { + for node in var.host_instances : node.name => { - ip_address = node.floating_ip != null && node.floating_ip.use_floating_ip ? node.floating_ip.address : openstack_compute_instance_v2.kubernetes_nodes[node.name].access_ip_v4 - unique_name = openstack_compute_instance_v2.kubernetes_nodes[node.name].name - name = node.name - use_floating_ip = node.floating_ip != null && node.floating_ip.use_floating_ip + ip_address = node.floating_ip != null && node.floating_ip.use_floating_ip ? node.floating_ip.address : openstack_compute_instance_v2.kubernetes_nodes[node.name].access_ip_v4 + unique_name = openstack_compute_instance_v2.kubernetes_nodes[node.name].name + name = node.name + use_floating_ip = node.floating_ip != null && node.floating_ip.use_floating_ip internal_ip_address = openstack_compute_instance_v2.kubernetes_nodes[node.name].access_ip_v4 - } - if !node.is_controller + } + if !node.is_controller } } From 3a9ea08de2a22b8f2046ccb6d60387986590fa16 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 15:59:52 +0000 Subject: [PATCH 21/27] feat(iac): set floating ip for k8s nodes - set node external ip --- .../openstack-kubernetes/k3s-cluster/main.tf | 15 +++++++++------ .../cloud-init-k3s-agent.yaml | 8 +++++++- .../cloud-init-k3s-server.yaml | 13 +++++++++---- .../modules/openstack-kubernetes-infra/compute.tf | 12 ++++++++---- .../openstack-kubernetes-infra/variables.tf | 9 +++++++++ 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf index 3525a5e..7e4e4bd 100644 --- a/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf +++ b/deployment/terraform/examples/openstack-kubernetes/k3s-cluster/main.tf @@ -1,17 +1,20 @@ module "openstack_cogstack_infra" { source = "../../../modules/openstack-kubernetes-infra" host_instances = [ - { name = "cogstack-k3s", is_controller = true }, { - name = "cogstack-k3s-node-2" - flavour = "2cpu4ram" - volume_size = 20 - is_controller = false, + name = "cogstack-k3s", + is_controller = true, # floating_ip = { # use_floating_ip = true, - # address = "10.10.10.10" + # address = "10.10.10.10" # } }, + { + name = "cogstack-k3s-node-2" + flavour = "2cpu4ram" + volume_size = 20 + is_controller = false + }, ] allowed_ingress_ips_cidr = var.allowed_ingress_ips_cidr ubuntu_immage_name = var.ubuntu_immage_name diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-agent.yaml b/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-agent.yaml index 36aa265..df2b8a3 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-agent.yaml +++ b/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-agent.yaml @@ -37,7 +37,13 @@ runcmd: # Run K3s - echo "Installing K3S" - - curl -sfL https://get.k3s.io | K3S_URL=https://${TF_K3S_SERVER_IP_ADDRESS}:6443 K3S_TOKEN="${TF_K3S_TOKEN}" sh - + - | + INSTALL_K3S_EXEC="" + TF_K3S_NODE_EXTERNAL_IP=${TF_K3S_NODE_EXTERNAL_IP} + if [ -n "$TF_K3S_NODE_EXTERNAL_IP" ]; then + INSTALL_K3S_EXEC="--node-external-ip $TF_K3S_NODE_EXTERNAL_IP" + fi + curl -sfL https://get.k3s.io | K3S_URL=https://${TF_K3S_SERVER_IP_ADDRESS}:6443 K3S_TOKEN="${TF_K3S_TOKEN}" INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" sh - - echo "Completed Installing K3S" # - sudo chmod 644 /etc/rancher/k3s/k3s.yaml diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml b/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml index 04c476e..f2c8ba2 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml +++ b/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml @@ -38,11 +38,16 @@ runcmd: # Run K3s - echo "Installing K3S" - | - if [ -n "${TF_K3S_TLS_SAN}" ]; then - sudo curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --tls-san ${TF_K3S_TLS_SAN}" K3S_TOKEN="${TF_K3S_TOKEN}" sh - - else - sudo curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" K3S_TOKEN="${TF_K3S_TOKEN}" sh - + INSTALL_K3S_EXEC="server" + TF_K3S_TLS_SAN=${TF_K3S_TLS_SAN} + TF_K3S_NODE_EXTERNAL_IP=${TF_K3S_NODE_EXTERNAL_IP} + if [ -n "$TF_K3S_TLS_SAN" ]; then + INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --tls-san $TF_K3S_TLS_SAN" fi + if [ -n "$TF_K3S_NODE_EXTERNAL_IP" ]; then + INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --node-external-ip $TF_K3S_NODE_EXTERNAL_IP" + fi + sudo curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="${INSTALL_K3S_EXEC}" K3S_TOKEN="${TF_K3S_TOKEN}" INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" sh - - echo "Completed Installing K3S" - sudo chmod 644 /etc/rancher/k3s/k3s.yaml diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 3a64c6e..401f1fd 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -52,7 +52,7 @@ resource "openstack_compute_instance_v2" "kubernetes_nodes" { key_pair = openstack_compute_keypair_v2.compute_keypair.name region = "RegionOne" - user_data = data.cloudinit_config.init_docker.rendered + user_data = data.cloudinit_config.init_docker[each.key].rendered security_groups = ["default", openstack_networking_secgroup_v2.cogstack_apps_security_group.name ] @@ -107,6 +107,8 @@ resource "null_resource" "kubernetes_nodes_provisioner" { data "cloudinit_config" "init_docker" { + for_each = { for vm in var.host_instances : vm.name => vm if !vm.is_controller } + depends_on = [openstack_compute_instance_v2.kubernetes_server] part { filename = "cloud-init-k3s-agent.yaml" @@ -114,7 +116,8 @@ data "cloudinit_config" "init_docker" { content = templatefile("${path.module}/cloud-init-k3s-agent.yaml", { TF_K3S_TOKEN = random_password.k3s_token.result - TF_K3S_SERVER_IP_ADDRESS = openstack_compute_instance_v2.kubernetes_server.access_ip_v4 + TF_K3S_SERVER_IP_ADDRESS = local.controller_host_instance.ip_address + TF_K3S_NODE_EXTERNAL_IP = each.value.floating_ip != null && each.value.floating_ip.use_floating_ip ? each.value.floating_ip.address : "" } ) } @@ -130,8 +133,9 @@ data "cloudinit_config" "init_docker_controller" { content_type = "text/cloud-config" content = templatefile("${path.module}/cloud-init-k3s-server.yaml", { - TF_K3S_TOKEN = random_password.k3s_token.result - TF_K3S_TLS_SAN = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : "" + TF_K3S_TOKEN = random_password.k3s_token.result + TF_K3S_TLS_SAN = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : "" + TF_K3S_NODE_EXTERNAL_IP = local.controller_host_has_floating_ip ? local.controller_host.floating_ip.address : "" } ) } diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf index a58a8a6..636e74c 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf @@ -93,3 +93,12 @@ variable "network" { error_message = "Either network.name or network.network_id must be provided" } } + +check "controller_floating_ip_required_for_non_default_network" { + assert { + condition = var.network == null || + (var.network.name == "external_4003" && var.network.network_id == null) || + (length([for host in var.host_instances : host if host.is_controller == true && host.floating_ip != null && host.floating_ip.use_floating_ip == true]) == 1) + error_message = "When using a non-default network (network.name != 'external_4003' or network.network_id is set), the controller host must have a floating IP configured with floating_ip.use_floating_ip = true" + } +} From 4b7433b0f5c3dc9acbbbf39b901a36411a39fce7 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 16:12:57 +0000 Subject: [PATCH 22/27] feat(iac): set floating ip for k8s nodes - set node external ip --- .../openstack-kubernetes-infra/cloud-init-k3s-server.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml b/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml index f2c8ba2..8d87e26 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml +++ b/deployment/terraform/modules/openstack-kubernetes-infra/cloud-init-k3s-server.yaml @@ -38,16 +38,16 @@ runcmd: # Run K3s - echo "Installing K3S" - | - INSTALL_K3S_EXEC="server" TF_K3S_TLS_SAN=${TF_K3S_TLS_SAN} TF_K3S_NODE_EXTERNAL_IP=${TF_K3S_NODE_EXTERNAL_IP} + INSTALL_K3S_EXEC="server" if [ -n "$TF_K3S_TLS_SAN" ]; then INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --tls-san $TF_K3S_TLS_SAN" fi if [ -n "$TF_K3S_NODE_EXTERNAL_IP" ]; then INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --node-external-ip $TF_K3S_NODE_EXTERNAL_IP" fi - sudo curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="${INSTALL_K3S_EXEC}" K3S_TOKEN="${TF_K3S_TOKEN}" INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" sh - + sudo curl -sfL https://get.k3s.io | K3S_TOKEN="${TF_K3S_TOKEN}" INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" sh - - echo "Completed Installing K3S" - sudo chmod 644 /etc/rancher/k3s/k3s.yaml From 5b06632226d14bc13d22f928c8a4bfb64a691d02 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 16:15:08 +0000 Subject: [PATCH 23/27] feat(iac): set floating ip for k8s nodes - set node external ip --- .../modules/openstack-kubernetes-infra/variables.tf | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf index 636e74c..a548e91 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/variables.tf @@ -96,9 +96,12 @@ variable "network" { check "controller_floating_ip_required_for_non_default_network" { assert { - condition = var.network == null || - (var.network.name == "external_4003" && var.network.network_id == null) || - (length([for host in var.host_instances : host if host.is_controller == true && host.floating_ip != null && host.floating_ip.use_floating_ip == true]) == 1) - error_message = "When using a non-default network (network.name != 'external_4003' or network.network_id is set), the controller host must have a floating IP configured with floating_ip.use_floating_ip = true" + condition = (var.network == null + || (var.network.name == "external_4003" && var.network.network_id == null) + || (length([for host in var.host_instances : host if host.is_controller == true && host.floating_ip.use_floating_ip == true]) == 1)) + error_message = <<-EOT +When using a non-default network, the controller host should have a floating IP in order to be accessible by the terraform agent +EOT } } + From 7746963d663729bb4cbd030062b17f470151d1c7 Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 16:31:39 +0000 Subject: [PATCH 24/27] feat(iac): set floating ip for k8s nodes - fix server ip --- .../terraform/modules/openstack-kubernetes-infra/compute.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 401f1fd..e68d98a 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -116,7 +116,7 @@ data "cloudinit_config" "init_docker" { content = templatefile("${path.module}/cloud-init-k3s-agent.yaml", { TF_K3S_TOKEN = random_password.k3s_token.result - TF_K3S_SERVER_IP_ADDRESS = local.controller_host_instance.ip_address + TF_K3S_SERVER_IP_ADDRESS = openstack_compute_instance_v2.kubernetes_server.access_ip_v4 TF_K3S_NODE_EXTERNAL_IP = each.value.floating_ip != null && each.value.floating_ip.use_floating_ip ? each.value.floating_ip.address : "" } ) From b8e156c809b3112f4574fb22aeba7b1f73a7f63f Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 16:53:26 +0000 Subject: [PATCH 25/27] feat(iac): add readme for floating ip setup --- .../openstack-kubernetes-infra/README.md | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/README.md b/deployment/terraform/modules/openstack-kubernetes-infra/README.md index 466a0e7..b21981b 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/README.md +++ b/deployment/terraform/modules/openstack-kubernetes-infra/README.md @@ -35,4 +35,54 @@ module "openstack_kubernetes_cluster" { } ``` +## Existing Network and Floating IPs +You can use this module with a custom OpenStack network by specifying the `network` variable. By default, it will use the network named `"external_4003"`, but you can override this with your own network name or network ID. + +Using a custom OpenStack network with your own subnet allows you to improve security by keeping most nodes private. This ensures worker nodes and other internal resources are not directly exposed, reducing security risks. Only the controller node needs a floating IP to be accessible in order to use the k8s api server (eg for kubectl to work from outside the network). Using floating ips will also have the advantage of being stable, so you can destroy/create VMs without having to update anywhere the IP address is referenced by reassigning the floating ip. + +To use this configuration, you will probably need to assign a floating IP to the controller node so that it is accessible. You can configure floating IP assignment per node using the `floating_ip` block within each entry in the `host_instances` variable + +Please see this example for using thism module with a custom network and floating IPs. + +```hcl +host_instances = [ + { + name = "controller" + is_controller = true + floating_ip = { + use_floating_ip = true + address = "203.0.113.10" # Address of an existing floating_ip in openstack + } + }, + { + name = "worker" + # Optionally also assign a floating IP here, or leave blank to keep it internal to the network + } + network = { + network_id = openstack_networking_network_v2.example_network.id + } +] + + +resource "openstack_networking_network_v2" "example_network" { + name = "dev-example-network" + admin_state_up = "true" +} + +resource "openstack_networking_subnet_v2" "example_subnet"{ + name = "dev-example-subnet" + network_id = openstack_networking_network_v2.example_network.id + cidr = "192.168.0.0/24" + ip_version = 4 +} + +resource "openstack_networking_router_v2" "example_router" { + name = "test-router" + admin_state_up = true + external_network_id = data.openstack_networking_network_v2.external_4003.id +} +``` + +When using a non-default network, ensure the controller host has a floating IP so Terraform can access it for provisioning. + From fca3ccf0b53f75685419504d2339c5e998aae72b Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 17:01:42 +0000 Subject: [PATCH 26/27] feat(iac): ignore user_data changes to not recreate after initialised --- .../modules/openstack-kubernetes-infra/compute.tf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index e68d98a..9de0032 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -6,6 +6,7 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { region = "RegionOne" user_data = data.cloudinit_config.init_docker_controller.rendered + security_groups = ["default", openstack_networking_secgroup_v2.cogstack_apps_security_group.name ] @@ -22,6 +23,10 @@ resource "openstack_compute_instance_v2" "kubernetes_server" { destination_type = "volume" delete_on_termination = true } + + lifecycle { + ignore_changes = [user_data] + } } resource "null_resource" "kubernetes_server_provisioner" { @@ -69,6 +74,10 @@ resource "openstack_compute_instance_v2" "kubernetes_nodes" { destination_type = "volume" delete_on_termination = true } + + lifecycle { + ignore_changes = [user_data] + } } locals { From 3f2ba6f9cb5d41567e2298141d153f10a76245ff Mon Sep 17 00:00:00 2001 From: alhendrickson <159636032+alhendrickson@users.noreply.github.com.> Date: Wed, 14 Jan 2026 17:03:56 +0000 Subject: [PATCH 27/27] feat(iac): cleanup --- .../terraform/modules/openstack-cogstack-infra/compute.tf | 3 --- .../terraform/modules/openstack-kubernetes-infra/compute.tf | 4 ---- 2 files changed, 7 deletions(-) diff --git a/deployment/terraform/modules/openstack-cogstack-infra/compute.tf b/deployment/terraform/modules/openstack-cogstack-infra/compute.tf index 0ab8c89..7764a68 100644 --- a/deployment/terraform/modules/openstack-cogstack-infra/compute.tf +++ b/deployment/terraform/modules/openstack-cogstack-infra/compute.tf @@ -125,6 +125,3 @@ data "openstack_images_image_v2" "ubuntu" { most_recent = true } -data "openstack_networking_secgroup_v2" "er_https_from_lbs" { - name = "er_https_from_lbs" -} diff --git a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf index 9de0032..869e888 100644 --- a/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf +++ b/deployment/terraform/modules/openstack-kubernetes-infra/compute.tf @@ -165,7 +165,3 @@ data "openstack_images_image_v2" "ubuntu" { most_recent = true } -data "openstack_networking_secgroup_v2" "er_https_from_lbs" { - name = "er_https_from_lbs" -} -