Utility tool for upgrading talos nodes.
1package cmd
2
3import (
4 "context"
5 "sync"
6 "testing"
7
8 "github.com/evanjarrett/homelab/internal/config"
9 "github.com/evanjarrett/homelab/internal/talos"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12)
13
14// ============================================================================
15// runStatusWithClient() Tests
16// ============================================================================
17
18func TestRunStatusWithClient_AllNodesReachable(t *testing.T) {
19 cfg = &config.Config{
20 Settings: config.Settings{
21 FactoryBaseURL: "https://factory.talos.dev",
22 DefaultTimeoutSeconds: 600,
23 },
24 Profiles: map[string]config.Profile{
25 "profile-a": {Arch: "amd64", Platform: "metal", Secureboot: false},
26 },
27 Nodes: []config.Node{
28 {IP: "192.168.1.1", Profile: "profile-a", Role: config.RoleControlPlane},
29 {IP: "192.168.1.2", Profile: "profile-a", Role: config.RoleWorker},
30 },
31 }
32
33 mock := &talos.MockClient{
34 GetNodeStatusFunc: func(ctx context.Context, nodeIP, profile, role string, secureboot bool) talos.NodeStatus {
35 return talos.NodeStatus{
36 IP: nodeIP,
37 Profile: profile,
38 Role: role,
39 Version: "1.9.0",
40 Reachable: true,
41 Secureboot: secureboot,
42 }
43 },
44 }
45
46 err := runStatusWithClient(context.Background(), mock)
47 require.NoError(t, err)
48}
49
50func TestRunStatusWithClient_SomeNodesUnreachable(t *testing.T) {
51 cfg = &config.Config{
52 Settings: config.Settings{
53 FactoryBaseURL: "https://factory.talos.dev",
54 DefaultTimeoutSeconds: 600,
55 },
56 Profiles: map[string]config.Profile{
57 "profile-a": {Arch: "amd64", Platform: "metal", Secureboot: false},
58 },
59 Nodes: []config.Node{
60 {IP: "192.168.1.1", Profile: "profile-a", Role: config.RoleControlPlane},
61 {IP: "192.168.1.2", Profile: "profile-a", Role: config.RoleWorker},
62 },
63 }
64
65 mock := &talos.MockClient{
66 GetNodeStatusFunc: func(ctx context.Context, nodeIP, profile, role string, secureboot bool) talos.NodeStatus {
67 reachable := nodeIP == "192.168.1.1" // Only first node is reachable
68 version := "1.9.0"
69 if !reachable {
70 version = "N/A"
71 }
72 return talos.NodeStatus{
73 IP: nodeIP,
74 Profile: profile,
75 Role: role,
76 Version: version,
77 Reachable: reachable,
78 Secureboot: secureboot,
79 }
80 },
81 }
82
83 err := runStatusWithClient(context.Background(), mock)
84 require.NoError(t, err)
85}
86
87func TestRunStatusWithClient_MixedRoles(t *testing.T) {
88 cfg = &config.Config{
89 Settings: config.Settings{
90 FactoryBaseURL: "https://factory.talos.dev",
91 DefaultTimeoutSeconds: 600,
92 },
93 Profiles: map[string]config.Profile{
94 "profile-a": {Arch: "amd64", Platform: "metal", Secureboot: false},
95 "profile-b": {Arch: "arm64", Platform: "metal", Secureboot: true},
96 },
97 Nodes: []config.Node{
98 {IP: "192.168.1.1", Profile: "profile-a", Role: config.RoleControlPlane},
99 {IP: "192.168.1.2", Profile: "profile-a", Role: config.RoleWorker},
100 {IP: "192.168.1.3", Profile: "profile-b", Role: config.RoleControlPlane},
101 {IP: "192.168.1.4", Profile: "profile-b", Role: config.RoleWorker},
102 },
103 }
104
105 var mu sync.Mutex
106 calledWith := make(map[string]bool)
107 mock := &talos.MockClient{
108 GetNodeStatusFunc: func(ctx context.Context, nodeIP, profile, role string, secureboot bool) talos.NodeStatus {
109 mu.Lock()
110 calledWith[nodeIP] = true
111 mu.Unlock()
112 return talos.NodeStatus{
113 IP: nodeIP,
114 Profile: profile,
115 Role: role,
116 Version: "1.9.0",
117 Reachable: true,
118 Secureboot: secureboot,
119 }
120 },
121 }
122
123 err := runStatusWithClient(context.Background(), mock)
124 require.NoError(t, err)
125
126 // All nodes should have been queried
127 assert.True(t, calledWith["192.168.1.1"])
128 assert.True(t, calledWith["192.168.1.2"])
129 assert.True(t, calledWith["192.168.1.3"])
130 assert.True(t, calledWith["192.168.1.4"])
131}
132
133func TestRunStatusWithClient_SecurebootIndicators(t *testing.T) {
134 cfg = &config.Config{
135 Settings: config.Settings{
136 FactoryBaseURL: "https://factory.talos.dev",
137 DefaultTimeoutSeconds: 600,
138 },
139 Profiles: map[string]config.Profile{
140 "secureboot": {Arch: "amd64", Platform: "metal", Secureboot: true},
141 "no-secureboot": {Arch: "amd64", Platform: "metal", Secureboot: false},
142 },
143 Nodes: []config.Node{
144 {IP: "192.168.1.1", Profile: "secureboot", Role: config.RoleControlPlane},
145 {IP: "192.168.1.2", Profile: "no-secureboot", Role: config.RoleWorker},
146 },
147 }
148
149 var mu sync.Mutex
150 securebootNodes := make(map[string]bool)
151 mock := &talos.MockClient{
152 GetNodeStatusFunc: func(ctx context.Context, nodeIP, profile, role string, secureboot bool) talos.NodeStatus {
153 mu.Lock()
154 securebootNodes[nodeIP] = secureboot
155 mu.Unlock()
156 return talos.NodeStatus{
157 IP: nodeIP,
158 Profile: profile,
159 Role: role,
160 Version: "1.9.0",
161 Reachable: true,
162 Secureboot: secureboot,
163 }
164 },
165 }
166
167 err := runStatusWithClient(context.Background(), mock)
168 require.NoError(t, err)
169
170 // Verify correct secureboot values were passed
171 assert.True(t, securebootNodes["192.168.1.1"], "secureboot profile should have secureboot=true")
172 assert.False(t, securebootNodes["192.168.1.2"], "no-secureboot profile should have secureboot=false")
173}
174
175func TestRunStatusWithClient_EmptyConfig(t *testing.T) {
176 cfg = &config.Config{
177 Settings: config.Settings{
178 FactoryBaseURL: "https://factory.talos.dev",
179 DefaultTimeoutSeconds: 600,
180 },
181 Profiles: map[string]config.Profile{},
182 Nodes: []config.Node{},
183 }
184
185 mock := &talos.MockClient{}
186
187 err := runStatusWithClient(context.Background(), mock)
188 require.NoError(t, err)
189}