fix(pve): 修复PVE API认证和VM状态查询路径

- PVE ticket字段名是'ticket'不是'PVEAuthCookie'
- Cookie header格式应为 PVEAuthCookie=<ticket>
- VM状态API路径改为 /status/current
- VM列表API从cluster级改为node级 /nodes/{node}/qemu
- vmid从int解析再转string

[砚砚/K2.6🐾]
This commit is contained in:
openclaw
2026-04-21 02:28:33 +08:00
parent dbeaeda083
commit b835daff1a

View File

@@ -8,6 +8,7 @@ import (
"net/http"
"net/http/cookiejar"
"net/url"
"strconv"
"strings"
"time"
@@ -81,16 +82,21 @@ func (c *PVEClient) Login() error {
var result struct {
Data struct {
CSRFToken string `json:"CSRFPreventionToken"`
Cookie string `json:"PVEAuthCookie"`
Ticket string `json:"ticket"`
} `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return err
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read login response failed: %v", err)
}
if err := json.Unmarshal(body, &result); err != nil {
return fmt.Errorf("decode login response failed: %v, body: %s", err, string(body))
}
c.CSRFToken = result.Data.CSRFToken
c.Cookie = result.Data.Cookie
c.Cookie = "PVEAuthCookie=" + result.Data.Ticket
return nil
}
@@ -103,7 +109,7 @@ func (c *PVEClient) GetVMStatus(vmid string) (*models.PVEVMStatus, error) {
}
// 获取 node 名称(通常是 pve
statusURL := c.baseURL() + "/api2/json/nodes/" + c.NodeName + "/qemu/" + vmid + "/status"
statusURL := c.baseURL() + "/api2/json/nodes/" + c.NodeName + "/qemu/" + vmid + "/status/current"
req, err := http.NewRequest("GET", statusURL, nil)
if err != nil {
@@ -246,7 +252,7 @@ func (c *PVEClient) GetVMList() ([]struct {
}
}
listURL := c.baseURL() + "/api2/json/cluster/resources?type=vm"
listURL := c.baseURL() + "/api2/json/nodes/" + c.NodeName + "/qemu"
req, err := http.NewRequest("GET", listURL, nil)
if err != nil {
@@ -262,22 +268,45 @@ func (c *PVEClient) GetVMList() ([]struct {
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("get vm list failed, status: %d", resp.StatusCode)
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("get vm list failed, status: %d, body: %s", resp.StatusCode, string(body))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read vm list body failed: %v", err)
}
var result struct {
Data []struct {
VMID string `json:"vmid"`
VMID int `json:"vmid"`
Name string `json:"name"`
Status string `json:"status"`
} `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("decode vm list failed: %v, body: %s", err, string(body))
}
return result.Data, nil
// vmid 是 int转换为 string
vms := make([]struct {
VMID string `json:"vmid"`
Name string `json:"name"`
Status string `json:"status"`
}, len(result.Data))
for i, vm := range result.Data {
vms[i] = struct {
VMID string `json:"vmid"`
Name string `json:"name"`
Status string `json:"status"`
}{
VMID: strconv.Itoa(vm.VMID),
Name: vm.Name,
Status: vm.Status,
}
}
return vms, nil
}
// PVEHostService PVE 主机服务