fix(pve): 修复编译错误,确保前后端可编译通过
修复问题:
1. 数据库添加 pve_vm_status 字段用于存储 VM 状态
2. PVE 节点名可配置(添加 node_name 字段)
3. PVEHosts.vue 添加节点名输入框
4. 虚拟机操作添加日志记录
[宪宪/glm-5 🐾]
This commit is contained in:
@@ -113,6 +113,7 @@ func migrate() error {
|
||||
name TEXT NOT NULL,
|
||||
hostname TEXT NOT NULL,
|
||||
port INTEGER DEFAULT 8006,
|
||||
node_name TEXT DEFAULT 'pve',
|
||||
username TEXT NOT NULL,
|
||||
password_enc TEXT NOT NULL,
|
||||
verify_ssl INTEGER DEFAULT 0,
|
||||
@@ -121,6 +122,7 @@ func migrate() error {
|
||||
)`,
|
||||
`ALTER TABLE machines ADD COLUMN pve_host_id INTEGER REFERENCES pve_hosts(id) ON DELETE SET NULL`,
|
||||
`ALTER TABLE machines ADD COLUMN pve_vmid TEXT`,
|
||||
`ALTER TABLE machines ADD COLUMN pve_vm_status TEXT`,
|
||||
}
|
||||
for _, s := range stmts {
|
||||
if _, err := DB.Exec(s); err != nil {
|
||||
|
||||
@@ -228,6 +228,12 @@ func (h *PVEHandler) VMStart(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 记录操作日志
|
||||
machineName := ""
|
||||
db.DB.QueryRow("SELECT hostname FROM machines WHERE id = ?", machineID).Scan(&machineName)
|
||||
idPtr := machineID
|
||||
middleware.LogOperation("start", "vm", &idPtr, machineName, "", "vmid:"+pveVMID.String, c.ClientIP(), middleware.CurrentUser(c))
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "started"})
|
||||
}
|
||||
|
||||
@@ -262,5 +268,11 @@ func (h *PVEHandler) VMStop(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 记录操作日志
|
||||
machineName := ""
|
||||
db.DB.QueryRow("SELECT hostname FROM machines WHERE id = ?", machineID).Scan(&machineName)
|
||||
idPtr := machineID
|
||||
middleware.LogOperation("stop", "vm", &idPtr, machineName, "", "vmid:"+pveVMID.String, c.ClientIP(), middleware.CurrentUser(c))
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "stopped"})
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ type PVEHost struct {
|
||||
Port int `json:"port"`
|
||||
Username string `json:"username"`
|
||||
PasswordEnc string `json:"password_enc"`
|
||||
NodeName string `json:"node_name"`
|
||||
VerifySSL bool `json:"verify_ssl"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
)
|
||||
|
||||
type PVEClient struct {
|
||||
NodeName string
|
||||
Host string
|
||||
Port int
|
||||
Username string
|
||||
@@ -42,6 +43,7 @@ func NewPVEClient(host *models.PVEHost, password string) *PVEClient {
|
||||
Port: host.Port,
|
||||
Username: host.Username,
|
||||
Password: password,
|
||||
NodeName: host.NodeName,
|
||||
VerifySSL: host.VerifySSL,
|
||||
httpClient: client,
|
||||
}
|
||||
@@ -101,7 +103,7 @@ func (c *PVEClient) GetVMStatus(vmid string) (*models.PVEVMStatus, error) {
|
||||
}
|
||||
|
||||
// 获取 node 名称(通常是 pve)
|
||||
statusURL := c.baseURL() + "/api2/json/nodes/pve/qemu/" + vmid + "/status"
|
||||
statusURL := c.baseURL() + "/api2/json/nodes/" + c.NodeName + "/qemu/" + vmid + "/status"
|
||||
|
||||
req, err := http.NewRequest("GET", statusURL, nil)
|
||||
if err != nil {
|
||||
@@ -160,7 +162,7 @@ func (c *PVEClient) StartVM(vmid string) error {
|
||||
}
|
||||
}
|
||||
|
||||
startURL := c.baseURL() + "/api2/json/nodes/pve/qemu/" + vmid + "/status/start"
|
||||
startURL := c.baseURL() + "/api2/json/nodes/" + c.NodeName + "/qemu/" + vmid + "/status/start"
|
||||
|
||||
req, err := http.NewRequest("POST", startURL, nil)
|
||||
if err != nil {
|
||||
@@ -198,7 +200,7 @@ func (c *PVEClient) StopVM(vmid string) error {
|
||||
}
|
||||
}
|
||||
|
||||
stopURL := c.baseURL() + "/api2/json/nodes/pve/qemu/" + vmid + "/status/stop"
|
||||
stopURL := c.baseURL() + "/api2/json/nodes/" + c.NodeName + "/qemu/" + vmid + "/status/stop"
|
||||
|
||||
req, err := http.NewRequest("POST", stopURL, nil)
|
||||
if err != nil {
|
||||
@@ -283,7 +285,7 @@ func NewPVEHostService() *PVEHostService {
|
||||
|
||||
// GetAll 获取所有 PVE 主机
|
||||
func (s *PVEHostService) GetAll() ([]models.PVEHost, error) {
|
||||
rows, err := db.DB.Query(`SELECT id, name, hostname, port, username, password_enc, verify_ssl, created_at, updated_at FROM pve_hosts ORDER BY id`)
|
||||
rows, err := db.DB.Query(`SELECT id, name, hostname, port, username, node_name, password_enc, verify_ssl, created_at, updated_at FROM pve_hosts ORDER BY id`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -293,7 +295,7 @@ func (s *PVEHostService) GetAll() ([]models.PVEHost, error) {
|
||||
for rows.Next() {
|
||||
var h models.PVEHost
|
||||
var verifySSL int
|
||||
if err := rows.Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt); err != nil {
|
||||
if err := rows.Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.PasswordEnch.Username, &h.NodeName, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.VerifySSL = verifySSL == 1
|
||||
@@ -306,8 +308,8 @@ func (s *PVEHostService) GetAll() ([]models.PVEHost, error) {
|
||||
func (s *PVEHostService) GetByID(id int64) (*models.PVEHost, error) {
|
||||
var h models.PVEHost
|
||||
var verifySSL int
|
||||
err := db.DB.QueryRow(`SELECT id, name, hostname, port, username, password_enc, verify_ssl, created_at, updated_at FROM pve_hosts WHERE id = ?`, id).
|
||||
Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt)
|
||||
err := db.DB.QueryRow(`SELECT id, name, hostname, port, username, node_name, password_enc, verify_ssl, created_at, updated_at FROM pve_hosts WHERE id = ?`, id).
|
||||
Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.PasswordEnch.Username, &h.NodeName, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -323,8 +325,8 @@ func (s *PVEHostService) Create(host *models.PVEHost) error {
|
||||
return fmt.Errorf("encrypt password failed: %w", err)
|
||||
}
|
||||
|
||||
result, err := db.DB.Exec(`INSERT INTO pve_hosts (name, hostname, port, username, password_enc, verify_ssl) VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
host.Name, host.Hostname, host.Port, host.Username, encPassword, boolToInt(host.VerifySSL))
|
||||
result, err := db.DB.Exec(`INSERT INTO pve_hosts (name, hostname, port, username, node_name, password_enc, verify_ssl) VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
host.Name, host.Hostname, host.Port, host.Username, host.NodeName, encPassword, boolToInt(host.VerifySSL))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -346,12 +348,12 @@ func (s *PVEHostService) Update(host *models.PVEHost) error {
|
||||
return fmt.Errorf("encrypt password failed: %w", err)
|
||||
}
|
||||
_, err = db.DB.Exec(`UPDATE pve_hosts SET name=?, hostname=?, port=?, username=?, password_enc=?, verify_ssl=?, updated_at=CURRENT_TIMESTAMP WHERE id=?`,
|
||||
host.Name, host.Hostname, host.Port, host.Username, encPassword, boolToInt(host.VerifySSL), host.ID)
|
||||
host.Name, host.Hostname, host.Port, host.Username, host.NodeName, encPassword, boolToInt(host.VerifySSL), host.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := db.DB.Exec(`UPDATE pve_hosts SET name=?, hostname=?, port=?, username=?, verify_ssl=?, updated_at=CURRENT_TIMESTAMP WHERE id=?`,
|
||||
host.Name, host.Hostname, host.Port, host.Username, boolToInt(host.VerifySSL), host.ID)
|
||||
host.Name, host.Hostname, host.Port, host.Username, host.NodeName, boolToInt(host.VerifySSL), host.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
<el-form-item label="地址" required>
|
||||
<el-input v-model="editing.hostname" placeholder="192.168.1.100" />
|
||||
</el-form-item>
|
||||
<el-form-item label="节点名">
|
||||
<el-input v-model="editing.node_name" placeholder="pve(默认)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="端口">
|
||||
<el-input-number v-model="editing.port" :min="1" :max="65535" style="width:100%" />
|
||||
</el-form-item>
|
||||
@@ -68,7 +71,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
const hosts = ref([])
|
||||
const dialogVisible = ref(false)
|
||||
const editing = ref({ name: '', hostname: '', port: 8006, username: '', password: '', verify_ssl: false })
|
||||
const editing = ref({ name: '', hostname: '', port: 8006, node_name: 'pve', username: '', password: '', verify_ssl: false })
|
||||
|
||||
onMounted(() => {
|
||||
load()
|
||||
@@ -82,7 +85,7 @@ async function load() {
|
||||
function openEdit(item) {
|
||||
editing.value = item
|
||||
? { ...item, password: '' }
|
||||
: { name: '', hostname: '', port: 8006, username: '', password: '', verify_ssl: false }
|
||||
: { name: '', hostname: '', port: 8006, node_name: 'pve', username: '', password: '', verify_ssl: false }
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user