ok-2
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user