diff --git a/contexts/_template/blueprint.jsonnet b/contexts/_template/blueprint.jsonnet
index b2eaae0d..d5007aad 100644
--- a/contexts/_template/blueprint.jsonnet
+++ b/contexts/_template/blueprint.jsonnet
@@ -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 {},
}
]
};
@@ -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 + {
diff --git a/terraform/cluster/talos/README.md b/terraform/cluster/talos/README.md
index 73f53b19..14602c83 100644
--- a/terraform/cluster/talos/README.md
+++ b/terraform/cluster/talos/README.md
@@ -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 |
@@ -49,4 +47,4 @@
## Outputs
No outputs.
-
\ No newline at end of file
+
diff --git a/terraform/cluster/talos/main.tf b/terraform/cluster/talos/main.tf
index 98038977..8f669430 100644
--- a/terraform/cluster/talos/main.tf
+++ b/terraform/cluster/talos/main.tf
@@ -6,6 +6,9 @@ terraform {
source = "siderolabs/talos"
version = "0.8.1"
}
+ local = {
+ source = "hashicorp/local"
+ }
}
}
@@ -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"
@@ -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,
@@ -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,
@@ -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,
@@ -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
diff --git a/terraform/cluster/talos/modules/machine/.terraform.lock.hcl b/terraform/cluster/talos/modules/machine/.terraform.lock.hcl
index 8c436b2f..2418f380 100644
--- a/terraform/cluster/talos/modules/machine/.terraform.lock.hcl
+++ b/terraform/cluster/talos/modules/machine/.terraform.lock.hcl
@@ -1,6 +1,25 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
+provider "registry.terraform.io/hashicorp/local" {
+ version = "2.5.3"
+ hashes = [
+ "h1:MCzg+hs1/ZQ32u56VzJMWP9ONRQPAAqAjuHuzbyshvI=",
+ "zh:284d4b5b572eacd456e605e94372f740f6de27b71b4e1fd49b63745d8ecd4927",
+ "zh:40d9dfc9c549e406b5aab73c023aa485633c1b6b730c933d7bcc2fa67fd1ae6e",
+ "zh:6243509bb208656eb9dc17d3c525c89acdd27f08def427a0dce22d5db90a4c8b",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:885d85869f927853b6fe330e235cd03c337ac3b933b0d9ae827ec32fa1fdcdbf",
+ "zh:bab66af51039bdfcccf85b25fe562cbba2f54f6b3812202f4873ade834ec201d",
+ "zh:c505ff1bf9442a889ac7dca3ac05a8ee6f852e0118dd9a61796a2f6ff4837f09",
+ "zh:d36c0b5770841ddb6eaf0499ba3de48e5d4fc99f4829b6ab66b0fab59b1aaf4f",
+ "zh:ddb6a407c7f3ec63efb4dad5f948b54f7f4434ee1a2607a49680d494b1776fe1",
+ "zh:e0dafdd4500bec23d3ff221e3a9b60621c5273e5df867bc59ef6b7e41f5c91f6",
+ "zh:ece8742fd2882a8fc9d6efd20e2590010d43db386b920b2a9c220cfecc18de47",
+ "zh:f4c6b3eb8f39105004cf720e202f04f57e3578441cfb76ca27611139bc116a82",
+ ]
+}
+
provider "registry.terraform.io/hashicorp/null" {
version = "3.2.4"
hashes = [
diff --git a/terraform/cluster/talos/modules/machine/main.tf b/terraform/cluster/talos/modules/machine/main.tf
index f8ab6323..9b5ff936 100644
--- a/terraform/cluster/talos/modules/machine/main.tf
+++ b/terraform/cluster/talos/modules/machine/main.tf
@@ -11,6 +11,9 @@ terraform {
null = {
source = "hashicorp/null"
}
+ local = {
+ source = "hashicorp/local"
+ }
}
}
@@ -78,6 +81,32 @@ 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
#-----------------------------------------------------------------------------------------------------------------------
@@ -85,6 +114,9 @@ resource "talos_machine_bootstrap" "bootstrap" {
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" {
@@ -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 : ""
} : {}
}
}
diff --git a/terraform/cluster/talos/modules/machine/output.tf b/terraform/cluster/talos/modules/machine/output.tf
index 607b7052..3434f2e9 100644
--- a/terraform/cluster/talos/modules/machine/output.tf
+++ b/terraform/cluster/talos/modules/machine/output.tf
@@ -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
+}
diff --git a/terraform/cluster/talos/modules/machine/test.tftest.hcl b/terraform/cluster/talos/modules/machine/test.tftest.hcl
index bff71892..1ea93769 100644
--- a/terraform/cluster/talos/modules/machine/test.tftest.hcl
+++ b/terraform/cluster/talos/modules/machine/test.tftest.hcl
@@ -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"
@@ -56,6 +61,7 @@ variables {
kubernetes_version = "dummy"
talos_version = "1.10.1"
talosconfig_path = "/tmp/dummy-talosconfig"
+ kubeconfig_path = ""
enable_health_check = false
}
@@ -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"
+ }
+}
diff --git a/terraform/cluster/talos/modules/machine/variables.tf b/terraform/cluster/talos/modules/machine/variables.tf
index 54ae088a..307509ab 100644
--- a/terraform/cluster/talos/modules/machine/variables.tf
+++ b/terraform/cluster/talos/modules/machine/variables.tf
@@ -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 = ""
+}
diff --git a/terraform/cluster/talos/test.tftest.hcl b/terraform/cluster/talos/test.tftest.hcl
index 3d5289c5..e8bfbf98 100644
--- a/terraform/cluster/talos/test.tftest.hcl
+++ b/terraform/cluster/talos/test.tftest.hcl
@@ -21,10 +21,7 @@ run "minimal_configuration" {
error_message = "Talos config file should be generated"
}
- assert {
- condition = length(local_sensitive_file.kubeconfig) == 1
- error_message = "Kubeconfig file should be generated"
- }
+
assert {
condition = module.controlplane_bootstrap.node == "192.168.1.10"
@@ -208,10 +205,7 @@ run "no_config_files" {
error_message = "No Talos config file should be generated without context path"
}
- assert {
- condition = length(local_sensitive_file.kubeconfig) == 0
- error_message = "No Kubeconfig file should be generated without context path"
- }
+
}
# Verifies that all input validation rules are enforced simultaneously, ensuring that
diff --git a/terraform/gitops/flux/README.md b/terraform/gitops/flux/README.md
index 1b4b9f37..e6de5560 100644
--- a/terraform/gitops/flux/README.md
+++ b/terraform/gitops/flux/README.md
@@ -31,9 +31,9 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
-| [flux\_helm\_version](#input\_flux\_helm\_version) | The version of Flux Helm chart to install | `string` | `"2.16.2"` | no |
+| [flux\_helm\_version](#input\_flux\_helm\_version) | The version of Flux Helm chart to install | `string` | `"2.16.3"` | no |
| [flux\_namespace](#input\_flux\_namespace) | The namespace in which Flux will be installed | `string` | `"system-gitops"` | no |
-| [flux\_version](#input\_flux\_version) | The version of Flux to install | `string` | `"2.6.3"` | no |
+| [flux\_version](#input\_flux\_version) | The version of Flux to install | `string` | `"2.6.4"` | no |
| [git\_auth\_secret](#input\_git\_auth\_secret) | The name of the secret to store the git authentication details | `string` | `"flux-system"` | no |
| [git\_password](#input\_git\_password) | The git password or PAT used to authenticte with the git provider | `string` | `""` | no |
| [git\_username](#input\_git\_username) | The git user to use to authenticte with the git provider | `string` | `"git"` | no |