1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
package control
import (
"context"
"testing"
)
func TestSetNodeEnabled(t *testing.T) {
t.Parallel()
node := Node{ID: "nl-01", Enabled: true}
disabled := SetNodeEnabled(node, false)
if disabled.Enabled {
t.Fatal("expected node to be disabled")
}
if node.Enabled != true {
t.Fatal("expected original node to stay unchanged")
}
}
func TestRotateNodeSecrets(t *testing.T) {
t.Parallel()
node := Node{
ID: "nl-01",
Protocols: []ProtocolProfile{
{Type: "vless", Enabled: true, Port: 443, Auth: &AuthProfile{UUID: "old-vless"}},
{Type: "vmess", Enabled: true, Port: 8444, Auth: &AuthProfile{UUID: "old-vmess"}},
{Type: "shadowsocks", Enabled: true, Port: 8443, Auth: &AuthProfile{Method: "2022-blake3-aes-128-gcm", Password: "old-ss"}},
{Type: "hysteria2", Enabled: true, Port: 9443, Auth: &AuthProfile{Password: "old-hy2"}, Extra: map[string]any{"obfs_password": "old-obfs"}},
},
}
rotated, err := RotateNodeSecrets(node)
if err != nil {
t.Fatalf("RotateNodeSecrets() error = %v", err)
}
if rotated.Protocols[0].Auth.UUID == "old-vless" || rotated.Protocols[0].Auth.UUID == "" {
t.Fatal("expected rotated vless uuid")
}
if rotated.Protocols[1].Auth.UUID == "old-vmess" || rotated.Protocols[1].Auth.UUID == "" {
t.Fatal("expected rotated vmess uuid")
}
if rotated.Protocols[2].Auth.Password == "old-ss" || rotated.Protocols[2].Auth.Password == "" {
t.Fatal("expected rotated shadowsocks password")
}
if rotated.Protocols[3].Auth.Password == "old-hy2" || rotated.Protocols[3].Auth.Password == "" {
t.Fatal("expected rotated hysteria2 password")
}
if rotated.Protocols[3].Extra["obfs_password"] == "old-obfs" || rotated.Protocols[3].Extra["obfs_password"] == "" {
t.Fatal("expected rotated hysteria2 obfs password")
}
}
func TestAddSocks5Protocol(t *testing.T) {
t.Parallel()
node, err := AddSocks5Protocol(Node{
ID: "nl-01",
Protocols: []ProtocolProfile{
{Type: "vless-reality", Enabled: true, Port: 443},
{Type: "hysteria2", Enabled: true, Port: 443},
},
}, 54101)
if err != nil {
t.Fatalf("AddSocks5Protocol() error = %v", err)
}
if len(node.Protocols) != 3 {
t.Fatalf("expected 3 protocols, got %d", len(node.Protocols))
}
last := node.Protocols[len(node.Protocols)-1]
if last.Type != "socks5" || last.Port != 54101 || !last.Enabled {
t.Fatalf("unexpected socks5 protocol: %+v", last)
}
}
func TestRepairReinstallNode(t *testing.T) {
t.Parallel()
state, err := RepairReinstallNode(context.Background(), fakeRunner{}, Node{
ID: "nl-01",
Name: "NL 01",
Region: "nl",
Host: "203.0.113.10",
Domain: "nl-01.example.com",
Enabled: true,
SSH: SSHConfig{User: "root", Port: 22, Auth: "key", IdentityFile: "~/.ssh/id_ed25519"},
Protocols: []ProtocolProfile{
{Type: "vless", Enabled: true, Port: 443, TLS: &TLSProfile{Enabled: true, ServerName: "nl-01.example.com"}, Auth: &AuthProfile{UUID: "11111111-1111-1111-1111-111111111111"}, Extra: map[string]any{"path": "/ws"}},
},
}, t.TempDir())
if err != nil {
t.Fatalf("RepairReinstallNode() error = %v", err)
}
if state == nil {
t.Fatal("expected state")
}
if state.BootstrapStatus != "healthy" {
t.Fatalf("BootstrapStatus = %q, want healthy", state.BootstrapStatus)
}
if got := state.Metadata["lifecycle_action"]; got != "repair_reinstall" {
t.Fatalf("lifecycle_action = %v, want repair_reinstall", got)
}
}
func TestCleanReinstallNode(t *testing.T) {
t.Parallel()
state, err := CleanReinstallNode(context.Background(), fakeRunner{}, Node{
ID: "nl-01",
Name: "NL 01",
Region: "nl",
Host: "203.0.113.10",
Domain: "nl-01.example.com",
Enabled: true,
SSH: SSHConfig{User: "root", Port: 22, Auth: "key", IdentityFile: "~/.ssh/id_ed25519"},
Protocols: []ProtocolProfile{
{Type: "vless", Enabled: true, Port: 443, TLS: &TLSProfile{Enabled: true, ServerName: "nl-01.example.com"}, Auth: &AuthProfile{UUID: "11111111-1111-1111-1111-111111111111"}, Extra: map[string]any{"path": "/ws"}},
},
}, t.TempDir())
if err != nil {
t.Fatalf("CleanReinstallNode() error = %v", err)
}
if state == nil {
t.Fatal("expected state")
}
if state.BootstrapStatus != "healthy" {
t.Fatalf("BootstrapStatus = %q, want healthy", state.BootstrapStatus)
}
if got := state.Metadata["lifecycle_action"]; got != "clean_reinstall" {
t.Fatalf("lifecycle_action = %v, want clean_reinstall", got)
}
}
func TestParsePreflightInspectOutput(t *testing.T) {
t.Parallel()
data := ParsePreflightInspectOutput("OS_ID=ubuntu\nMANAGED=1\nTCP_443=0\n")
if data["OS_ID"] != "ubuntu" {
t.Fatalf("OS_ID = %q, want ubuntu", data["OS_ID"])
}
if data["MANAGED"] != "1" {
t.Fatalf("MANAGED = %q, want 1", data["MANAGED"])
}
if data["TCP_443"] != "0" {
t.Fatalf("TCP_443 = %q, want 0", data["TCP_443"])
}
}
|