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
2 changes: 1 addition & 1 deletion charts/cozystack/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ cluster:
{{- toYaml .Values.podSubnets | nindent 6 }}
serviceSubnets:
{{- toYaml .Values.serviceSubnets | nindent 6 }}
clusterName: "{{ .Chart.Name }}"
clusterName: {{ .Values.clusterName | default .Chart.Name | regexFind "^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" | required "clusterName must be a valid DNS-1123 label" | quote }}
controlPlane:
endpoint: {{ required "values.yaml: `endpoint` must be set to the cluster control-plane URL (e.g. https://<vip>:6443). This field is cluster-wide: every node's kubelet and kube-proxy dials it, so it cannot be auto-derived from the current node's IP -- `talm template` runs once per node and has no way to reconcile per-node IPs into a single shared endpoint. For multi-node setups use a VIP (cozystack floatingIP) or an external load balancer; for single-node clusters the node's routable IP works." .Values.endpoint | quote }}
{{- if eq .MachineType "controlplane" }}
Expand Down
6 changes: 6 additions & 0 deletions charts/cozystack/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
# Example: endpoint: "https://192.168.0.1:6443"
endpoint: ""

# Optional override for the cluster's name (defaults to Chart.Name).
# Note that changing this value on a live cluster is considered
# dangerous as it is baked into PKI (cert SANs) and ETCD identity at
# bootstrap.
clusterName: ""

clusterDomain: cozy.local
# Layer-2 VIP for cozystack multi-node setups. When set, the chart
# emits a Layer2VIPConfig document pinning this IP as a floating
Expand Down
3 changes: 2 additions & 1 deletion charts/generic/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@ machine:

{{- /* Shared cluster section */ -}}
{{- define "talos.config.cluster" }}

cluster:
network:
podSubnets:
{{- toYaml .Values.podSubnets | nindent 6 }}
serviceSubnets:
{{- toYaml .Values.serviceSubnets | nindent 6 }}
clusterName: "{{ .Chart.Name }}"
clusterName: {{ .Values.clusterName | default .Chart.Name | regexFind "^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" | required "clusterName must be a valid DNS-1123 label" | quote }}
controlPlane:
endpoint: {{ required "values.yaml: `endpoint` must be set to the cluster control-plane URL (e.g. https://<vip>:6443). This field is cluster-wide: every node's kubelet and kube-proxy dials it, so it cannot be auto-derived from the current node's IP -- `talm template` runs once per node and has no way to reconcile per-node IPs into a single shared endpoint. For multi-node setups use a VIP or an external load balancer; for single-node clusters the node's routable IP works." .Values.endpoint | quote }}
{{- if eq .MachineType "controlplane" }}
Expand Down
6 changes: 6 additions & 0 deletions charts/generic/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ floatingIP: ""
# Example: vipLink: eth0.4000
vipLink: ""

# Optional override for the cluster's name (defaults to Chart.Name).
# Note that changing this value on a live cluster is considered
# dangerous as it is baked into PKI (cert SANs) and ETCD identity at
# bootstrap.
clusterName: ""

podSubnets:
- 10.244.0.0/16
serviceSubnets:
Expand Down
16 changes: 13 additions & 3 deletions pkg/commands/talosconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ This command:
4. Re-encrypts if encryption is used

