package proxmox import ( "encoding/json" "errors" "fmt" "time" "github.com/mitchellh/mapstructure" log "github.com/sirupsen/logrus" ) // PVE API client. type PveApiClient struct { apiClient *ApiClient // Instance of API client. } // Create new instance of PVE API client. func NewPveApiClient(endpoints []string, tokenId string, secret string) *PveApiClient { client := PveApiClient{} client.apiClient = NewApiClient(endpoints, tokenId, secret, 5*time.Second) client.apiClient.Start() return &client } // Get PVE version. func (instance *PveApiClient) GetVersion() (*PveVersion, error) { res, err := instance.apiClient.PerformRequest("GET", "/version", nil) if err != nil { return nil, err } version := PveVersion{} err = json.Unmarshal(res.Data, &version) if err != nil { return nil, err } return &version, nil } // Get PVE cluster status. func (instance *PveApiClient) GetClusterStatus() (*PveClusterStatus, error) { res, err := instance.apiClient.PerformRequest("GET", "/cluster/status", nil) if err != nil { return nil, err } var objects []map[string]interface{} err = json.Unmarshal(res.Data, &objects) if err != nil { return nil, err } // If data returned is empty array then there is possible issue with permissions. if len(objects) == 0 { return nil, errors.New("Unable to fetch cluster status from API. Please make sure you have valid token and 'PVEAuditor' permission on token and user.") } var cluster PveClusterStatus for _, obj := range objects { switch obj["type"] { case "cluster": if err := mapstructure.Decode(obj, &cluster); err != nil { log.Errorf("Unable to decode cluster status object. Error:", err) continue } case "node": var node PveNodeStatus if err := mapstructure.Decode(obj, &node); err != nil { log.Errorf("Unable to decode node status object. Error:", err) continue } cluster.NodeStatuses = append(cluster.NodeStatuses, node) default: log.Errorf("Unable to decode cluster status object. Unknown type:", obj["type"]) } } return &cluster, nil } // Get PVE cluster resources. func (instance *PveApiClient) GetClusterResources() (*PveResources, error) { res, err := instance.apiClient.PerformRequest("GET", "/cluster/resources", nil) if err != nil { return nil, err } var objects []map[string]interface{} err = json.Unmarshal(res.Data, &objects) if err != nil { return nil, err } // If data returned is empty array then there is possible issue with permissions. if len(objects) == 0 { return nil, errors.New("Unable to fetch cluster status from API. Please make sure you have valid token and 'PVEAuditor' permission on token and user.") } resources := PveResources{} for _, obj := range objects { switch obj["type"] { case "lxc": var resource PveLxcResource if err := mapstructure.Decode(obj, &resource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } if err := mapstructure.Decode(obj, &resource.PveResource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } resources.CTs = append(resources.CTs, resource) case "qemu": var resource PveQemuResource if err := mapstructure.Decode(obj, &resource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } if err := mapstructure.Decode(obj, &resource.PveResource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } resources.VMs = append(resources.VMs, resource) case "node": var resource PveNodeResource if err := mapstructure.Decode(obj, &resource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } if err := mapstructure.Decode(obj, &resource.PveResource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } resources.Nodes = append(resources.Nodes, resource) case "storage": var resource PveStorageResource if err := mapstructure.Decode(obj, &resource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } if err := mapstructure.Decode(obj, &resource.PveResource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } resources.Storages = append(resources.Storages, resource) case "sdn": var resource PveSdnResource if err := mapstructure.Decode(obj, &resource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } if err := mapstructure.Decode(obj, &resource.PveResource); err != nil { log.Errorf("Unable to decode cluster resource object. Error:", err) continue } resources.SDNs = append(resources.SDNs, resource) default: log.Errorf("Unable to decode cluster resource object. Unknown type:", obj["type"]) } } return &resources, nil } // Get PVE cluster node stats. func (instance *PveApiClient) GetNodeStatusDetail(node string) (*PveNodeStatusDetail, error) { res, err := instance.apiClient.PerformRequest("GET", "/nodes/"+node+"/status", nil) if err != nil { return nil, err } var status PveNodeStatusDetail err = json.Unmarshal(res.Data, &status) if err != nil { return nil, err } return &status, nil } // Get PVE cluster node subscription info. func (instance *PveApiClient) GetNodeSubscription(node string) (*PveSubscription, error) { res, err := instance.apiClient.PerformRequest("GET", "/nodes/"+node+"/subscription", nil) if err != nil { return nil, err } var subscription PveSubscription err = json.Unmarshal(res.Data, &subscription) if err != nil { return nil, err } return &subscription, nil } // Get PVE cluster node disks info. func (instance *PveApiClient) GetNodeDisksList(node string) (*[]PveDisk, error) { res, err := instance.apiClient.PerformRequest("GET", "/nodes/"+node+"/disks/list", nil) if err != nil { return nil, err } var disks []PveDisk err = json.Unmarshal(res.Data, &disks) if err != nil { return nil, err } return &disks, nil } // Get PVE node time info. func (instance *PveApiClient) GetNodeTime(node string) (*PveNodeTime, error) { res, err := instance.apiClient.PerformRequest("GET", "/nodes/"+node+"/time", nil) if err != nil { return nil, err } var time PveNodeTime err = json.Unmarshal(res.Data, &time) if err != nil { return nil, err } return &time, nil } // Get PVE node storage time info. func (instance *PveApiClient) GetNodeStorages(node string) (*[]PveStorage, error) { res, err := instance.apiClient.PerformRequest("GET", "/nodes/"+node+"/storage", nil) if err != nil { return nil, err } var storages []PveStorage err = json.Unmarshal(res.Data, &storages) if err != nil { return nil, err } return &storages, nil } // Get PVE node LXC containers. func (instance *PveApiClient) GetNodeContainerList(node string) (*[]PveLxcStatus, error) { res, err := instance.apiClient.PerformRequest("GET", fmt.Sprintf("/nodes/%s/lxc/", node), nil) if err != nil { return nil, err } var status []PveLxcStatus err = json.Unmarshal(res.Data, &status) if err != nil { return nil, err } return &status, nil } // Get PVE LXC container status. func (instance *PveApiClient) GetContainerStatus(node string, vmid int) (*PveLxcStatus, error) { res, err := instance.apiClient.PerformRequest("GET", fmt.Sprintf("/nodes/%s/lxc/%d/status/current", node, vmid), nil) if err != nil { return nil, err } var status PveLxcStatus err = json.Unmarshal(res.Data, &status) if err != nil { return nil, err } return &status, nil } // Get PVE node VM list. func (instance *PveApiClient) GetNodeQemuList(node string) (*[]PveQemuStatus, error) { res, err := instance.apiClient.PerformRequest("GET", fmt.Sprintf("/nodes/%s/qemu/", node), nil) if err != nil { return nil, err } var status []PveQemuStatus err = json.Unmarshal(res.Data, &status) if err != nil { return nil, err } return &status, nil } // Get PVE node VM detail. func (instance *PveApiClient) GetNodeQemu(node string, vmid string) (*PveQemuStatusDetail, error) { res, err := instance.apiClient.PerformRequest("GET", fmt.Sprintf("/nodes/%s/qemu/%s/status/current", node, vmid), nil) if err != nil { return nil, err } var status PveQemuStatusDetail err = json.Unmarshal(res.Data, &status) if err != nil { return nil, err } return &status, nil }