-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.go
More file actions
130 lines (117 loc) · 3.08 KB
/
Copy pathconfig.go
File metadata and controls
130 lines (117 loc) · 3.08 KB
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
// [Input] ~/.sshlogin/servers.json 配置文件
// [Output] 解析后的 Server/Group 结构体
// [Pos] 配置加载层,负责读取和校验 JSON 配置
package main
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
// Server 单台服务器配置
type Server struct {
Name string `json:"name"`
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
Group string `json:"-"` // 运行时填充,所属组名
}
// Group 服务器分组
type Group struct {
Name string `json:"name"`
Servers []Server `json:"servers"`
}
// Config 顶层配置结构
type Config struct {
Groups []Group `json:"groups"`
}
// configPath 返回配置文件路径
func configPath() string {
home, _ := os.UserHomeDir()
return filepath.Join(home, ".sshlogin", "servers.json")
}
// exampleConfig 生成示例配置内容
func exampleConfig() []byte {
cfg := Config{
Groups: []Group{
{
Name: "生产环境",
Servers: []Server{
{Name: "Web Server", Host: "192.168.1.10", Port: 22, User: "root", Password: "your-password"},
},
},
{
Name: "测试环境",
Servers: []Server{
{Name: "Test Server", Host: "10.0.0.5", Port: 22, User: "test", Password: "test123"},
},
},
},
}
data, _ := json.MarshalIndent(cfg, "", " ")
return data
}
// loadConfig 加载配置文件,若不存在则生成示例配置
func loadConfig() ([]Server, error) {
path := configPath()
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return nil, generateExampleConfig(path)
}
return nil, fmt.Errorf("read config failed: %w", err)
}
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parse config failed: %w", err)
}
// 展平分组为服务器列表
var servers []Server
for _, g := range cfg.Groups {
for i := range g.Servers {
s := &g.Servers[i]
s.Group = g.Name
if s.Port == 0 {
s.Port = 22
}
s.Password = resolvePassword(s.Password)
servers = append(servers, *s)
}
}
if len(servers) == 0 {
return nil, fmt.Errorf("no servers configured")
}
return servers, nil
}
// generateExampleConfig 生成示例配置文件
func generateExampleConfig(path string) error {
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0700); err != nil {
return fmt.Errorf("create config dir failed: %w", err)
}
data := exampleConfig()
if err := os.WriteFile(path, data, 0600); err != nil {
return fmt.Errorf("write example config failed: %w", err)
}
return fmt.Errorf("config not found, example created at %s\nPlease edit it and run again", path)
}
// resolvePassword 解析密码,支持 $ENV:VAR_NAME 格式
func resolvePassword(pwd string) string {
if envName, ok := strings.CutPrefix(pwd, "$ENV:"); ok {
if val := os.Getenv(envName); val != "" {
return val
}
}
return pwd
}
// checkSshpass 检查 sshpass 是否已安装
func checkSshpass() error {
_, err := exec.LookPath("sshpass")
if err != nil {
return fmt.Errorf("sshpass not found, install with: brew install sshpass")
}
return nil
}