Tui 模块开发完成,数据正常写入数据库

This commit is contained in:
2026-03-06 16:33:08 +08:00
parent 3f5e333a4d
commit 8bc4f4fe04
7 changed files with 674 additions and 535 deletions

View File

@@ -3,6 +3,7 @@ package database
import (
"database/sql"
"fmt"
"strings"
"sync"
"sunhpc/pkg/config"
@@ -22,22 +23,20 @@ var (
dbErr error
)
// =========================================================
// 封装数据库函数使用Go实现
// =========================================================
// MapCategory - 根据类别名称查ID
// 查询方式: globalID, err := db.MapCategory(conn, "global")
func MapCategory(conn *sql.DB, catname string) (int, error) {
var id int
query := "select id from categories where name = ?"
logger.Debugf("查询SQL: %s", query)
logger.Debugf("查询类别ID: %s", catname)
fullSQL := ReplaceSQLQuery(query, catname)
err := conn.QueryRow(query, catname).Scan(&id)
if err == sql.ErrNoRows {
logger.Debugf("未找到类别 %s, 返回ID=0", catname)
return 0, nil // 无匹配返回0
}
logger.Debugf("查询到类别 %s, ID=%d", catname, id)
logger.Debugf("查询语句: %s , CatName=%s, ID=%d", fullSQL, catname, id)
return id, nil
}
@@ -49,14 +48,15 @@ func MapCategoryIndex(conn *sql.DB, catindexName, categoryIndex string) (int, er
select index_id from vmapCategoryIndex
where categoryName = ? and categoryIndex = ?
`
logger.Debugf("查询SQL: %s", query)
logger.Debugf("查询索引ID: %s, 类别: %s", catindexName, categoryIndex)
fullSQL := ReplaceSQLQuery(query, catindexName, categoryIndex)
err := conn.QueryRow(query, catindexName, categoryIndex).Scan(&id)
if err == sql.ErrNoRows {
logger.Debugf("未找到索引 %s, 返回ID=0", catindexName)
return 0, nil // 无匹配返回0
}
logger.Debugf("查询到索引 %s, ID=%d", catindexName, id)
logger.Debugf("查询语句: %s , CatIndexName=%s, CategoryIndex=%s, ID=%d",
fullSQL, catindexName, categoryIndex, id)
return id, nil
}
@@ -165,6 +165,13 @@ func GetDB() (*sql.DB, error) {
return
}
var version string
err = sqlDB.QueryRow("select sqlite_version()").Scan(&version)
if err != nil {
version = "unknown"
}
logger.Debugf("数据库版本: %s", version)
logger.Debug("数据库连接成功")
dbInstance = sqlDB
})
@@ -178,10 +185,44 @@ func GetDB() (*sql.DB, error) {
func InitTables(db *sql.DB, force bool) error {
// 临时关闭外键约束(解决外键依赖删除报错问题)
_, err := db.Exec("PRAGMA foreign_keys = OFF;")
if err != nil {
logger.Errorf("关闭外键约束失败: %v", err)
return err
}
defer func() {
// 延迟恢复外键约束(确保在函数退出时恢复)
_, err := db.Exec("PRAGMA foreign_keys = ON;")
if err != nil {
logger.Errorf("恢复外键约束失败: %v", err)
}
}()
// ✅ 调用 schema.go 中的函数
//for _, ddl := range CreateTableStatements() {
for _, ddl := range BaseTables() {
logger.Debugf("执行: %s", ddl)
for name, ddl := range BaseTables() {
// 删除表或者试图(如果存在)
logger.Debugf("执行删除 - %s", name)
// 先尝试作为表进行删除
query := fmt.Sprintf("DROP TABLE IF EXISTS %s;", name)
logger.Debugf("执行语句: %s", query)
_, err := db.Exec(query)
if err != nil {
// 如果作为表删除失败,尝试作为试图删除
logger.Debugf("删除表失败: %v", err)
query = fmt.Sprintf("DROP VIEW IF EXISTS %s;", name)
logger.Debugf("执行语句: %s", query)
_, err = db.Exec(query)
if err != nil {
return fmt.Errorf("删除失败: %w", err)
}
}
logger.Debugf("执行图表 - %s", name)
logger.Debugf("执行语句: %s", ddl)
if _, err := db.Exec(ddl); err != nil {
return fmt.Errorf("数据表创建失败: %w", err)
}
@@ -291,28 +332,36 @@ func ExecWithTransaction(ddl []string) error {
return err
}
var finished bool
// 延迟处理:如果函数异常,回滚事务
defer func() {
if r := recover(); r != nil {
// 捕获 panic 并回滚事务
tx.Rollback()
logger.Errorf("事务执行中发生 panic: %v", r)
if !finished {
// 捕获 panic 并回滚事务
tx.Rollback()
logger.Errorf("事务执行中发生 panic: %v", r)
}
panic(r)
}
}()
// 遍历执行 DDL 语句
for idx, sql := range ddl {
logger.Debugf("执行 DDL 语句 %d: %s", idx+1, sql)
_, err = tx.Exec(sql)
if err != nil {
// 执行失败时,回滚事务
rollbackErr := tx.Rollback()
finished = true // 标记事务已完成
if rollbackErr != nil {
logger.Errorf("执行失败: 回滚失败: %v (原错误: %v, SQL: %s)", rollbackErr, err, sql)
} else {
logger.Errorf("执行失败: 回滚事务: %v, SQL: %s", err, sql)
}
logger.Errorf("执行 %d 条, 失败: %w (SQL: %s)", idx+1, err, sql)
return fmt.Errorf("执行 %d 条, 失败: %w (SQL: %s)", idx+1, err, sql)
}
}
@@ -323,6 +372,21 @@ func ExecWithTransaction(ddl []string) error {
return err
}
finished = true // 标记事务已完成
logger.Debugf("成功执行 %d 条 SQL 语句, 事务已提交.", len(ddl))
return nil
}
func ReplaceSQLQuery(query string, args ...interface{}) string {
for _, arg := range args {
switch v := arg.(type) {
case string:
query = strings.Replace(query, "?", fmt.Sprintf("'%s'", v), 1)
case int, int64, float64:
query = strings.Replace(query, "?", fmt.Sprintf("%v", v), 1)
default:
query = strings.Replace(query, "?", fmt.Sprintf("%v", v), 1)
}
}
return strings.TrimSpace(strings.ReplaceAll(query, "\n", " "))
}

View File

@@ -4,473 +4,412 @@ package database
import (
"database/sql"
"fmt"
"sunhpc/pkg/logger"
)
func BaseTables() []string {
func BaseTables() map[string]string {
datalist := []string{}
Appliances := `
CREATE TABLE IF NOT EXISTS appliances (
ID integer primary key autoincrement,
Name varchar(32) not null default '',
Graph varchar(64) not null default 'default',
Node varchar(64) not null default '',
OS varchar(64) not null default 'linux'
);
`
datalist = append(datalist, Appliances)
Memberships := `
CREATE TABLE IF NOT EXISTS memberships (
ID integer primary key autoincrement,
Name varchar(64) not null default '',
Appliance integer(11) default '0',
Distribution integer(11) default '1',
Public varchar(64) not null default 'no'
);
`
datalist = append(datalist, Memberships)
Categories := `
CREATE TABLE IF NOT EXISTS categories (
ID integer primary key autoincrement,
Name varchar(64) not null unique default '0',
Description varchar(255) default null,
UNIQUE(Name)
);
`
datalist = append(datalist, Categories)
Catindex := `
CREATE TABLE IF NOT EXISTS catindex (
ID integer primary key autoincrement,
Name varchar(64) not null unique default '0',
Category integer not null,
Foreign key(Category) references categories(ID) on delete cascade
);
`
datalist = append(datalist, Catindex)
Resolvechain := `
CREATE TABLE IF NOT EXISTS resolvechain (
ID integer primary key autoincrement,
Name varchar(64) not null default '0',
Category integer(11) not null,
Precedence integer(11) not null default '10',
UNIQUE(Name, Category)
Foreign key(Category) references categories(ID) on delete cascade
);
`
datalist = append(datalist, Resolvechain)
Nodes := `
CREATE TABLE IF NOT EXISTS nodes (
ID integer primary key autoincrement,
Name varchar(128) default null,
Membership integer(11) default '2',
CPUs integer(11) not null default '1',
Rack varchar(11) default null,
Rank integer(11) default null,
Arch varchar(32) default null,
OS varchar(64) not null default 'linux',
RunAction varchar(64) default 'os',
InstallAction varchar(64) default 'install'
);
create index if not exists idx_nodes_name on nodes(Name);
`
datalist = append(datalist, Nodes)
Aliases := `
CREATE TABLE IF NOT EXISTS aliases (
ID integer primary key autoincrement,
Node integer(15) not null default '0',
Name varchar(32) default null,
Foreign key(Node) references nodes(ID) on delete cascade
);
`
datalist = append(datalist, Aliases)
Networks := `
CREATE TABLE IF NOT EXISTS networks (
ID integer primary key autoincrement,
Node integer(11) default null,
MAC varchar(64) default null,
IP varchar(64) default null,
Name varchar(128) default null,
Device varchar(32) default null,
Subnet integer(11) default null,
Module varchar(128) default null,
VlanID integer(11) default null,
Options varchar(128) default null,
Channel varchar(128) default null,
Foreign key(Node) references nodes(ID) on delete cascade,
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`
datalist = append(datalist, Networks)
GlobalRoutes := `
CREATE TABLE IF NOT EXISTS globalroutes (
Network varchar(32) not null default '',
Netmask varchar(32) not null default '',
Gateway varchar(32) not null default '',
Subnet integer(11) default null,
Primary key(Network, Netmask)
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`
datalist = append(datalist, GlobalRoutes)
OSRoutes := `
CREATE TABLE IF NOT EXISTS osroutes (
OS varchar(64) not null default 'linux',
Network varchar(32) not null default '',
Netmask varchar(32) not null default '',
Gateway varchar(32) not null default '',
Subnet integer(11) default null,
Primary key(OS, Network, Netmask)
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`
datalist = append(datalist, OSRoutes)
ApplianceRoutes := `
CREATE TABLE IF NOT EXISTS applianceroutes (
Appliance varchar(11) not null default '0',
Network varchar(32) not null default '',
Netmask varchar(32) not null default '',
Gateway varchar(32) not null default '',
Subnet integer(11) default null,
Primary key(Appliance, Network, Netmask)
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`
datalist = append(datalist, ApplianceRoutes)
NodeRoutes := `
CREATE TABLE IF NOT EXISTS noderoutes (
Node varchar(11) not null default '0',
Network varchar(32) not null default '',
Netmask varchar(32) not null default '',
Gateway varchar(32) not null default '',
Subnet integer(11) default null,
Primary key(Node, Network, Netmask)
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`
datalist = append(datalist, NodeRoutes)
Subnets := `
CREATE TABLE IF NOT EXISTS subnets (
ID integer primary key autoincrement,
name varchar(32) unique not null,
dnszone varchar(64) unique not null,
subnet varchar(32) default null,
netmask varchar(32) default null,
mtu integer(11) default '1500',
servedns boolean default false
);
`
datalist = append(datalist, Subnets)
PublicKeys := `
CREATE TABLE IF NOT EXISTS publickeys (
ID integer primary key autoincrement,
Node integer(11) not null default '0',
Public_Key varchar(8192) default null,
Description varchar(8192) default null,
Foreign key(Node) references nodes(ID) on delete cascade
);
`
datalist = append(datalist, PublicKeys)
SecGlobal := `
CREATE TABLE IF NOT EXISTS secglobal (
Attr varchar(128) default null,
Value text,
Enc varchar(128) default null,
Primary key(Attr)
);
`
datalist = append(datalist, SecGlobal)
SecNodes := `
CREATE TABLE IF NOT EXISTS secnodes (
Attr varchar(128) default null,
Enc varchar(128) default null,
Value text,
Node integer(15) not null default '0',
Primary key(Attr, Node)
);
`
datalist = append(datalist, SecNodes)
Attributes := `
CREATE TABLE IF NOT EXISTS attributes (
ID integer primary key autoincrement,
Attr varchar(128) not null,
Value text,
Shadow text,
Category integer(11) not null,
Catindex integer(11) not null,
UNIQUE(Attr, Category, Catindex),
Foreign key(Catindex) references catindex(ID) on delete cascade
);
`
datalist = append(datalist, Attributes)
Partitions := `
CREATE TABLE IF NOT EXISTS partitions (
ID integer primary key autoincrement,
Node integer(15) not null default '0',
Device varchar(128) not null default '',
MountPoint varchar(128) not null default '',
SectorStart varchar(128) not null default '',
PartitionSize varchar(128) not null default '',
FsType varchar(128) not null default '',
PartitionFlags varchar(128) not null default '',
FormatFlags varchar(128) not null default ''
);
`
datalist = append(datalist, Partitions)
Firewalls := `
CREATE TABLE IF NOT EXISTS firewalls (
ID integer primary key autoincrement,
Rulename varchar(128) not null,
Rulesrc varchar(256) not null default 'custom',
InSubnet int(11),
OutSubnet int(11),
Service varchar(256),
Protocol varchar(256),
Action varchar(256),
Chain varchar(256),
Flags varchar(256),
Comment varchar(256),
Category integer(11) not null,
Catindex integer(11) not null,
Check(rulesrc IN ('system', 'custom'))
UNIQUE(Rulename, Category, Catindex),
Foreign key(Catindex) references catindex(ID) on delete cascade
);
`
datalist = append(datalist, Firewalls)
Rolls := `
CREATE TABLE IF NOT EXISTS rolls (
ID integer primary key autoincrement,
Name varchar(128) not null default '',
Version varchar(32) not null default '',
Arch varchar(32) not null default '',
OS varchar(64) not null default 'linux',
Enabled varchar(3) not null default 'yes',
Check(Enabled IN ('yes', 'no'))
Check(OS IN ('linux', 'other'))
);
`
datalist = append(datalist, Rolls)
NodeRolls := `
CREATE TABLE IF NOT EXISTS noderolls (
Node varchar(11) not null default '0',
RollID varchar(11) not null,
Primary key(Node, RollID)
);
`
datalist = append(datalist, NodeRolls)
Bootactions := `
CREATE TABLE IF NOT EXISTS bootactions (
ID integer primary key autoincrement,
Action varchar(256) default null,
Kernel varchar(256) default null,
Ramdisk varchar(256) default null,
Args varchar(1024) default null
);
`
datalist = append(datalist, Bootactions)
BootFlags := `
CREATE TABLE IF NOT EXISTS bootflags (
ID integer primary key autoincrement,
Node integer(11) not null default '0',
Flags varchar(256) default null
);
`
datalist = append(datalist, BootFlags)
Distributions := `
CREATE TABLE IF NOT EXISTS distributions (
ID integer primary key autoincrement,
Name varchar(32) not null default '',
OS varchar(32) default '',
Release varchar(32) default ''
);
`
datalist = append(datalist, Distributions)
View_vnet := `
DROP VIEW IF EXISTS vnet;
CREATE VIEW vnet AS
SELECT
n.name AS nodename, /* 查询nodes表中name字段,将字段改名为nodename */
m.name AS membership,
a.name AS appliance,
n.rack, n.rank, /* 查询nodes表中rack和rank字段,使用原始字段名 */
s.name AS subnet,
nt.ip, nt.device, nt.module,
nt.name AS hostname,
s.dnszone AS domainname,
s.netmask, s.mtu
FROM
nodes n /* 主表: 先查询nodes表,别名n */
inner join memberships m on n.membership=m.id /* 连接memberships表,on只保留满足条件的行 */
inner join appliances a on m.appliance=a.id /* 连接appliances表,on只保留满足条件的行 */
inner join networks nt on n.id=nt.node /* 连接networks表,on只保留满足条件的行 */
inner join subnets s on nt.subnet=s.id /* 连接subnets表,on只保留满足条件的行 */
;
`
datalist = append(datalist, View_vnet)
View_hostselections := `
DROP VIEW IF EXISTS hostselections;
CREATE VIEW hostselections AS
SELECT
n.name AS host,
c.id as category,
ci.id as selection
FROM
nodes n
inner join memberships m on n.membership=m.id -- 节点表关联所属分组
inner join appliances a on m.appliance=a.id -- 分组关联所属应用角色
inner join categories c on
-- 匹配4类分层配置的category(全局/OS/应用/主机)
c.name in ('global', 'os', 'appliance', 'host')
inner join catindex ci on
-- 核心匹配逻辑: category和catindex的name字段一一对应
(c.name = 'global' and ci.name = 'global') or
(c.name = 'os' and ci.name = n.os) or
(c.name = 'appliance' and ci.name = a.name) or
(c.name = 'host' and ci.name = n.name)
;
`
datalist = append(datalist, View_hostselections)
View_vcatindex := `
-- 视图vcatindex: 类别索引可读试图
DROP VIEW IF EXISTS vcatindex;
CREATE VIEW vcatindex AS
SELECT
c.id AS ID,
cat.Name AS Category,
ci.Name AS catindex
FROM
categories cat
inner join catindex ci on ci.category=cat.id
;
`
datalist = append(datalist, View_vcatindex)
View_vresolvechain := `
-- 视图vresolvechain: 解析链可读试图
DROP VIEW IF EXISTS vresolvechain;
CREATE VIEW vresolvechain AS
SELECT
r.name AS chain,
cat.name AS category,
precedence
FROM
resolvechain r
inner join categories cat on r.category=cat.id
order by chain, precedence
;
`
datalist = append(datalist, View_vresolvechain)
View_vattributes := `
-- 视图vattributes: 属性可读试图
DROP VIEW IF EXISTS vattributes;
CREATE VIEW vattributes AS
SELECT
a.id,
attr,
value,
shadow,
cat.name AS category,
ci.name AS catindex
FROM
attributes a
inner join catindex ci on a.catindex=ci.id
inner join categories cat on a.category=cat.id
order by attr, catindex, category
;
`
datalist = append(datalist, View_vattributes)
View_vfirewalls := `
-- 视图vfirewalls: 防火墙规则可读试图
DROP VIEW IF EXISTS vfirewalls;
CREATE VIEW vfirewalls AS
SELECT
f.id,
f.Rulename,
f.Rulesrc,
f.InSubnet,
f.OutSubnet,
f.Service,
f.Protocol,
f.Action,
f.Chain,
f.Flags,
f.Comment,
cat.name AS category,
ci.name AS catindex
FROM
firewalls f
inner join catindex ci on f.catindex=ci.id
inner join categories cat on f.category=cat.id
order by f.Rulename, catindex, category
;
`
datalist = append(datalist, View_vfirewalls)
View_vhostselections := `
-- 视图vhostselections: 主机选择可读试图
DROP VIEW IF EXISTS vhostselections;
CREATE VIEW vhostselections AS
SELECT
hs.host AS host,
cat.name AS category,
ci.name AS selection
FROM
hostselections hs
inner join categories cat on hs.category=cat.id
inner join catindex ci on hs.selection=ci.id
order by host, category, selection
;
`
datalist = append(datalist, View_vhostselections)
View_vmapCategoryIndex := `
-- 视图vmapcategoryindex: 类别索引映射可读试图
DROP VIEW IF EXISTS vmapcategoryindex;
CREATE VIEW vmapCategoryIndex AS
SELECT
cat.name AS categoryName,
ci.name AS categoryIndex,
ci.ID AS index_ID
FROM
cateindex ci
inner join categories cat on ci.category=cat.id
;
`
datalist = append(datalist, View_vmapCategoryIndex)
return datalist
return map[string]string{
"appliances": `
CREATE TABLE IF NOT EXISTS appliances (
ID integer primary key autoincrement,
Name varchar(32) not null default '',
Graph varchar(64) not null default 'default',
Node varchar(64) not null default '',
OS varchar(64) not null default 'linux'
);
`,
"memberships": `
CREATE TABLE IF NOT EXISTS memberships (
ID integer primary key autoincrement,
Name varchar(64) not null default '',
Appliance integer(11) default '0',
Distribution integer(11) default '1',
Public varchar(64) not null default 'no'
);
`,
"categories": `
CREATE TABLE IF NOT EXISTS categories (
ID integer primary key autoincrement,
Name varchar(64) not null unique default '0',
Description varchar(255) default null,
UNIQUE(Name)
);
`,
"catindex": `
CREATE TABLE IF NOT EXISTS catindex (
ID integer primary key autoincrement,
Name varchar(64) not null unique default '0',
Category integer not null,
Foreign key(Category) references categories(ID) on delete cascade
);
`,
"resolvechain": `
CREATE TABLE IF NOT EXISTS resolvechain (
ID integer primary key autoincrement,
Name varchar(64) not null default '0',
Category integer(11) not null,
Precedence integer(11) not null default '10',
UNIQUE(Name, Category)
Foreign key(Category) references categories(ID) on delete cascade
);
`,
"nodes": `
CREATE TABLE IF NOT EXISTS nodes (
ID integer primary key autoincrement,
Name varchar default null,
Membership integer default '2',
CPUs integer not null default '1',
Rack varchar default null,
Rank integer default null,
Arch varchar default null,
OS varchar default null,
RunAction varchar(64) default 'os',
InstallAction varchar(64) default 'install'
);
create index if not exists idx_nodes_name on nodes(Name);
`,
"aliases": `
CREATE TABLE IF NOT EXISTS aliases (
ID integer primary key autoincrement,
Node integer not null default '0',
Name varchar default null,
Foreign key(Node) references nodes(ID) on delete cascade
);
create index if not exists idx_aliases_name on aliases(Name);
`,
"networks": `
CREATE TABLE IF NOT EXISTS networks (
ID integer primary key autoincrement,
Node integer not null default '0',
MAC varchar default null,
IP varchar default null,
Name varchar default null,
Device varchar default null,
Subnet integer default null,
Module varchar default null,
VlanID integer default null,
Options varchar default null,
Channel varchar default null,
Foreign key(Node) references nodes(ID) on delete cascade,
Foreign key(Subnet) references subnets(ID) on delete cascade
);
create index if not exists idx_networks_name on networks(Name);
`,
"globalroutes": `
CREATE TABLE IF NOT EXISTS globalroutes (
Network varchar(32) not null default '',
Netmask varchar(32) not null default '',
Gateway varchar(32) not null default '',
Subnet integer default null,
Primary key(Network, Netmask)
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`,
"osroutes": `
CREATE TABLE IF NOT EXISTS osroutes (
OS varchar(64) not null default 'linux',
Network varchar(32) not null default '',
Netmask varchar(32) not null default '',
Gateway varchar(32) not null default '',
Subnet integer default null,
Primary key(OS, Network, Netmask)
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`,
"applianceroutes": `
CREATE TABLE IF NOT EXISTS applianceroutes (
Appliance varchar(11) not null default '0',
Network varchar(32) not null default '',
Netmask varchar(32) not null default '',
Gateway varchar(32) not null default '',
Subnet integer default null,
Primary key(Appliance, Network, Netmask)
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`,
"noderoutes": `
CREATE TABLE IF NOT EXISTS noderoutes (
Node varchar(11) not null default '0',
Network varchar(32) not null default '',
Netmask varchar(32) not null default '',
Gateway varchar(32) not null default '',
Subnet integer default null,
Primary key(Node, Network, Netmask)
Foreign key(Subnet) references subnets(ID) on delete cascade
);
`,
"subnets": `
CREATE TABLE IF NOT EXISTS subnets (
ID integer primary key autoincrement,
name varchar(32) unique not null,
dnszone varchar(64) unique not null,
subnet varchar(32) default null,
netmask varchar(32) default null,
mtu integer(11) default '1500',
servedns boolean default false
);
`,
"publickeys": `
CREATE TABLE IF NOT EXISTS publickeys (
ID integer primary key autoincrement,
Node integer(11) not null default '0',
Public_Key varchar(8192) default null,
Description varchar(8192) default null,
Foreign key(Node) references nodes(ID) on delete cascade
);
`,
"secglobal": `
CREATE TABLE IF NOT EXISTS secglobal (
Attr varchar(128) default null,
Value text,
Enc varchar(128) default null,
Primary key(Attr)
);
`,
"secnodes": `
CREATE TABLE IF NOT EXISTS secnodes (
Attr varchar(128) default null,
Enc varchar(128) default null,
Value text,
Node integer(15) not null default '0',
Primary key(Attr, Node)
);
`,
"attributes": `
CREATE TABLE IF NOT EXISTS attributes (
ID integer primary key autoincrement,
Attr varchar(128) not null,
Value text,
Shadow text,
Category integer(11) not null,
Catindex integer(11) not null,
UNIQUE(Attr, Category, Catindex),
Foreign key(Catindex) references catindex(ID) on delete cascade
);
`,
"partitions": `
CREATE TABLE IF NOT EXISTS partitions (
ID integer primary key autoincrement,
Node integer(15) not null default '0',
Device varchar(128) not null default '',
MountPoint varchar(128) not null default '',
SectorStart varchar(128) not null default '',
PartitionSize varchar(128) not null default '',
FsType varchar(128) not null default '',
PartitionFlags varchar(128) not null default '',
FormatFlags varchar(128) not null default ''
);
`,
"firewalls": `
CREATE TABLE IF NOT EXISTS firewalls (
ID integer primary key autoincrement,
Rulename varchar(128) not null,
Rulesrc varchar(256) not null default 'custom',
InSubnet int(11),
OutSubnet int(11),
Service varchar(256),
Protocol varchar(256),
Action varchar(256),
Chain varchar(256),
Flags varchar(256),
Comment varchar(256),
Category integer(11) not null,
Catindex integer(11) not null,
Check(rulesrc IN ('system', 'custom'))
UNIQUE(Rulename, Category, Catindex),
Foreign key(Catindex) references catindex(ID) on delete cascade
);
`,
"rolls": `
CREATE TABLE IF NOT EXISTS rolls (
ID integer primary key autoincrement,
Name varchar(128) not null default '',
Version varchar(32) not null default '',
Arch varchar(32) not null default '',
OS varchar(64) not null default 'linux',
Enabled varchar(3) not null default 'yes',
Check(Enabled IN ('yes', 'no'))
Check(OS IN ('linux', 'other'))
);
`,
"noderolls": `
CREATE TABLE IF NOT EXISTS noderolls (
Node varchar(11) not null default '0',
RollID varchar(11) not null,
Primary key(Node, RollID)
);
`,
"bootactions": `
CREATE TABLE IF NOT EXISTS bootactions (
ID integer primary key autoincrement,
Action varchar(256) default null,
Kernel varchar(256) default null,
Ramdisk varchar(256) default null,
Args varchar(1024) default null
);
`,
"bootflags": `
CREATE TABLE IF NOT EXISTS bootflags (
ID integer primary key autoincrement,
Node integer(11) not null default '0',
Flags varchar(256) default null
);
`,
"distributions": `
CREATE TABLE IF NOT EXISTS distributions (
ID integer primary key autoincrement,
Name varchar(32) not null default '',
OS varchar(32) default '',
Release varchar(32) default ''
);
`,
"vnet": `
DROP VIEW IF EXISTS vnet;
CREATE VIEW vnet AS
SELECT
n.name AS nodename, /* 查询nodes表中name字段,将字段改名为nodename */
m.name AS membership,
a.name AS appliance,
n.rack, n.rank, /* 查询nodes表中rack和rank字段,使用原始字段名 */
s.name AS subnet,
nt.ip, nt.device, nt.module,
nt.name AS hostname,
s.dnszone AS domainname,
s.netmask, s.mtu
FROM
nodes n /* 主表: 先查询nodes表,别名n */
inner join memberships m on n.membership=m.id /* 连接memberships表,on只保留满足条件的行 */
inner join appliances a on m.appliance=a.id /* 连接appliances表,on只保留满足条件的行 */
inner join networks nt on n.id=nt.node /* 连接networks表,on只保留满足条件的行 */
inner join subnets s on nt.subnet=s.id /* 连接subnets表,on只保留满足条件的行 */
;
`,
"hostselections": `
DROP VIEW IF EXISTS hostselections;
CREATE VIEW hostselections AS
SELECT
n.name AS host,
c.id as category,
ci.id as selection
FROM
nodes n
inner join memberships m on n.membership=m.id -- 节点表关联所属分组
inner join appliances a on m.appliance=a.id -- 分组关联所属应用角色
inner join categories c on
-- 匹配4类分层配置的category(全局/OS/应用/主机)
c.name in ('global', 'os', 'appliance', 'host')
inner join catindex ci on
-- 核心匹配逻辑: category和catindex的name字段一一对应
(c.name = 'global' and ci.name = 'global') or
(c.name = 'os' and ci.name = n.os) or
(c.name = 'appliance' and ci.name = a.name) or
(c.name = 'host' and ci.name = n.name)
;
`,
"vcatindex": `
-- 视图vcatindex: 类别索引可读试图
DROP VIEW IF EXISTS vcatindex;
CREATE VIEW vcatindex AS
SELECT
c.id AS ID,
cat.Name AS Category,
ci.Name AS catindex
FROM
categories cat
inner join catindex ci on ci.category=cat.id
;
`,
"vresolvechain": `
-- 视图vresolvechain: 解析链可读试图
DROP VIEW IF EXISTS vresolvechain;
CREATE VIEW vresolvechain AS
SELECT
r.name AS chain,
cat.name AS category,
precedence
FROM
resolvechain r
inner join categories cat on r.category=cat.id
order by chain, precedence
;
`,
"vattributes": `
-- 视图vattributes: 属性可读试图
DROP VIEW IF EXISTS vattributes;
CREATE VIEW vattributes AS
SELECT
a.id,
attr,
value,
shadow,
cat.name AS category,
ci.name AS catindex
FROM
attributes a
inner join catindex ci on a.catindex=ci.id
inner join categories cat on a.category=cat.id
order by attr, catindex, category
;
`,
"vfirewalls": `
-- 视图vfirewalls: 防火墙规则可读试图
DROP VIEW IF EXISTS vfirewalls;
CREATE VIEW vfirewalls AS
SELECT
f.id,
f.Rulename,
f.Rulesrc,
f.InSubnet,
f.OutSubnet,
f.Service,
f.Protocol,
f.Action,
f.Chain,
f.Flags,
f.Comment,
cat.name AS category,
ci.name AS catindex
FROM
firewalls f
inner join catindex ci on f.catindex=ci.id
inner join categories cat on f.category=cat.id
order by f.Rulename, catindex, category
;
`,
"vhostselections": `
-- 视图vhostselections: 主机选择可读试图
DROP VIEW IF EXISTS vhostselections;
CREATE VIEW vhostselections AS
SELECT
hs.host AS host,
cat.name AS category,
ci.name AS selection
FROM
hostselections hs
inner join categories cat on hs.category=cat.id
inner join catindex ci on hs.selection=ci.id
order by host, category, selection
;
`,
"vmapcategoryindex": `
-- 视图vmapcategoryindex: 类别索引映射可读试图
DROP VIEW IF EXISTS vmapcategoryindex;
CREATE VIEW vmapCategoryIndex AS
SELECT
cat.name AS categoryName,
ci.name AS categoryIndex,
ci.ID AS index_ID
FROM
cateindex ci
inner join categories cat on ci.category=cat.id
;
`,
}
}
func InitBaseData(conn *sql.DB) error {
logger.Debug("初始化基础数据...")
// ========== 第一步:插入 categories 数据 ==========
categoryData := []struct {
Name string
@@ -484,15 +423,26 @@ func InitBaseData(conn *sql.DB) error {
}
// 批量插入 categories (忽略重复)
logger.Debug("插入 categories 数据...")
for _, cd := range categoryData {
query := `
insert or ignore into categories (Name, Description)
values (?, ?)
`
_, err := conn.Exec(query, cd.Name, cd.Description)
fullSQL := ReplaceSQLQuery(query, cd.Name, cd.Description)
logger.Debugf("执行语句: %s", fullSQL)
// 执行 SQL 语句仍用占位符避免SQL注入
result, err := conn.Exec(query, cd.Name, cd.Description)
if err != nil {
return fmt.Errorf("error inserting category %s: %w", cd.Name, err)
}
id, err := result.LastInsertId()
if err != nil {
return fmt.Errorf("error getting last insert ID: %w", err)
}
logger.Debugf("执行语句: %s, 插入ID: %d", fullSQL, id)
}
// ========== 第二步:插入 catindex 数据 ==========
@@ -511,7 +461,9 @@ func InitBaseData(conn *sql.DB) error {
{"devel-server", "appliance"},
{"login", "appliance"},
}
// 批量插入 catindex (忽略重复)
logger.Debug("插入 Catindex 数据...")
for _, ci := range catindexData {
// 动态获取类别ID (复用MapCategory函数)
catID, err := MapCategory(conn, ci.Category)
@@ -527,10 +479,19 @@ func InitBaseData(conn *sql.DB) error {
insert or ignore into catindex (Name, Category)
values (?, ?)
`
_, err = conn.Exec(query, ci.Name, catID)
fullSQL := ReplaceSQLQuery(query, ci.Name, catID)
// 执行 SQL 语句仍用占位符避免SQL注入
result, err := conn.Exec(query, ci.Name, catID)
if err != nil {
return fmt.Errorf("error inserting catindex %s: %w", ci.Name, err)
}
id, err := result.LastInsertId()
if err != nil {
return fmt.Errorf("error getting last insert ID: %w", err)
}
logger.Debugf("执行语句: %s, 插入ID: %d", fullSQL, id)
}
// ========== 第三步:插入 resolvechain 数据 ==========
@@ -546,6 +507,7 @@ func InitBaseData(conn *sql.DB) error {
{"default", "host", 50},
}
// 批量插入 resolvechain (忽略重复)
logger.Debugf("插入 resolvechain 数据...")
for _, rcd := range resolveChainData {
// 动态获取类别ID (复用MapCategory函数)
catID, err := MapCategory(conn, rcd.Category)
@@ -561,10 +523,19 @@ func InitBaseData(conn *sql.DB) error {
insert or ignore into resolvechain (Name, Category, Precedence)
values (?, ?, ?)
`
_, err = conn.Exec(query, rcd.Name, catID, rcd.Precedence)
fullSQL := ReplaceSQLQuery(query, rcd.Name, catID, rcd.Precedence)
// 执行 SQL 语句仍用占位符避免SQL注入
result, err := conn.Exec(query, rcd.Name, catID, rcd.Precedence)
if err != nil {
return fmt.Errorf("error inserting resolvechain %s: %w", rcd.Name, err)
}
id, err := result.LastInsertId()
if err != nil {
return fmt.Errorf("error getting last insert ID: %w", err)
}
logger.Debugf("执行语句: %s, 插入ID: %d", fullSQL, id)
}
return nil