Skip to content
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
17 changes: 5 additions & 12 deletions contexts/_template/blueprint.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,16 @@ local terraformConfigs = {
"local": [
{
path: "cluster/talos",
parallelism: 1,
},
{
path: "gitops/flux",
destroy: false,
values: {
values: if rawProvider == "local" then {
git_username: "local",
git_password: "local",
git_password: "local",
webhook_token: "abcdef123456",
},
} else {},
}
]
};
Expand Down Expand Up @@ -431,15 +432,7 @@ local blueprintMetadata = {
};

// Source configuration
local sourceConfig = [
{
name: "core",
url: "github.com/windsorcli/core",
ref: {
branch: "main",
},
},
];
local sourceConfig = [];

// Start of Blueprint
blueprintMetadata + {
Expand Down
4 changes: 1 addition & 3 deletions terraform/cluster/talos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@

| Name | Type |
|------|------|
| [local_sensitive_file.kubeconfig](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/sensitive_file) | resource |
| [local_sensitive_file.talosconfig](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/sensitive_file) | resource |
| [talos_cluster_kubeconfig.this](https://registry.terraform.io/providers/siderolabs/talos/0.8.1/docs/resources/cluster_kubeconfig) | resource |
| [talos_machine_secrets.this](https://registry.terraform.io/providers/siderolabs/talos/0.8.1/docs/resources/machine_secrets) | resource |
| [talos_client_configuration.this](https://registry.terraform.io/providers/siderolabs/talos/0.8.1/docs/data-sources/client_configuration) | data source |

Expand All @@ -49,4 +47,4 @@
## Outputs

No outputs.
<!-- END_TF_DOCS -->
<!-- END_TF_DOCS -->
29 changes: 6 additions & 23 deletions terraform/cluster/talos/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ terraform {
source = "siderolabs/talos"
version = "0.8.1"
}
local = {
source = "hashicorp/local"
}
}
}

Expand All @@ -24,7 +27,6 @@ resource "talos_machine_secrets" "this" {
locals {
// Local variables for configuration paths and data
talosconfig = data.talos_client_configuration.this.talos_config
kubeconfig = talos_cluster_kubeconfig.this.kubeconfig_raw

talosconfig_path = "${var.context_path}/.talos/config"
kubeconfig_path = "${var.context_path}/.kube/config"
Expand All @@ -51,6 +53,7 @@ module "controlplane_bootstrap" {
endpoint = var.controlplanes[0].endpoint
bootstrap = true // Bootstrap the first control plane node
talosconfig_path = local.talosconfig_path
kubeconfig_path = local.kubeconfig_path
enable_health_check = true
config_patches = compact(concat([
var.common_config_patches,
Expand Down Expand Up @@ -79,6 +82,7 @@ module "controlplanes" {
endpoint = var.controlplanes[count.index + 1].endpoint
bootstrap = false // Do not bootstrap other control plane nodes
talosconfig_path = local.talosconfig_path
kubeconfig_path = local.kubeconfig_path
enable_health_check = true
config_patches = compact(concat([
var.common_config_patches,
Expand Down Expand Up @@ -110,6 +114,7 @@ module "workers" {
machine_type = "worker"
endpoint = var.workers[count.index].endpoint
talosconfig_path = local.talosconfig_path
kubeconfig_path = local.kubeconfig_path
enable_health_check = true
config_patches = compact(concat([
var.common_config_patches,
Expand All @@ -122,34 +127,12 @@ module "workers" {
# Config Files
#-----------------------------------------------------------------------------------------------------------------------

resource "talos_cluster_kubeconfig" "this" {
depends_on = [module.controlplane_bootstrap]

client_configuration = talos_machine_secrets.this.client_configuration
node = var.controlplanes[0].node
endpoint = var.controlplanes[0].endpoint
}

data "talos_client_configuration" "this" {
cluster_name = var.cluster_name
client_configuration = talos_machine_secrets.this.client_configuration
endpoints = var.controlplanes.*.endpoint
}

// Write kubeconfig to a local file
resource "local_sensitive_file" "kubeconfig" {
count = trim(var.context_path, " ") != "" ? 1 : 0 // Create file only if path is specified and not empty/whitespace
depends_on = [local_sensitive_file.talosconfig] // Ensure Talos config is written first

content = talos_cluster_kubeconfig.this.kubeconfig_raw
filename = local.kubeconfig_path
file_permission = "0600" // Set file permissions to read/write for owner only

lifecycle {
ignore_changes = [content] // Ignore changes to content to prevent unnecessary updates
}
}

// Write Talos config to a local file
resource "local_sensitive_file" "talosconfig" {
count = trim(var.context_path, " ") != "" ? 1 : 0 // Create file only if path is specified and not empty/whitespace
Expand Down
19 changes: 19 additions & 0 deletions terraform/cluster/talos/modules/machine/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 36 additions & 2 deletions terraform/cluster/talos/modules/machine/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ terraform {
null = {
source = "hashicorp/null"
}
local = {
source = "hashicorp/local"
}
}
}

Expand Down Expand Up @@ -78,13 +81,42 @@ resource "talos_machine_bootstrap" "bootstrap" {
client_configuration = var.client_configuration
}

#-----------------------------------------------------------------------------------------------------------------------
# Kubeconfig Generation
#-----------------------------------------------------------------------------------------------------------------------

resource "talos_cluster_kubeconfig" "this" {
count = var.bootstrap ? 1 : 0
depends_on = [talos_machine_bootstrap.bootstrap]

client_configuration = var.client_configuration
node = var.node
endpoint = var.endpoint
}

// Write kubeconfig to a local file when bootstrap is true
resource "local_sensitive_file" "kubeconfig" {
count = var.bootstrap && trim(var.kubeconfig_path, " ") != "" ? 1 : 0

content = talos_cluster_kubeconfig.this[0].kubeconfig_raw
filename = var.kubeconfig_path
file_permission = "0600" // Set file permissions to read/write for owner only

lifecycle {
ignore_changes = [content] // Ignore changes to content to prevent unnecessary updates
}
}

#-----------------------------------------------------------------------------------------------------------------------
# Node Health Check
#-----------------------------------------------------------------------------------------------------------------------

locals {
# Use hostname if available, otherwise fall back to node address
node_name = var.hostname != null && var.hostname != "" ? var.hostname : var.node

# Always use Talos API; during bootstrap also check Kubernetes API
health_check_command = var.bootstrap ? "windsor check node-health --nodes ${local.node_name} --timeout 5m --k8s-endpoint" : "windsor check node-health --nodes ${local.node_name} --timeout 5m"
}

resource "null_resource" "node_healthcheck" {
Expand All @@ -94,13 +126,15 @@ resource "null_resource" "node_healthcheck" {

depends_on = [
talos_machine_configuration_apply.this,
talos_machine_bootstrap.bootstrap
talos_machine_bootstrap.bootstrap,
local_sensitive_file.kubeconfig
]

provisioner "local-exec" {
command = var.enable_health_check ? "windsor check node-health --nodes ${local.node_name} --timeout 5m" : "echo 'Health check disabled for testing'"
command = var.enable_health_check ? local.health_check_command : "echo 'Health check disabled'"
environment = var.enable_health_check ? {
TALOSCONFIG = var.talosconfig_path
KUBECONFIG = var.bootstrap ? var.kubeconfig_path : ""
} : {}
}
}
6 changes: 6 additions & 0 deletions terraform/cluster/talos/modules/machine/output.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ output "node" {
output "endpoint" {
value = var.endpoint
}

output "kubeconfig" {
description = "The generated kubeconfig when bootstrap is true"
value = var.bootstrap ? talos_cluster_kubeconfig.this[0].kubeconfig_raw : null
sensitive = true
}
117 changes: 117 additions & 0 deletions terraform/cluster/talos/modules/machine/test.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ mock_provider "talos" {
mock_resource "talos_machine_configuration" {}
mock_resource "talos_machine_configuration_apply" {}
mock_resource "talos_machine_bootstrap" {}
mock_resource "talos_cluster_kubeconfig" {}
}

mock_provider "null" {
mock_resource "null_resource" {}
}

mock_provider "local" {
mock_resource "local_sensitive_file" {}
}

variables {
machine_type = "controlplane"
endpoint = "dummy"
Expand Down Expand Up @@ -56,6 +61,7 @@ variables {
kubernetes_version = "dummy"
talos_version = "1.10.1"
talosconfig_path = "/tmp/dummy-talosconfig"
kubeconfig_path = ""
enable_health_check = false
}

Expand Down Expand Up @@ -162,3 +168,114 @@ run "config_patches_includes_extra" {
error_message = "Should include nameservers in extra patch"
}
}

run "bootstrap_mode_generates_kubeconfig" {
variables {
bootstrap = true
kubeconfig_path = "/tmp/test-kubeconfig"
disk_selector = null
hostname = "test-node"
}

assert {
condition = length(talos_cluster_kubeconfig.this) == 1
error_message = "Should create kubeconfig resource when bootstrap is true"
}

assert {
condition = length(local_sensitive_file.kubeconfig) == 1
error_message = "Should create kubeconfig file when bootstrap is true and path is provided"
}

assert {
condition = local_sensitive_file.kubeconfig[0].filename == "/tmp/test-kubeconfig"
error_message = "Should write kubeconfig to specified path"
}
}

run "non_bootstrap_mode_no_kubeconfig" {
variables {
bootstrap = false
kubeconfig_path = "/tmp/test-kubeconfig"
disk_selector = null
hostname = "test-node"
}

assert {
condition = length(talos_cluster_kubeconfig.this) == 0
error_message = "Should not create kubeconfig resource when bootstrap is false"
}

assert {
condition = length(local_sensitive_file.kubeconfig) == 0
error_message = "Should not create kubeconfig file when bootstrap is false"
}
}

run "bootstrap_mode_empty_kubeconfig_path" {
variables {
bootstrap = true
kubeconfig_path = ""
disk_selector = null
hostname = "test-node"
}

assert {
condition = length(talos_cluster_kubeconfig.this) == 1
error_message = "Should create kubeconfig resource when bootstrap is true"
}

assert {
condition = length(local_sensitive_file.kubeconfig) == 0
error_message = "Should not create kubeconfig file when path is empty"
}
}

run "health_check_command_bootstrap_mode" {
variables {
bootstrap = true
hostname = "test-node"
disk_selector = null
}

assert {
condition = strcontains(local.health_check_command, "--k8s-endpoint")
error_message = "Should include --k8s-endpoint flag during bootstrap"
}

assert {
condition = strcontains(local.health_check_command, "test-node")
error_message = "Should include node name in health check command"
}
}

run "health_check_command_non_bootstrap_mode" {
variables {
bootstrap = false
hostname = "test-node"
disk_selector = null
}

assert {
condition = !strcontains(local.health_check_command, "--k8s-endpoint")
error_message = "Should not include --k8s-endpoint flag after bootstrap"
}

assert {
condition = strcontains(local.health_check_command, "test-node")
error_message = "Should include node name in health check command"
}
}

run "health_check_command_without_hostname" {
variables {
bootstrap = true
hostname = ""
disk_selector = null
}

assert {
condition = strcontains(local.health_check_command, "dummy")
error_message = "Should use node address when hostname is empty"
}
}
6 changes: 6 additions & 0 deletions terraform/cluster/talos/modules/machine/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,9 @@ variable "enable_health_check" {
type = bool
default = true
}

variable "kubeconfig_path" {
description = "Path where the kubeconfig file should be written when bootstrap is true."
type = string
default = ""
}
Loading
Loading