重构架构
This commit is contained in:
161
data/confs/confs.go
Normal file
161
data/confs/confs.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package tmpls
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 核心:
|
||||
// 1. 从嵌入的文件系统中读取指定目录下的单个配置文件内容
|
||||
// 2. 检查文件是否存在
|
||||
// 3. 读取文件内容
|
||||
// 通配符说明:
|
||||
// - db/*/*.yaml : 匹配data/一级子目录下的所有yaml文件.
|
||||
// - 如需递归匹配子目录(如data/db/sub/*.yaml),用 data/**/*.yaml(Go.18+)
|
||||
//
|
||||
//go:embed db/*.yaml firewall/*.yaml
|
||||
var ConfigFS embed.FS
|
||||
|
||||
// GetConfigFile 获取指定目录下的的单个配置文件内容
|
||||
//
|
||||
// 参数:
|
||||
// - dir : 目录名(db/services/firewall...)
|
||||
// - name: 文件名(如base.yaml)
|
||||
//
|
||||
// 返回值:
|
||||
// - []byte: YAML 文件的内容
|
||||
// - error: 如果读取文件失败,返回错误信息
|
||||
func GetConfigFile(dir, name string) ([]byte, error) {
|
||||
// 拼接完整路径(基于tmpls.go所在的 data 目录)
|
||||
fullPath := filepath.Join(dir, name)
|
||||
|
||||
// 检查文件是否存在(避免ReadFile直接报错)
|
||||
_, err := fs.Stat(ConfigFS, fullPath)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, fmt.Errorf("配置文件不存在: %s", fullPath)
|
||||
}
|
||||
return nil, fmt.Errorf("读取配置文件失败: %w", err)
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
content, err := ConfigFS.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取配置文件内容失败: %w", err)
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// GetConfigDir 获取指定目录下的所有配置文件内容
|
||||
//
|
||||
// 参数:
|
||||
// - dir : 目录名(db/services/firewall...)
|
||||
//
|
||||
// 返回值:
|
||||
// - map[string][]byte: 键为文件名(如base.yaml), 值为文件内容
|
||||
// - error: 如果读取文件失败,返回错误信息
|
||||
func GetConfigDir(dir string) (map[string][]byte, error) {
|
||||
// 存储结果: key=文件名 value=文件内容
|
||||
configMap := make(map[string][]byte)
|
||||
|
||||
// 遍历指定目录下的所有文件
|
||||
err := fs.WalkDir(ConfigFS, dir,
|
||||
func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("遍历目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 跳过目录,只处理文件
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 只处理yaml文件(双重效验,避免非yaml文件)
|
||||
if !strings.HasSuffix(d.Name(), ".yaml") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
content, err := ConfigFS.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取文件内容失败: %w", err)
|
||||
}
|
||||
|
||||
// 存储: key用文件名(如base.yaml),而非完整路径.
|
||||
configMap[d.Name()] = content
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return configMap, nil
|
||||
}
|
||||
|
||||
// GetAllConfigDirs 获取所有嵌入目录(db/services/firewall...)的配置
|
||||
//
|
||||
// 返回值:
|
||||
// - map[目录名]map[文件名]文件内容
|
||||
// - error: 如果读取文件失败,返回错误信息
|
||||
func GetAllConfigDirs() (map[string]map[string][]byte, error) {
|
||||
allConfigs := make(map[string]map[string][]byte)
|
||||
|
||||
// 动态获取所有一级子目录(如db/services/firewall)
|
||||
dirs, err := GetAllSubDirs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 遍历所有嵌入目录
|
||||
for _, dir := range dirs {
|
||||
dirConfigs, err := GetConfigDir(dir)
|
||||
if err != nil {
|
||||
// 可选: 忽略空目录、错误目录,继续处理其他目录
|
||||
// 如不需要、直接返回错误、return nil, err
|
||||
continue
|
||||
}
|
||||
allConfigs[dir] = dirConfigs
|
||||
}
|
||||
|
||||
return allConfigs, nil
|
||||
}
|
||||
|
||||
// GetAllSubDirs 动态获取data/下的所有一级子目录
|
||||
//
|
||||
// 返回值:
|
||||
// - []string: 所有一级子目录名(如db/services/firewall)
|
||||
// - error: 如果读取目录失败,返回错误信息
|
||||
func GetAllSubDirs() ([]string, error) {
|
||||
var subDirs []string
|
||||
|
||||
// 遍历data/目录下的所有一级子目录
|
||||
err := fs.WalkDir(ConfigFS, "",
|
||||
func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("遍历目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤条件:
|
||||
// 1. 是目录(d.IsDir())
|
||||
// 2. 是一级子目录(path不含/,排除嵌套子目录如db/sub)
|
||||
// 3. 排除根目录本身(path != "")
|
||||
if d.IsDir() && !strings.Contains(path, "/") && path != "" {
|
||||
subDirs = append(subDirs, path)
|
||||
// 跳过该目录的子目录遍历(提升性能)
|
||||
return fs.SkipDir
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return subDirs, nil
|
||||
}
|
||||
123
data/confs/db/base.yaml
Normal file
123
data/confs/db/base.yaml
Normal file
@@ -0,0 +1,123 @@
|
||||
# 基础数据配置文件
|
||||
version: 1.0
|
||||
description: "SunHPC 基础数据配置"
|
||||
|
||||
# 节点基础数据
|
||||
nodes:
|
||||
- name: frontend
|
||||
cpus: 4
|
||||
memory: 8192
|
||||
disk: 100
|
||||
rack: null
|
||||
rank: null
|
||||
arch: x86_64
|
||||
os: linux
|
||||
runaction: os
|
||||
installaction: os
|
||||
status: active
|
||||
description: "管理节点"
|
||||
|
||||
# 属性基础数据
|
||||
attributes:
|
||||
# 国家地区
|
||||
- node_name: frontend # 通过节点名称关联
|
||||
attr: country
|
||||
value: CN
|
||||
shadow: ""
|
||||
- node_name: frontend
|
||||
attr: state
|
||||
value: Liaoning
|
||||
shadow: ""
|
||||
- node_name: frontend
|
||||
attr: city
|
||||
value: Shenyang
|
||||
shadow: ""
|
||||
|
||||
# 网络配置
|
||||
- node_name: frontend
|
||||
attr: network_type
|
||||
value: management
|
||||
shadow: ""
|
||||
- node_name: frontend
|
||||
attr: ip_address
|
||||
value: 192.168.1.100
|
||||
shadow: ""
|
||||
- node_name: frontend
|
||||
attr: subnet_mask
|
||||
value: 255.255.255.0
|
||||
shadow: ""
|
||||
|
||||
# 硬件信息
|
||||
- node_name: frontend
|
||||
attr: manufacturer
|
||||
value: Dell
|
||||
shadow: ""
|
||||
- node_name: frontend
|
||||
attr: model
|
||||
value: PowerEdge R740
|
||||
shadow: ""
|
||||
|
||||
# 系统配置
|
||||
- node_name: frontend
|
||||
attr: timezone
|
||||
value: Asia/Shanghai
|
||||
shadow: ""
|
||||
- node_name: frontend
|
||||
attr: language
|
||||
value: zh_CN.UTF-8
|
||||
shadow: ""
|
||||
- node_name: frontend
|
||||
attr: kernel_version
|
||||
value: "5.10.0"
|
||||
shadow: ""
|
||||
|
||||
# 软件基础数据
|
||||
software:
|
||||
- name: openssl
|
||||
version: "1.1.1k"
|
||||
vendor: OpenSSL
|
||||
install_method: source
|
||||
is_installed: 0
|
||||
description: "加密库"
|
||||
|
||||
- name: slurm
|
||||
version: "23.02"
|
||||
vendor: SchedMD
|
||||
install_method: source
|
||||
is_installed: 0
|
||||
description: "作业调度系统"
|
||||
|
||||
- name: openmpi
|
||||
version: "4.1.5"
|
||||
vendor: OpenMPI
|
||||
install_method: source
|
||||
is_installed: 0
|
||||
description: "MPI 并行计算库"
|
||||
|
||||
# 网络基础数据
|
||||
networks:
|
||||
- node_name: frontend
|
||||
interface: eth0
|
||||
ip_address: 192.168.1.100
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.1.1
|
||||
type: management
|
||||
mac: "00:11:22:33:44:55"
|
||||
|
||||
# 分区基础数据
|
||||
partitions:
|
||||
- node_name: frontend
|
||||
device: /dev/sda1
|
||||
mount_point: /boot
|
||||
size: 1024
|
||||
fs_type: ext4
|
||||
- node_name: frontend
|
||||
device: /dev/sda2
|
||||
mount_point: /
|
||||
size: 102400
|
||||
fs_type: ext4
|
||||
- node_name: frontend
|
||||
device: /dev/sda3
|
||||
mount_point: /home
|
||||
size: 51200
|
||||
fs_type: ext4
|
||||
0
data/confs/firewall/rule1.yaml
Normal file
0
data/confs/firewall/rule1.yaml
Normal file
29
data/tmpls/services/autofs.yaml
Normal file
29
data/tmpls/services/autofs.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
description: AutoFS server for SunHPC clusters
|
||||
copyright: |
|
||||
Copyright (c) 2026 SunHPC Project.
|
||||
Licensed under Apache 2.0.
|
||||
|
||||
stages:
|
||||
post:
|
||||
- type: file
|
||||
path: /etc/auto.master
|
||||
content: |
|
||||
/share /etc/auto.share --timeout=1200
|
||||
/home /etc/auto.home --timeout=1200
|
||||
|
||||
- type: file
|
||||
path: /etc/auto.share
|
||||
content: |
|
||||
apps {{ .Node.Hostname }}.{{ .Cluster.Domain }}:/export/&
|
||||
|
||||
- type: script
|
||||
content: |
|
||||
mkdir -p /export/apps
|
||||
echo "AutoFS 配置已生成"
|
||||
|
||||
configure:
|
||||
- type: script
|
||||
condition: "{{ if .Node.OldHostname }}true{{ end }}"
|
||||
content: |
|
||||
sed -i 's/{{ .Node.OldHostname }}/{{ .Node.Hostname }}/g' /etc/auto.share
|
||||
systemctl restart autofs
|
||||
161
data/tmpls/tmpl.go
Normal file
161
data/tmpls/tmpl.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package tmpls
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 核心:
|
||||
// 1. 从嵌入的文件系统中读取指定目录下的单个配置文件内容
|
||||
// 2. 检查文件是否存在
|
||||
// 3. 读取文件内容
|
||||
// 通配符说明:
|
||||
// - db/*/*.yaml : 匹配data/一级子目录下的所有yaml文件.
|
||||
// - 如需递归匹配子目录(如data/db/sub/*.yaml),用 data/**/*.yaml(Go.18+)
|
||||
//
|
||||
//go:embed db/*.yaml services/*.yaml firewall/*.yaml
|
||||
var ConfigFS embed.FS
|
||||
|
||||
// GetConfigFile 获取指定目录下的的单个配置文件内容
|
||||
//
|
||||
// 参数:
|
||||
// - dir : 目录名(db/services/firewall...)
|
||||
// - name: 文件名(如base.yaml)
|
||||
//
|
||||
// 返回值:
|
||||
// - []byte: YAML 文件的内容
|
||||
// - error: 如果读取文件失败,返回错误信息
|
||||
func GetConfigFile(dir, name string) ([]byte, error) {
|
||||
// 拼接完整路径(基于tmpls.go所在的 data 目录)
|
||||
fullPath := filepath.Join(dir, name)
|
||||
|
||||
// 检查文件是否存在(避免ReadFile直接报错)
|
||||
_, err := fs.Stat(ConfigFS, fullPath)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, fmt.Errorf("配置文件不存在: %s", fullPath)
|
||||
}
|
||||
return nil, fmt.Errorf("读取配置文件失败: %w", err)
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
content, err := ConfigFS.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取配置文件内容失败: %w", err)
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// GetConfigDir 获取指定目录下的所有配置文件内容
|
||||
//
|
||||
// 参数:
|
||||
// - dir : 目录名(db/services/firewall...)
|
||||
//
|
||||
// 返回值:
|
||||
// - map[string][]byte: 键为文件名(如base.yaml), 值为文件内容
|
||||
// - error: 如果读取文件失败,返回错误信息
|
||||
func GetConfigDir(dir string) (map[string][]byte, error) {
|
||||
// 存储结果: key=文件名 value=文件内容
|
||||
configMap := make(map[string][]byte)
|
||||
|
||||
// 遍历指定目录下的所有文件
|
||||
err := fs.WalkDir(ConfigFS, dir,
|
||||
func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("遍历目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 跳过目录,只处理文件
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 只处理yaml文件(双重效验,避免非yaml文件)
|
||||
if !strings.HasSuffix(d.Name(), ".yaml") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
content, err := ConfigFS.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取文件内容失败: %w", err)
|
||||
}
|
||||
|
||||
// 存储: key用文件名(如base.yaml),而非完整路径.
|
||||
configMap[d.Name()] = content
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return configMap, nil
|
||||
}
|
||||
|
||||
// GetAllConfigDirs 获取所有嵌入目录(db/services/firewall...)的配置
|
||||
//
|
||||
// 返回值:
|
||||
// - map[目录名]map[文件名]文件内容
|
||||
// - error: 如果读取文件失败,返回错误信息
|
||||
func GetAllConfigDirs() (map[string]map[string][]byte, error) {
|
||||
allConfigs := make(map[string]map[string][]byte)
|
||||
|
||||
// 动态获取所有一级子目录(如db/services/firewall)
|
||||
dirs, err := GetAllSubDirs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 遍历所有嵌入目录
|
||||
for _, dir := range dirs {
|
||||
dirConfigs, err := GetConfigDir(dir)
|
||||
if err != nil {
|
||||
// 可选: 忽略空目录、错误目录,继续处理其他目录
|
||||
// 如不需要、直接返回错误、return nil, err
|
||||
continue
|
||||
}
|
||||
allConfigs[dir] = dirConfigs
|
||||
}
|
||||
|
||||
return allConfigs, nil
|
||||
}
|
||||
|
||||
// GetAllSubDirs 动态获取data/下的所有一级子目录
|
||||
//
|
||||
// 返回值:
|
||||
// - []string: 所有一级子目录名(如db/services/firewall)
|
||||
// - error: 如果读取目录失败,返回错误信息
|
||||
func GetAllSubDirs() ([]string, error) {
|
||||
var subDirs []string
|
||||
|
||||
// 遍历data/目录下的所有一级子目录
|
||||
err := fs.WalkDir(ConfigFS, "",
|
||||
func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("遍历目录失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤条件:
|
||||
// 1. 是目录(d.IsDir())
|
||||
// 2. 是一级子目录(path不含/,排除嵌套子目录如db/sub)
|
||||
// 3. 排除根目录本身(path != "")
|
||||
if d.IsDir() && !strings.Contains(path, "/") && path != "" {
|
||||
subDirs = append(subDirs, path)
|
||||
// 跳过该目录的子目录遍历(提升性能)
|
||||
return fs.SkipDir
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return subDirs, nil
|
||||
}
|
||||
Reference in New Issue
Block a user