This commit is contained in:
2026-02-15 07:18:14 +08:00
parent d7cd899983
commit 8a7bf8a39c
39 changed files with 1578 additions and 2868 deletions

View File

@@ -1,26 +1,135 @@
package config
import (
"fmt"
"os"
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
"github.com/spf13/viper"
)
const (
BaseDir = "/etc/sunhpc"
LogDir = "/var/log/sunhpc"
TmplDir = BaseDir + "/tmpl.d"
BaseDir string = "/etc/sunhpc"
LogDir string = "/var/log/sunhpc"
TmplDir string = BaseDir + "/tmpl.d"
appName string = "sunhpc"
defaultDBPath string = "/var/lib/sunhpc"
defaultDBName string = "sunhpc.db"
)
var (
SunHPCFile = filepath.Join(BaseDir, "sunhpc.yaml")
NodesFile = filepath.Join(BaseDir, "nodes.yaml")
NetworkFile = filepath.Join(BaseDir, "network.yaml")
DisksFile = filepath.Join(BaseDir, "disks.yaml")
ServicesFile = filepath.Join(BaseDir, "services.yaml")
FirewallFile = filepath.Join(BaseDir, "iptables.yaml")
)
type Config struct {
DB DBConfig `yaml:"db"`
Log LogConfig `yaml:"log"`
Cluster ClusterConfig `yaml:"cluster"`
}
type DBConfig struct {
Type string `yaml:"type"`
Path string `yaml:"path"` // SQLite: 目录路径
Name string `yaml:"name"` // SQLite: 文件名
User string `yaml:"user"`
Password string `yaml:"password"`
Host string `yaml:"host"`
Port int `yaml:"port"`
Socket string `yaml:"socket"`
Verbose bool `yaml:"verbose"`
}
type LogConfig struct {
Level string `yaml:"level"`
Format string `yaml:"format"`
Output string `yaml:"output"`
FilePath string `yaml:"file_path"`
}
type ClusterConfig struct {
Name string `yaml:"name"`
AdminEmail string `yaml:"admin_email"`
TimeZone string `yaml:"time_zone"`
NodePrefix string `yaml:"node_prefix"`
}
// LoadConfig loads configuration with the following precedence:
// 优先级排序:
// 1. 环境变量 (prefix: SUNHPC_)
// 2. ~/.sunhpc.yaml
// 3. ./sunhpc.yaml
// 4. /etc/sunhpc/sunhpc.yaml
// 5. Default values
/*
示例配置文件:
```yaml
db:
type: sqlite
name: sunhpc.db
path: /var/lib/sunhpc
socket: /var/lib/sunhpc/mysql/mysqld.sock
user: root
password: ""
host: localhost
```
环境变量配置示例:
```bash
export SUNHPC_DATABASE_TYPE=mysql
export SUNHPC_DATABASE_NAME=sunhpc
export SUNHPC_DATABASE_USER=root
export SUNHPC_DATABASE_PASSWORD=123456
export SUNHPC_DATABASE_HOST=localhost
```
*/
func LoadConfig() (*Config, error) {
v := viper.New()
// Step 1: 设置默认值(最低优先级)
v.SetDefault("db.type", "sqlite")
v.SetDefault("db.name", "sunhpc.db")
v.SetDefault("db.path", "/var/lib/sunhpc")
v.SetDefault("db.socket", "/var/lib/sunhpc/mysql/mysqld.sock")
v.SetDefault("db.user", "")
v.SetDefault("db.password", "")
v.SetDefault("db.host", "localhost")
v.SetDefault("db.port", 3306)
v.SetDefault("db.verbose", false)
// Step 2: 启用环境变量(高优先级)
v.SetEnvPrefix("SUNHPC") // e.g., SUNHPC_DATABASE_NAME
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // db.type -> SUNHPC_DB_TYPE
v.AutomaticEnv() // Auto bind env vars matching config keys
// Step 3: 按优先级从高到低加载配置文件
// 优先级: env > ./sunhpc.yaml > ~/.sunhpc.yaml > /etc/sunhpc/sunhpc.yaml > defaults
configFiles := []string{
"./sunhpc.yaml",
filepath.Join(os.Getenv("HOME"), ".sunhpc.yaml"),
filepath.Join(BaseDir, "sunhpc.yaml"),
}
var configFile string
for _, cfgFile := range configFiles {
if _, err := os.Stat(cfgFile); err == nil {
configFile = cfgFile
break // 找到第一个就停止.
}
}
// 如果找到配置文件,就加载它.
if configFile != "" {
v.SetConfigFile(configFile)
if err := v.ReadInConfig(); err != nil {
return nil, fmt.Errorf("加载配置文件 %s 失败: %w", configFile, err)
}
}
// 解码到结构体
var cfg Config
if err := v.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("解码配置到结构体失败: %w", err)
}
return &cfg, nil
}
// InitDirs 创建所有必需目录
func InitDirs() error {
@@ -31,39 +140,8 @@ func InitDirs() error {
}
for _, d := range dirs {
if err := os.MkdirAll(d, 0755); err != nil {
return err
return fmt.Errorf("创建目录 %s 失败: %w", d, err)
}
}
return nil
}
// CreateDefaultConfigs 生成默认 YAML 配置文件
func CreateDefaultConfigs() error {
files := map[string]interface{}{
SunHPCFile: DefaultSunHPC(),
NodesFile: DefaultNodes(),
NetworkFile: DefaultNetwork(),
DisksFile: DefaultDisks(),
ServicesFile: DefaultServices(),
FirewallFile: DefaultFirewall(),
}
for path, data := range files {
if err := writeYAML(path, data); err != nil {
return err
}
}
return nil
}
func writeYAML(path string, data interface{}) error {
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
enc := yaml.NewEncoder(f)
defer enc.Close()
return enc.Encode(data)
}