Use this command when your client certificate has expired.`,
Args: cobra.NoArgs,
Args: cobra.NoArgs,
PreRunE: func(cmd *cobra.Command, args []string) error {
// Ensure project root is detected
if !Config.RootDirExplicit {
Expand Down Expand Up @@ -190,8 +190,19 @@ func regenerateTalosconfig() error {
return nil
}

// getClusterNameFromChart reads the cluster name from Chart.yaml
// getClusterNameFromChart reads the cluster name from values.yaml or Chart.yaml
func getClusterNameFromChart() string {
valuesYamlPath := filepath.Join(Config.RootDir, "values.yaml")
if data, err := os.ReadFile(valuesYamlPath); err == nil {
var valuesData struct {
ClusterName string `yaml:"clusterName"`
}

if err = yaml.Unmarshal(data, &valuesData); err == nil && valuesData.ClusterName != "" {
return valuesData.ClusterName
}
}

chartYamlPath := filepath.Join(Config.RootDir, "Chart.yaml")
data, err := os.ReadFile(chartYamlPath)
if err != nil {
Expand All @@ -208,4 +219,3 @@ func getClusterNameFromChart() string {

return chartData.Name
}

86 changes: 82 additions & 4 deletions pkg/engine/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func TestLegacyCozystack_ControlPlane(t *testing.T) {

// Legacy format: cluster section present
assertContains(t, output, "cluster:")
assertContains(t, output, "clusterName:")
assertContains(t, output, "clusterName: \"cozystack\"")
assertContains(t, output, "controlPlane:")
assertContains(t, output, "endpoint:")

Expand Down Expand Up @@ -289,7 +289,7 @@ func TestLegacyGeneric_ControlPlane(t *testing.T) {

// Legacy format: cluster section present
assertContains(t, output, "cluster:")
assertContains(t, output, "clusterName:")
assertContains(t, output, "clusterName: \"generic\"")
assertContains(t, output, "controlPlane:")
assertContains(t, output, "endpoint:")

Expand Down Expand Up @@ -342,7 +342,7 @@ func TestMultiDocCozystack_ControlPlane(t *testing.T) {

// Multi-doc: cluster section unchanged
assertContains(t, output, "cluster:")
assertContains(t, output, "clusterName:")
assertContains(t, output, "clusterName: \"cozystack\"")
assertContains(t, output, "controlPlane:")
assertContains(t, output, "allowSchedulingOnControlPlanes:")
assertContains(t, output, "etcd:")
Expand Down Expand Up @@ -504,7 +504,7 @@ func TestMultiDocGeneric_ControlPlane(t *testing.T) {

// Multi-doc: cluster section still present
assertContains(t, output, "cluster:")
assertContains(t, output, "clusterName:")
assertContains(t, output, "clusterName: \"generic\"")
assertContains(t, output, "controlPlane:")
assertContains(t, output, "endpoint:")

Expand Down Expand Up @@ -4107,6 +4107,84 @@ func TestMultiDocCozystack_EndpointRequired(t *testing.T) {
}
}

// TestMultiDocCozystack_InvalidClusterNameOverride ensures invalid
// clusterName overrides are rejected
func TestMultiDocCozystack_InvalidClusterNameOverride(t *testing.T) {
origLookup := helmEngine.LookupFunc
t.Cleanup(func() { helmEngine.LookupFunc = origLookup })
helmEngine.LookupFunc = simpleNicLookup()

chrt, err := loader.LoadDir("../../charts/cozystack")
if err != nil {
t.Fatalf("load chart: %v", err)
}
values := make(map[string]any)
maps.Copy(values, chrt.Values)
values["clusterName"] = "InvalidClusterName"

eng := helmEngine.Engine{}
_, err = eng.Render(chrt, chartutil.Values{
"Values": values,
"TalosVersion": "v1.12",
})
if err == nil {
t.Fatal("expected render to fail with required() error when clusterName is invalid")
}
if !strings.Contains(err.Error(), "clusterName") {
t.Errorf("error should mention 'clusterName'; got: %v", err)
}
}

// TestMultiDocCozystack_ValidClusterNameOverride ensures clusterName
// overrides make it through to the result.
func TestMultiDocCozystack_ValidClusterNameOverride(t *testing.T) {
result := renderCozystackWith(t, simpleNicLookup(), map[string]any{
"clusterName": "differentclustername",
})

assertContains(t, result, "clusterName: \"differentclustername\"")
}

// TestMultiDocGeneric_InvalidSubnetsFallsBackToDiscovery mirrors the
// cozystack-side smoke test for ensuring invalid clusterName
// overrides are rejected.
func TestMultiDocGeneric_InvalidClusterNameOverride(t *testing.T) {
origLookup := helmEngine.LookupFunc
t.Cleanup(func() { helmEngine.LookupFunc = origLookup })
helmEngine.LookupFunc = simpleNicLookup()

chrt, err := loader.LoadDir("../../charts/generic")
if err != nil {
t.Fatalf("load chart: %v", err)
}
values := make(map[string]any)
maps.Copy(values, chrt.Values)
values["clusterName"] = "InvalidClusterName"

eng := helmEngine.Engine{}
_, err = eng.Render(chrt, chartutil.Values{
"Values": values,
"TalosVersion": "v1.12",
})
if err == nil {
t.Fatal("expected render to fail with required() error when clusterName is invalid")
}
if !strings.Contains(err.Error(), "clusterName") {
t.Errorf("error should mention 'clusterName'; got: %v", err)
}
}

// TestMultiDocGeneric_ValidSubnetsFallsBackToDiscovery mirrors the
// cozystack-side smoke test for ensuring clusterName overrides make
// it through to the result.
func TestMultiDocGeneric_ValidClusterNameOverride(t *testing.T) {
result := renderGenericWith(t, simpleNicLookup(), map[string]any{
"clusterName": "differentclustername",
})

assertContains(t, result, "clusterName: \"differentclustername\"")
}

// TestMultiDocGeneric_ValidSubnetsFallsBackToDiscovery mirrors the
// cozystack-side smoke test for the generic preset. A single
// representative assertion proves the edits apply symmetrically to
Expand Down