2026-04-24 16:57:34 -03:00
|
|
|
package plan
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"reflect"
|
|
|
|
|
"strings"
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"metis/pkg/config"
|
|
|
|
|
"metis/pkg/secrets"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestNodeSecretHelpers(t *testing.T) {
|
|
|
|
|
if got := effectiveAtlasPassword(nil); got != "" {
|
|
|
|
|
t.Fatalf("effectiveAtlasPassword(nil) = %q", got)
|
|
|
|
|
}
|
2026-04-24 18:07:14 -03:00
|
|
|
sec := &secrets.NodeSecrets{AtlasPassword: "atlas-pass"}
|
2026-04-24 16:57:34 -03:00
|
|
|
if got := effectiveAtlasPassword(sec); got != "atlas-pass" {
|
2026-04-24 18:07:14 -03:00
|
|
|
t.Fatalf("effectiveAtlasPassword = %q", got)
|
2026-04-24 16:57:34 -03:00
|
|
|
}
|
|
|
|
|
if got := firstNonEmptyString("", " value ", "ignored"); got != "value" {
|
|
|
|
|
t.Fatalf("firstNonEmptyString = %q", got)
|
|
|
|
|
}
|
2026-04-24 18:07:14 -03:00
|
|
|
if !hasNodePasswords(&secrets.NodeSecrets{RootPassword: "root-pass"}) {
|
|
|
|
|
t.Fatal("expected root password to count as password material")
|
2026-04-24 16:57:34 -03:00
|
|
|
}
|
|
|
|
|
if hasNodePasswords(&secrets.NodeSecrets{}) {
|
|
|
|
|
t.Fatal("empty node secrets should not count as password material")
|
|
|
|
|
}
|
|
|
|
|
debug := redactedSecretsForImage(&secrets.NodeSecrets{Extra: map[string]string{"b": "2", "a": "1"}})
|
|
|
|
|
if !reflect.DeepEqual(debug["extra_keys"], []string{"a", "b"}) {
|
|
|
|
|
t.Fatalf("redactedSecretsForImage extra_keys = %#v", debug)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNodeSecretsFromEnvAndMergeNodeSecrets(t *testing.T) {
|
|
|
|
|
t.Setenv("METIS_NODE_ATLAS_PASSWORD", "atlas-pass")
|
|
|
|
|
t.Setenv("METIS_NODE_ROOT_PASSWORD", "root-pass")
|
|
|
|
|
envSecrets := nodeSecretsFromEnv()
|
2026-04-24 18:07:14 -03:00
|
|
|
if envSecrets == nil || envSecrets.RootPassword != "root-pass" || envSecrets.AtlasPassword != "atlas-pass" {
|
2026-04-24 16:57:34 -03:00
|
|
|
t.Fatalf("nodeSecretsFromEnv = %#v", envSecrets)
|
|
|
|
|
}
|
|
|
|
|
merged := mergeNodeSecrets(&secrets.NodeSecrets{
|
2026-04-24 18:07:14 -03:00
|
|
|
AtlasPassword: "base-atlas",
|
|
|
|
|
K3sToken: "base-token",
|
|
|
|
|
CloudInit: "base-cloud",
|
|
|
|
|
Extra: map[string]string{"base": "1"},
|
2026-04-24 16:57:34 -03:00
|
|
|
}, &secrets.NodeSecrets{
|
|
|
|
|
AtlasPassword: "override-atlas",
|
|
|
|
|
RootPassword: "override-root",
|
|
|
|
|
K3sToken: "override-token",
|
|
|
|
|
CloudInit: "override-cloud",
|
|
|
|
|
Extra: map[string]string{"override": "2"},
|
|
|
|
|
})
|
|
|
|
|
if merged.K3sToken != "override-token" || merged.CloudInit != "override-cloud" || merged.AtlasPassword != "override-atlas" || merged.RootPassword != "override-root" {
|
|
|
|
|
t.Fatalf("mergeNodeSecrets = %#v", merged)
|
|
|
|
|
}
|
|
|
|
|
if merged.Extra["base"] != "1" || merged.Extra["override"] != "2" {
|
|
|
|
|
t.Fatalf("mergeNodeSecrets extras = %#v", merged.Extra)
|
|
|
|
|
}
|
2026-04-24 18:07:14 -03:00
|
|
|
if got := mergeNodeSecrets(nil, envSecrets); got.RootPassword != "root-pass" {
|
2026-04-24 16:57:34 -03:00
|
|
|
t.Fatalf("mergeNodeSecrets nil base = %#v", got)
|
|
|
|
|
}
|
2026-04-24 18:07:14 -03:00
|
|
|
if got := mergeNodeSecrets(envSecrets, nil); got.AtlasPassword != "atlas-pass" {
|
2026-04-24 16:57:34 -03:00
|
|
|
t.Fatalf("mergeNodeSecrets nil override = %#v", got)
|
|
|
|
|
}
|
|
|
|
|
t.Setenv("METIS_NODE_ATLAS_PASSWORD", "")
|
|
|
|
|
t.Setenv("METIS_NODE_ROOT_PASSWORD", "")
|
|
|
|
|
if got := nodeSecretsFromEnv(); got != nil {
|
|
|
|
|
t.Fatalf("expected empty env secrets to collapse to nil, got %#v", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 18:07:14 -03:00
|
|
|
func TestFirstbootEnvContentIncludesPasswords(t *testing.T) {
|
2026-04-24 16:57:34 -03:00
|
|
|
cfg := &config.NodeConfig{
|
|
|
|
|
Hostname: "titan-15",
|
|
|
|
|
SSHUser: "atlas",
|
|
|
|
|
K3s: config.K3sConfig{Version: "v1.31.5+k3s1"},
|
|
|
|
|
}
|
|
|
|
|
content := firstbootEnvContent(cfg, &secrets.NodeSecrets{
|
2026-04-24 18:07:14 -03:00
|
|
|
AtlasPassword: "atlas-pass",
|
|
|
|
|
RootPassword: "root-pass",
|
2026-04-24 16:57:34 -03:00
|
|
|
})
|
|
|
|
|
if !reflect.DeepEqual(parseEnvLines(content), map[string]string{
|
2026-04-24 18:07:14 -03:00
|
|
|
"METIS_HOSTNAME": "'titan-15'",
|
|
|
|
|
"METIS_SSH_USER": "'atlas'",
|
|
|
|
|
"METIS_ATLAS_USER": "'atlas'",
|
|
|
|
|
"METIS_K3S_VERSION": "'v1.31.5+k3s1'",
|
|
|
|
|
"METIS_ATLAS_PASSWORD": "'atlas-pass'",
|
|
|
|
|
"METIS_ROOT_PASSWORD": "'root-pass'",
|
2026-04-24 16:57:34 -03:00
|
|
|
}) {
|
|
|
|
|
t.Fatalf("firstbootEnvContent = %q", content)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseEnvLines(raw string) map[string]string {
|
|
|
|
|
result := map[string]string{}
|
|
|
|
|
for _, line := range strings.Split(strings.TrimSpace(raw), "\n") {
|
|
|
|
|
parts := strings.SplitN(line, "=", 2)
|
|
|
|
|
if len(parts) != 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
result[parts[0]] = parts[1]
|
|
|
|
|
}
|
|
|
|
|
return result
|
|
|
|
|
}
|