View File

@@ -1,128 +1,60 @@
package config
// SunHPC 主配置
type SunHPCConfig struct {
Hostname string `yaml:"hostname"`
MOTD string `yaml:"motd"`
Sysctl map[string]string `yaml:"sysctl"`
SELinux string `yaml:"selinux"` // enforcing, permissive, disabled
SSH SSHConfig `yaml:"ssh"`
}
import (
"os"
"path/filepath"
type SSHConfig struct {
PermitRootLogin string `yaml:"permit_root_login"`
PasswordAuth string `yaml:"password_authentication"`
}
"gopkg.in/yaml.v3"
)
func DefaultSunHPC() *SunHPCConfig {
return &SunHPCConfig{
Hostname: "sunhpc-master",
MOTD: "Welcome to SunHPC Cluster\n",
Sysctl: map[string]string{
"net.ipv4.ip_forward": "1",
"vm.swappiness": "10",
// DefaultConfig 返回 SunHPC 的默认配置结构体
func DefaultConfig() *Config {
return &Config{
DB: DBConfig{
Type: "sqlite",
Path: "/var/lib/sunhpc", // SQLite 数据库存放目录
Name: "sunhpc.db", // 数据库文件名
User: "", // SQLite 不需要
Password: "",
Host: "",
Port: 0,
Socket: "",
Verbose: false,
},
SELinux: "enforcing",
SSH: SSHConfig{
PermitRootLogin: "yes",
PasswordAuth: "yes",
Log: LogConfig{
Level: "info",
Format: "text", // or "json"
Output: "stdout",
FilePath: "/var/log/sunhpc/sunhpc.log",
},
Cluster: ClusterConfig{
Name: "default-cluster",
AdminEmail: "admin@example.com",
TimeZone: "Asia/Shanghai",
NodePrefix: "node",
},
}
}
// Nodes 节点配置
type NodesConfig struct {
Nodes []Node `yaml:"nodes"`
}
type Node struct {
Hostname string `yaml:"hostname"`
MAC string `yaml:"mac"`
IP string `yaml:"ip"`
Role string `yaml:"role"` // master, compute, login
}
func DefaultNodes() *NodesConfig {
return &NodesConfig{
Nodes: []Node{
{Hostname: "master", MAC: "00:11:22:33:44:55", IP: "192.168.1.1", Role: "master"},
},
// WriteDefaultConfig 将默认配置写入指定路径
// 如果目录不存在,会自动创建(需有权限)
// 如果文件已存在且非空,会返回错误(除非调用方先删除)
func WriteDefaultConfig(path string) error {
// 确保目录存在
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
}
// Network 网络配置
type NetworkConfig struct {
Interface string `yaml:"interface"`
Subnet string `yaml:"subnet"`
Netmask string `yaml:"netmask"`
Gateway string `yaml:"gateway"`
DNSServers []string `yaml:"dns_servers"`
}
// 生成默认配置
cfg := DefaultConfig()
func DefaultNetwork() *NetworkConfig {
return &NetworkConfig{
Interface: "eth0",
Subnet: "192.168.1.0",
Netmask: "255.255.255.0",
Gateway: "192.168.1.1",
DNSServers: []string{"8.8.8.8", "114.114.114.114"},
// 序列化为 YAML
data, err := yaml.Marshal(cfg)
if err != nil {
return err
}
}
// Disks 磁盘配置
type DisksConfig struct {
Disks []Disk `yaml:"disks"`
}
type Disk struct {
Device string `yaml:"device"`
Mount string `yaml:"mount"`
FSType string `yaml:"fstype"`
Options string `yaml:"options"`
}
func DefaultDisks() *DisksConfig {
return &DisksConfig{
Disks: []Disk{
{Device: "/dev/sda1", Mount: "/", FSType: "ext4", Options: "defaults"},
},
}
}
// Services 服务配置
type ServicesConfig struct {
HTTPD Service `yaml:"httpd"`
TFTPD Service `yaml:"tftpd"`
DHCPD Service `yaml:"dhcpd"`
}
type Service struct {
Enabled bool `yaml:"enabled"`
Config string `yaml:"config,omitempty"`
}
func DefaultServices() *ServicesConfig {
return &ServicesConfig{
HTTPD: Service{Enabled: true},
TFTPD: Service{Enabled: true},
DHCPD: Service{Enabled: true},
}
}
// Firewall 防火墙配置
type FirewallConfig struct {
DefaultPolicy string `yaml:"default_policy"`
Rules []string `yaml:"rules"`
}
func DefaultFirewall() *FirewallConfig {
return &FirewallConfig{
DefaultPolicy: "DROP",
Rules: []string{
"-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT",
"-A INPUT -p icmp -j ACCEPT",
"-A INPUT -i lo -j ACCEPT",
"-A INPUT -p tcp --dport 22 -j ACCEPT",
},
}
// 写入文件0644 权限)
return os.WriteFile(path, data, 0644)
}

View File

@@ -1,43 +0,0 @@
package config
import (
"os"
"gopkg.in/yaml.v3"
)
func LoadSunHPC() (*SunHPCConfig, error) {
return loadYAML[SunHPCConfig](SunHPCFile)
}
func LoadNodes() (*NodesConfig, error) {
return loadYAML[NodesConfig](NodesFile)
}
func LoadNetwork() (*NetworkConfig, error) {
return loadYAML[NetworkConfig](NetworkFile)
}
func LoadDisks() (*DisksConfig, error) {
return loadYAML[DisksConfig](DisksFile)
}
func LoadServices() (*ServicesConfig, error) {
return loadYAML[ServicesConfig](ServicesFile)
}
func LoadFirewall() (*FirewallConfig, error) {
return loadYAML[FirewallConfig](FirewallFile)
}
func loadYAML[T any](path string) (*T, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var cfg T
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, err
}
return &cfg, nil
}