625 lines
15 KiB
Go
625 lines
15 KiB
Go
|
|
package db
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"net"
|
|||
|
|
"os"
|
|||
|
|
"strings"
|
|||
|
|
"sync"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
// 获取数据库实例
|
|||
|
|
database, err := db.GetInstance()
|
|||
|
|
if err != nil {
|
|||
|
|
log.Fatal(err)
|
|||
|
|
}
|
|||
|
|
defer database.Close()
|
|||
|
|
|
|||
|
|
// 创建Helper
|
|||
|
|
helper, _ := db.NewDBHelper()
|
|||
|
|
|
|||
|
|
// 执行查询
|
|||
|
|
helper.Execute("SELECT * FROM nodes WHERE rack = ?", 1)
|
|||
|
|
|
|||
|
|
// 获取一行
|
|||
|
|
row, _ := helper.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
log.Infof("节点: %v", row["name"])
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取所有行
|
|||
|
|
rows, _ := helper.FetchAll()
|
|||
|
|
log.Infof("共 %d 个节点", len(rows))
|
|||
|
|
|
|||
|
|
// 使用Helper方法
|
|||
|
|
hostname, _ := helper.GetHostname("192.168.1.1")
|
|||
|
|
log.Infof("解析主机名: %s", hostname)
|
|||
|
|
|
|||
|
|
// 设置属性
|
|||
|
|
helper.SetCategoryAttr("global", "global", "Kickstart_PrivateHostname", "sunhpc-master")
|
|||
|
|
|
|||
|
|
// 获取属性
|
|||
|
|
val := helper.GetCategoryAttr("global", "global", "Kickstart_PrivateHostname")
|
|||
|
|
log.Infof("前端主机名: %s", val)
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const (
|
|||
|
|
attrPostfix = "_old"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// DBHelper DatabaseHelper类 - 继承DB,扩展业务方法
|
|||
|
|
type DBHelper struct {
|
|||
|
|
*DB
|
|||
|
|
appliancesList []string
|
|||
|
|
frontendName string
|
|||
|
|
cacheAttrs sync.Map
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func NewDBHelper() (*DBHelper, error) {
|
|||
|
|
db, err := GetInstance()
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return &DBHelper{
|
|||
|
|
DB: db,
|
|||
|
|
appliancesList: nil,
|
|||
|
|
frontendName: "",
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 节点查询 ====================
|
|||
|
|
|
|||
|
|
// GetListHostnames 获取所有主机名列表
|
|||
|
|
func (h *DBHelper) GetListHostnames() ([]string, error) {
|
|||
|
|
_, err := h.Execute("SELECT name FROM nodes ORDER BY name")
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
rows, err := h.FetchAll()
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var names []string
|
|||
|
|
for _, row := range rows {
|
|||
|
|
if name, ok := row["name"]; ok {
|
|||
|
|
names = append(names, name.(string))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return names, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetNodesFromNames 从名称列表获取节点
|
|||
|
|
func (h *DBHelper) GetNodesFromNames(names []string, managedOnly bool) ([]map[string]interface{}, error) {
|
|||
|
|
// 如果没有提供名称,返回所有节点
|
|||
|
|
if len(names) == 0 {
|
|||
|
|
query := "SELECT * FROM nodes"
|
|||
|
|
if managedOnly {
|
|||
|
|
query = `
|
|||
|
|
SELECT n.* FROM nodes n
|
|||
|
|
JOIN node_attrs a ON n.id = a.node_id
|
|||
|
|
WHERE a.attr = 'managed' AND a.value = 'true'
|
|||
|
|
`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_, err := h.Execute(query)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return h.FetchAll()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建查询条件
|
|||
|
|
conditions := []string{}
|
|||
|
|
args := []interface{}{}
|
|||
|
|
|
|||
|
|
for _, name := range names {
|
|||
|
|
if strings.HasPrefix(name, "select ") {
|
|||
|
|
conditions = append(conditions, fmt.Sprintf("name IN (%s)", name[7:]))
|
|||
|
|
|
|||
|
|
} else if strings.Contains(name, "%") {
|
|||
|
|
conditions = append(conditions, "name LIKE ?")
|
|||
|
|
args = append(args, name)
|
|||
|
|
|
|||
|
|
} else if strings.HasPrefix(name, "rack") {
|
|||
|
|
rackNum := strings.TrimPrefix(name, "rack")
|
|||
|
|
conditions = append(conditions, "rack = ?")
|
|||
|
|
args = append(args, rackNum)
|
|||
|
|
|
|||
|
|
} else if h.IsApplianceName(name) {
|
|||
|
|
conditions = append(conditions, `id IN (
|
|||
|
|
SELECT node_id FROM node_attrs
|
|||
|
|
WHERE attr = 'appliance' AND value = ?
|
|||
|
|
)`)
|
|||
|
|
args = append(args, name)
|
|||
|
|
|
|||
|
|
} else {
|
|||
|
|
hostname, err := h.GetHostname(name)
|
|||
|
|
if err == nil {
|
|||
|
|
conditions = append(conditions, "name = ?")
|
|||
|
|
args = append(args, hostname)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if len(conditions) == 0 {
|
|||
|
|
return []map[string]interface{}{}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
query := "SELECT * FROM nodes WHERE " + strings.Join(conditions, " OR ")
|
|||
|
|
_, err := h.Execute(query, args...)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
nodes, err := h.FetchAll()
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 过滤受管节点
|
|||
|
|
if managedOnly {
|
|||
|
|
var managed []map[string]interface{}
|
|||
|
|
for _, node := range nodes {
|
|||
|
|
val := h.GetHostAttr(node["name"].(string), "managed")
|
|||
|
|
if val == "true" {
|
|||
|
|
managed = append(managed, node)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return managed, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nodes, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 设备类型 ====================
|
|||
|
|
|
|||
|
|
// GetAppliancesListText 获取所有设备类型名称
|
|||
|
|
func (h *DBHelper) GetAppliancesListText() []string {
|
|||
|
|
if h.appliancesList != nil {
|
|||
|
|
return h.appliancesList
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_, err := h.Execute("SELECT DISTINCT value FROM node_attrs WHERE attr = 'appliance'")
|
|||
|
|
if err != nil {
|
|||
|
|
return []string{}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
rows, _ := h.FetchAll()
|
|||
|
|
var apps []string
|
|||
|
|
for _, row := range rows {
|
|||
|
|
if val, ok := row["value"]; ok {
|
|||
|
|
apps = append(apps, val.(string))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
h.appliancesList = apps
|
|||
|
|
return apps
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsApplianceName 检查是否为设备类型名称
|
|||
|
|
func (h *DBHelper) IsApplianceName(name string) bool {
|
|||
|
|
for _, app := range h.GetAppliancesListText() {
|
|||
|
|
if app == name {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 主机名解析 ====================
|
|||
|
|
|
|||
|
|
// GetHostname 规范化主机名 - 完全参考Rocks实现
|
|||
|
|
func (h *DBHelper) GetHostname(hostname string) (string, error) {
|
|||
|
|
// 如果hostname为空,使用系统主机名
|
|||
|
|
if hostname == "" {
|
|||
|
|
hostname, _ = os.Hostname()
|
|||
|
|
hostname = strings.Split(hostname, ".")[0]
|
|||
|
|
return h.GetHostname(hostname)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 1. 直接在nodes表中查找
|
|||
|
|
_, err := h.Execute("SELECT * FROM nodes WHERE name = ?", hostname)
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
return hostname, nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 尝试IP地址反向解析
|
|||
|
|
addr := net.ParseIP(hostname)
|
|||
|
|
if addr != nil {
|
|||
|
|
names, err := net.LookupAddr(hostname)
|
|||
|
|
if err == nil && len(names) > 0 {
|
|||
|
|
return h.GetHostname(strings.Split(names[0], ".")[0])
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 在networks表中查找IP
|
|||
|
|
if addr != nil {
|
|||
|
|
_, err := h.Execute(`
|
|||
|
|
SELECT n.name FROM nodes n
|
|||
|
|
JOIN networks net ON n.id = net.node_id
|
|||
|
|
WHERE net.ip = ?
|
|||
|
|
`, addr.String())
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
return row["name"].(string), nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. 尝试MAC地址
|
|||
|
|
mac := strings.ReplaceAll(hostname, "-", ":")
|
|||
|
|
_, err = h.Execute(`
|
|||
|
|
SELECT n.name FROM nodes n
|
|||
|
|
JOIN networks net ON n.id = net.node_id
|
|||
|
|
WHERE net.mac = ?
|
|||
|
|
`, mac)
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
return row["name"].(string), nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 5. 检查别名
|
|||
|
|
_, err = h.Execute(`
|
|||
|
|
SELECT n.name FROM nodes n
|
|||
|
|
JOIN aliases a ON n.id = a.node_id
|
|||
|
|
WHERE a.name = ?
|
|||
|
|
`, hostname)
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
return row["name"].(string), nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 6. 尝试FQDN
|
|||
|
|
if strings.Contains(hostname, ".") {
|
|||
|
|
parts := strings.Split(hostname, ".")
|
|||
|
|
name := parts[0]
|
|||
|
|
domain := strings.Join(parts[1:], ".")
|
|||
|
|
|
|||
|
|
_, err := h.Execute(`
|
|||
|
|
SELECT n.name FROM nodes n
|
|||
|
|
JOIN networks net ON n.id = net.node_id
|
|||
|
|
JOIN subnets s ON net.subnet_id = s.id
|
|||
|
|
WHERE s.dns_zone = ? AND (net.name = ? OR n.name = ?)
|
|||
|
|
`, domain, name, name)
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
return row["name"].(string), nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 7. 如果以上都失败,抛出异常
|
|||
|
|
return "", fmt.Errorf("无法解析主机名: %s", hostname)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CheckHostnameValidity 检查主机名有效性
|
|||
|
|
func (h *DBHelper) CheckHostnameValidity(hostname string) error {
|
|||
|
|
// 不能包含点
|
|||
|
|
if strings.Contains(hostname, ".") {
|
|||
|
|
return fmt.Errorf("主机名 %s 不能包含点号", hostname)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 不能是rack<数字>格式
|
|||
|
|
if strings.HasPrefix(hostname, "rack") {
|
|||
|
|
num := strings.TrimPrefix(hostname, "rack")
|
|||
|
|
if _, err := fmt.Sscanf(num, "%d", new(int)); err == nil {
|
|||
|
|
return fmt.Errorf("主机名 %s 不能是rack<数字>格式", hostname)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 不能是设备类型名称
|
|||
|
|
if h.IsApplianceName(hostname) {
|
|||
|
|
return fmt.Errorf("主机名 %s 不能与设备类型名称相同", hostname)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否已存在
|
|||
|
|
_, err := h.GetHostname(hostname)
|
|||
|
|
if err == nil {
|
|||
|
|
return fmt.Errorf("节点 %s 已存在", hostname)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 前端节点 ====================
|
|||
|
|
|
|||
|
|
// GetFrontendName 获取前端节点名称
|
|||
|
|
func (h *DBHelper) GetFrontendName() string {
|
|||
|
|
if h.frontendName != "" {
|
|||
|
|
return h.frontendName
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
name := h.GetCategoryAttr("global", "global", "Kickstart_PrivateHostname")
|
|||
|
|
if name != "" {
|
|||
|
|
h.frontendName = name
|
|||
|
|
}
|
|||
|
|
return h.frontendName
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 属性管理 ====================
|
|||
|
|
|
|||
|
|
// GetCategoryIndex 获取类别索引
|
|||
|
|
func (h *DBHelper) GetCategoryIndex(categoryName, categoryIndex string) (map[string]interface{}, map[string]interface{}, error) {
|
|||
|
|
// 查询类别和索引
|
|||
|
|
_, err := h.Execute(`
|
|||
|
|
SELECT c.id as cid, c.name as cname, i.id as iid, i.name as iname
|
|||
|
|
FROM categories c
|
|||
|
|
JOIN catindexes i ON c.id = i.category_id
|
|||
|
|
WHERE c.name = ? AND i.name = ?
|
|||
|
|
`, categoryName, categoryIndex)
|
|||
|
|
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
category := map[string]interface{}{
|
|||
|
|
"id": row["cid"],
|
|||
|
|
"name": row["cname"],
|
|||
|
|
}
|
|||
|
|
catindex := map[string]interface{}{
|
|||
|
|
"id": row["iid"],
|
|||
|
|
"name": row["iname"],
|
|||
|
|
"category_id": row["cid"],
|
|||
|
|
}
|
|||
|
|
return category, catindex, nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 不存在则创建
|
|||
|
|
// 创建类别
|
|||
|
|
_, err = h.Execute("INSERT INTO categories (name) VALUES (?)", categoryName)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var catID int64
|
|||
|
|
h.Execute("SELECT last_insert_rowid()")
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
catID = row["last_insert_rowid()"].(int64)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建索引
|
|||
|
|
_, err = h.Execute(
|
|||
|
|
"INSERT INTO catindexes (name, category_id) VALUES (?, ?)",
|
|||
|
|
categoryIndex, catID,
|
|||
|
|
)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
h.Execute("SELECT last_insert_rowid()")
|
|||
|
|
row, _ = h.FetchOne()
|
|||
|
|
var idxID int64
|
|||
|
|
if row != nil {
|
|||
|
|
idxID = row["last_insert_rowid()"].(int64)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
category := map[string]interface{}{
|
|||
|
|
"id": catID,
|
|||
|
|
"name": categoryName,
|
|||
|
|
}
|
|||
|
|
catindex := map[string]interface{}{
|
|||
|
|
"id": idxID,
|
|||
|
|
"name": categoryIndex,
|
|||
|
|
"category_id": catID,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return category, catindex, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SetCategoryAttr 设置类别属性
|
|||
|
|
func (h *DBHelper) SetCategoryAttr(categoryName, catindexName, attr, value string) error {
|
|||
|
|
cat, catindex, err := h.GetCategoryIndex(categoryName, catindexName)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查询现有属性
|
|||
|
|
_, err = h.Execute(`
|
|||
|
|
SELECT id, value FROM attributes
|
|||
|
|
WHERE attr = ? AND category_id = ? AND catindex_id = ?
|
|||
|
|
`, attr, cat["id"], catindex["id"])
|
|||
|
|
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
// 更新现有属性
|
|||
|
|
oldValue := row["value"]
|
|||
|
|
attrID := row["id"]
|
|||
|
|
|
|||
|
|
_, err = h.Execute(
|
|||
|
|
"UPDATE attributes SET value = ? WHERE id = ?",
|
|||
|
|
value, attrID,
|
|||
|
|
)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 保存旧值
|
|||
|
|
if !strings.HasSuffix(attr, attrPostfix) {
|
|||
|
|
h.SetCategoryAttr(categoryName, catindexName, attr+attrPostfix, oldValue.(string))
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建新属性
|
|||
|
|
_, err = h.Execute(`
|
|||
|
|
INSERT INTO attributes (attr, value, category_id, catindex_id)
|
|||
|
|
VALUES (?, ?, ?, ?)
|
|||
|
|
`, attr, value, cat["id"], catindex["id"])
|
|||
|
|
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetCategoryAttr 获取类别属性
|
|||
|
|
func (h *DBHelper) GetCategoryAttr(categoryName, catindexName, attrName string) string {
|
|||
|
|
cat, catindex, err := h.GetCategoryIndex(categoryName, catindexName)
|
|||
|
|
if err != nil {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_, err = h.Execute(`
|
|||
|
|
SELECT value FROM attributes
|
|||
|
|
WHERE attr = ? AND category_id = ? AND catindex_id = ?
|
|||
|
|
`, attrName, cat["id"], catindex["id"])
|
|||
|
|
|
|||
|
|
if err != nil {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row == nil {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return row["value"].(string)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RemoveCategoryAttr 移除类别属性
|
|||
|
|
func (h *DBHelper) RemoveCategoryAttr(categoryName, catindexName, attrName string) error {
|
|||
|
|
cat, catindex, err := h.GetCategoryIndex(categoryName, catindexName)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_, err = h.Execute(`
|
|||
|
|
DELETE FROM attributes
|
|||
|
|
WHERE attr = ? AND category_id = ? AND catindex_id = ?
|
|||
|
|
`, attrName, cat["id"], catindex["id"])
|
|||
|
|
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 同时删除对应的_old属性
|
|||
|
|
_, _ = h.Execute(`
|
|||
|
|
DELETE FROM attributes
|
|||
|
|
WHERE attr = ? AND category_id = ? AND catindex_id = ?
|
|||
|
|
`, attrName+attrPostfix, cat["id"], catindex["id"])
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 主机属性 ====================
|
|||
|
|
|
|||
|
|
// GetHostAttr 获取主机属性
|
|||
|
|
func (h *DBHelper) GetHostAttr(hostname, attr string) string {
|
|||
|
|
// 先从节点直接属性查询
|
|||
|
|
_, err := h.Execute(`
|
|||
|
|
SELECT value FROM node_attrs
|
|||
|
|
WHERE node_id = (SELECT id FROM nodes WHERE name = ?)
|
|||
|
|
AND attr = ?
|
|||
|
|
`, hostname, attr)
|
|||
|
|
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
return row["value"].(string)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 使用Rocks的属性解析链查询
|
|||
|
|
query := `
|
|||
|
|
SELECT a.value FROM attributes a
|
|||
|
|
JOIN resolvechain r ON a.category_id = r.category_id
|
|||
|
|
JOIN hostselections h ON a.category_id = h.category_id
|
|||
|
|
AND a.catindex_id = h.selection
|
|||
|
|
WHERE h.host_id = (SELECT id FROM nodes WHERE name = ?)
|
|||
|
|
AND a.attr = ?
|
|||
|
|
ORDER BY r.precedence DESC
|
|||
|
|
LIMIT 1
|
|||
|
|
`
|
|||
|
|
|
|||
|
|
_, err = h.Execute(query, hostname, attr)
|
|||
|
|
if err != nil {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row == nil {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return row["value"].(string)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetHostAttrs 获取主机所有属性
|
|||
|
|
func (h *DBHelper) GetHostAttrs(hostname string, showSource bool) map[string]interface{} {
|
|||
|
|
attrs := make(map[string]interface{})
|
|||
|
|
|
|||
|
|
// 获取节点基本信息
|
|||
|
|
_, err := h.Execute(`
|
|||
|
|
SELECT n.id, n.name, n.rack, n.rank, m.name as membership, a.name as appliance
|
|||
|
|
FROM nodes n
|
|||
|
|
LEFT JOIN memberships m ON n.membership_id = m.id
|
|||
|
|
LEFT JOIN appliances a ON m.appliance_id = a.id
|
|||
|
|
WHERE n.name = ?
|
|||
|
|
`, hostname)
|
|||
|
|
|
|||
|
|
if err == nil {
|
|||
|
|
row, _ := h.FetchOne()
|
|||
|
|
if row != nil {
|
|||
|
|
if showSource {
|
|||
|
|
attrs["hostname"] = []interface{}{row["name"], "I"}
|
|||
|
|
attrs["rack"] = []interface{}{row["rack"], "I"}
|
|||
|
|
attrs["rank"] = []interface{}{row["rank"], "I"}
|
|||
|
|
attrs["appliance"] = []interface{}{row["appliance"], "I"}
|
|||
|
|
attrs["membership"] = []interface{}{row["membership"], "I"}
|
|||
|
|
} else {
|
|||
|
|
attrs["hostname"] = row["name"]
|
|||
|
|
attrs["rack"] = row["rack"]
|
|||
|
|
attrs["rank"] = row["rank"]
|
|||
|
|
attrs["appliance"] = row["appliance"]
|
|||
|
|
attrs["membership"] = row["membership"]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取所有属性
|
|||
|
|
query := `
|
|||
|
|
SELECT a.attr, a.value,
|
|||
|
|
CASE
|
|||
|
|
WHEN h.host_id IS NOT NULL THEN 'H'
|
|||
|
|
ELSE UPPER(SUBSTR(c.name, 1, 1))
|
|||
|
|
END as source
|
|||
|
|
FROM attributes a
|
|||
|
|
JOIN categories c ON a.category_id = c.id
|
|||
|
|
LEFT JOIN hostselections h ON a.category_id = h.category_id
|
|||
|
|
AND a.catindex_id = h.selection
|
|||
|
|
AND h.host_id = (SELECT id FROM nodes WHERE name = ?)
|
|||
|
|
UNION
|
|||
|
|
SELECT attr, value, 'N' as source
|
|||
|
|
FROM node_attrs
|
|||
|
|
WHERE node_id = (SELECT id FROM nodes WHERE name = ?)
|
|||
|
|
`
|
|||
|
|
|
|||
|
|
_, err = h.Execute(query, hostname, hostname)
|
|||
|
|
if err == nil {
|
|||
|
|
rows, _ := h.FetchAll()
|
|||
|
|
for _, row := range rows {
|
|||
|
|
attr := row["attr"].(string)
|
|||
|
|
value := row["value"]
|
|||
|
|
if showSource {
|
|||
|
|
attrs[attr] = []interface{}{value, row["source"]}
|
|||
|
|
} else {
|
|||
|
|
attrs[attr] = value
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return attrs
|
|||
|
|
}
|