-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
241 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package api | ||
|
||
type OSInfo struct { | ||
ID string `json:"id"` | ||
KernelRelease string `json:"kernel-release"` | ||
KernelVersion string `json:"kernel-version"` | ||
Machine string `json:"machine"` | ||
Name string `json:"name"` | ||
PrettyName string `json:"pretty-name"` | ||
Version string `json:"version"` | ||
VersionID string `json:"version-id"` | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package proxmox | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/sp-yduck/proxmox-go/api" | ||
) | ||
|
||
func (s *Service) Nodes(ctx context.Context) ([]*api.Node, error) { | ||
return s.restclient.GetNodes(ctx) | ||
} | ||
|
||
func (s *Service) Node(ctx context.Context, name string) (*api.Node, error) { | ||
return s.restclient.GetNode(ctx, name) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package proxmox | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"regexp" | ||
"strings" | ||
|
||
"github.com/sp-yduck/proxmox-go/api" | ||
"github.com/sp-yduck/proxmox-go/rest" | ||
) | ||
|
||
type VirtualMachine struct { | ||
restclient *rest.RESTClient | ||
node string | ||
vm *api.VirtualMachine | ||
config *api.VirtualMachineConfig | ||
} | ||
|
||
const ( | ||
UUIDFormat = `[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}` | ||
) | ||
|
||
// VirtualMachines returns all qemus across all proxmox nodes | ||
func (s *Service) VirtualMachines(ctx context.Context) ([]*api.VirtualMachine, error) { | ||
nodes, err := s.Nodes(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
var vms []*api.VirtualMachine | ||
for _, node := range nodes { | ||
v, err := s.restclient.GetVirtualMachines(ctx, node.Node) | ||
if err != nil { | ||
return nil, err | ||
} | ||
vms = append(vms, v...) | ||
} | ||
return vms, nil | ||
} | ||
|
||
func (s *Service) NewVirtualMachine(ctx context.Context, vmid int) (*VirtualMachine, error) { | ||
nodes, err := s.Nodes(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, node := range nodes { | ||
vm, err := s.restclient.GetVirtualMachine(ctx, node.Node, vmid) | ||
if err != nil { | ||
if rest.IsNotFound(err) { | ||
continue | ||
} | ||
return nil, err | ||
} | ||
return &VirtualMachine{restclient: s.restclient, vm: vm, node: node.Node}, nil | ||
} | ||
return nil, rest.NotFoundErr | ||
} | ||
|
||
func (s *Service) VirtualMachineFromUUID(ctx context.Context, uuid string) (*VirtualMachine, error) { | ||
nodes, err := s.Nodes(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, node := range nodes { | ||
vms, err := s.restclient.GetVirtualMachines(ctx, node.Node) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, vm := range vms { | ||
config, err := s.restclient.GetVirtualMachineConfig(ctx, node.Node, vm.VMID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
vmuuid, err := convertSMBiosToUUID(config.SMBios1) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if vmuuid == uuid { | ||
return &VirtualMachine{restclient: s.restclient, vm: vm, node: node.Node, config: config}, nil | ||
} | ||
} | ||
} | ||
return nil, rest.NotFoundErr | ||
} | ||
|
||
func convertSMBiosToUUID(smbios string) (string, error) { | ||
re := regexp.MustCompile(fmt.Sprintf("uuid=%s", UUIDFormat)) | ||
match := re.FindString(smbios) | ||
if match == "" { | ||
return "", errors.New("failed to fetch uuid form smbios") | ||
} | ||
// match: uuid=<uuid> | ||
return strings.Split(match, "=")[1], nil | ||
} | ||
|
||
func (c *VirtualMachine) GetConfig(ctx context.Context) (*api.VirtualMachineConfig, error) { | ||
if c.config != nil { | ||
return c.config, nil | ||
} | ||
config, err := c.restclient.GetVirtualMachineConfig(ctx, c.node, c.vm.VMID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
c.config = config | ||
return c.config, err | ||
} | ||
|
||
func (c *VirtualMachine) GetOSInfo(ctx context.Context) (*api.OSInfo, error) { | ||
var osInfo *api.OSInfo | ||
path := fmt.Sprintf("/nodes/%s/qemu/%d/agent/get-osinfo", c.node, c.vm.VMID) | ||
if err := c.restclient.Get(ctx, path, &osInfo); err != nil { | ||
return nil, err | ||
} | ||
return osInfo, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package proxmox | ||
|
||
import ( | ||
"crypto/tls" | ||
"errors" | ||
"net/http" | ||
|
||
"github.com/sp-yduck/proxmox-go/rest" | ||
) | ||
|
||
type Service struct { | ||
restclient *rest.RESTClient | ||
} | ||
|
||
type AuthConfig struct { | ||
Username string | ||
Password string | ||
TokenID string | ||
Secret string | ||
} | ||
|
||
func NewService(url string, authConfig AuthConfig, insecure bool) (*Service, error) { | ||
var loginOption rest.ClientOption | ||
if authConfig.Username != "" && authConfig.Password != "" { | ||
loginOption = rest.WithUserPassword(authConfig.Username, authConfig.Password) | ||
} else if authConfig.TokenID != "" && authConfig.Secret != "" { | ||
loginOption = rest.WithAPIToken(authConfig.TokenID, authConfig.Secret) | ||
} else { | ||
return nil, errors.New("invalid authentication config") | ||
} | ||
clientOptions := []rest.ClientOption{loginOption} | ||
|
||
if insecure { | ||
baseClient := &http.Client{ | ||
Transport: &http.Transport{ | ||
TLSClientConfig: &tls.Config{ | ||
InsecureSkipVerify: true, | ||
}, | ||
}, | ||
} | ||
clientOptions = append(clientOptions, rest.WithClient(baseClient)) | ||
} | ||
|
||
restclient, err := rest.NewRESTClient(url, clientOptions...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Service{restclient: restclient}, nil | ||
} | ||
|
||
func NewServiceWithUserPassword(url, user, password string, insecure bool) (*Service, error) { | ||
clientOptions := []rest.ClientOption{ | ||
rest.WithUserPassword(user, password), | ||
} | ||
|
||
if insecure { | ||
baseClient := &http.Client{ | ||
Transport: &http.Transport{ | ||
TLSClientConfig: &tls.Config{ | ||
InsecureSkipVerify: true, | ||
}, | ||
}, | ||
} | ||
clientOptions = append(clientOptions, rest.WithClient(baseClient)) | ||
} | ||
|
||
restclient, err := rest.NewRESTClient(url, clientOptions...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Service{restclient: restclient}, nil | ||
} | ||
|
||
func NewServiceWithAPIToken(url, tokenid, secret string, insecure bool) (*Service, error) { | ||
clientOptions := []rest.ClientOption{ | ||
rest.WithAPIToken(tokenid, secret), | ||
} | ||
if insecure { | ||
baseClient := &http.Client{ | ||
Transport: &http.Transport{ | ||
TLSClientConfig: &tls.Config{ | ||
InsecureSkipVerify: true, | ||
}, | ||
}, | ||
} | ||
clientOptions = append(clientOptions, rest.WithClient(baseClient)) | ||
} | ||
|
||
restclient, err := rest.NewRESTClient(url, clientOptions...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Service{restclient: restclient}, nil | ||
} | ||
|
||
func (s *Service) RESTClient() *rest.RESTClient { | ||
return s.restclient | ||
} |