258 lines
9.2 KiB
Go
258 lines
9.2 KiB
Go
package packngo
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const deviceBasePath = "/devices"
|
|
|
|
// DeviceService interface defines available device methods
|
|
type DeviceService interface {
|
|
List(ProjectID string, listOpt *ListOptions) ([]Device, *Response, error)
|
|
Get(string) (*Device, *Response, error)
|
|
GetExtra(deviceID string, includes, excludes []string) (*Device, *Response, error)
|
|
Create(*DeviceCreateRequest) (*Device, *Response, error)
|
|
Update(string, *DeviceUpdateRequest) (*Device, *Response, error)
|
|
Delete(string) (*Response, error)
|
|
Reboot(string) (*Response, error)
|
|
PowerOff(string) (*Response, error)
|
|
PowerOn(string) (*Response, error)
|
|
Lock(string) (*Response, error)
|
|
Unlock(string) (*Response, error)
|
|
}
|
|
|
|
type devicesRoot struct {
|
|
Devices []Device `json:"devices"`
|
|
Meta meta `json:"meta"`
|
|
}
|
|
|
|
// Device represents a Packet device
|
|
type Device struct {
|
|
ID string `json:"id"`
|
|
Href string `json:"href,omitempty"`
|
|
Hostname string `json:"hostname,omitempty"`
|
|
State string `json:"state,omitempty"`
|
|
Created string `json:"created_at,omitempty"`
|
|
Updated string `json:"updated_at,omitempty"`
|
|
Locked bool `json:"locked,omitempty"`
|
|
BillingCycle string `json:"billing_cycle,omitempty"`
|
|
Storage map[string]interface{} `json:"storage,omitempty"`
|
|
Tags []string `json:"tags,omitempty"`
|
|
Network []*IPAddressAssignment `json:"ip_addresses"`
|
|
Volumes []*Volume `json:"volumes"`
|
|
OS *OS `json:"operating_system,omitempty"`
|
|
Plan *Plan `json:"plan,omitempty"`
|
|
Facility *Facility `json:"facility,omitempty"`
|
|
Project *Project `json:"project,omitempty"`
|
|
ProvisionEvents []*ProvisionEvent `json:"provisioning_events,omitempty"`
|
|
ProvisionPer float32 `json:"provisioning_percentage,omitempty"`
|
|
UserData string `json:"userdata,omitempty"`
|
|
RootPassword string `json:"root_password,omitempty"`
|
|
IPXEScriptURL string `json:"ipxe_script_url,omitempty"`
|
|
AlwaysPXE bool `json:"always_pxe,omitempty"`
|
|
HardwareReservation Href `json:"hardware_reservation,omitempty"`
|
|
SpotInstance bool `json:"spot_instance,omitempty"`
|
|
SpotPriceMax float64 `json:"spot_price_max,omitempty"`
|
|
TerminationTime *Timestamp `json:"termination_time,omitempty"`
|
|
NetworkPorts []Port `json:"network_ports,omitempty"`
|
|
CustomData map[string]interface{} `json:"customdata,omitempty"`
|
|
}
|
|
|
|
type ProvisionEvent struct {
|
|
ID string `json:"id"`
|
|
Body string `json:"body"`
|
|
CreatedAt *Timestamp `json:"created_at,omitempty"`
|
|
Href string `json:"href"`
|
|
Interpolated string `json:"interpolated"`
|
|
Relationships []Href `json:"relationships"`
|
|
State string `json:"state"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
func (d Device) String() string {
|
|
return Stringify(d)
|
|
}
|
|
|
|
// DeviceCreateRequest type used to create a Packet device
|
|
type DeviceCreateRequest struct {
|
|
Hostname string `json:"hostname"`
|
|
Plan string `json:"plan"`
|
|
Facility string `json:"facility"`
|
|
OS string `json:"operating_system"`
|
|
BillingCycle string `json:"billing_cycle"`
|
|
ProjectID string `json:"project_id"`
|
|
UserData string `json:"userdata"`
|
|
Storage string `json:"storage,omitempty"`
|
|
Tags []string `json:"tags"`
|
|
IPXEScriptURL string `json:"ipxe_script_url,omitempty"`
|
|
PublicIPv4SubnetSize int `json:"public_ipv4_subnet_size,omitempty"`
|
|
AlwaysPXE bool `json:"always_pxe,omitempty"`
|
|
HardwareReservationID string `json:"hardware_reservation_id,omitempty"`
|
|
SpotInstance bool `json:"spot_instance,omitempty"`
|
|
SpotPriceMax float64 `json:"spot_price_max,omitempty,string"`
|
|
TerminationTime *Timestamp `json:"termination_time,omitempty"`
|
|
CustomData string `json:"customdata,omitempty"`
|
|
}
|
|
|
|
// DeviceUpdateRequest type used to update a Packet device
|
|
type DeviceUpdateRequest struct {
|
|
Hostname *string `json:"hostname,omitempty"`
|
|
Description *string `json:"description,omitempty"`
|
|
UserData *string `json:"userdata,omitempty"`
|
|
Locked *bool `json:"locked,omitempty"`
|
|
Tags *[]string `json:"tags,omitempty"`
|
|
AlwaysPXE *bool `json:"always_pxe,omitempty"`
|
|
IPXEScriptURL *string `json:"ipxe_script_url,omitempty"`
|
|
CustomData *string `json:"customdata,omitempty"`
|
|
}
|
|
|
|
func (d DeviceCreateRequest) String() string {
|
|
return Stringify(d)
|
|
}
|
|
|
|
// DeviceActionRequest type used to execute actions on devices
|
|
type DeviceActionRequest struct {
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
func (d DeviceActionRequest) String() string {
|
|
return Stringify(d)
|
|
}
|
|
|
|
// DeviceServiceOp implements DeviceService
|
|
type DeviceServiceOp struct {
|
|
client *Client
|
|
}
|
|
|
|
// List returns devices on a project
|
|
func (s *DeviceServiceOp) List(projectID string, listOpt *ListOptions) (devices []Device, resp *Response, err error) {
|
|
params := "include=facility"
|
|
if listOpt != nil {
|
|
params = listOpt.createURL()
|
|
}
|
|
path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, deviceBasePath, params)
|
|
|
|
for {
|
|
subset := new(devicesRoot)
|
|
|
|
resp, err = s.client.DoRequest("GET", path, nil, subset)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
devices = append(devices, subset.Devices...)
|
|
|
|
if subset.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) {
|
|
path = subset.Meta.Next.Href
|
|
if params != "" {
|
|
path = fmt.Sprintf("%s&%s", path, params)
|
|
}
|
|
continue
|
|
}
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
// Get returns a device by id
|
|
func (s *DeviceServiceOp) Get(deviceID string) (*Device, *Response, error) {
|
|
return s.GetExtra(deviceID, []string{"facility"}, nil)
|
|
}
|
|
|
|
// GetExtra returns a device by id. Specifying either includes/excludes provides more or less desired
|
|
// detailed information about resources which would otherwise be represented with an href link
|
|
func (s *DeviceServiceOp) GetExtra(deviceID string, includes, excludes []string) (*Device, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s", deviceBasePath, deviceID)
|
|
if includes != nil {
|
|
path += fmt.Sprintf("?include=%s", strings.Join(includes, ","))
|
|
} else if excludes != nil {
|
|
path += fmt.Sprintf("?exclude=%s", strings.Join(excludes, ","))
|
|
}
|
|
device := new(Device)
|
|
|
|
resp, err := s.client.DoRequest("GET", path, nil, device)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return device, resp, err
|
|
}
|
|
|
|
// Create creates a new device
|
|
func (s *DeviceServiceOp) Create(createRequest *DeviceCreateRequest) (*Device, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s%s", projectBasePath, createRequest.ProjectID, deviceBasePath)
|
|
device := new(Device)
|
|
|
|
resp, err := s.client.DoRequest("POST", path, createRequest, device)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return device, resp, err
|
|
}
|
|
|
|
// Update updates an existing device
|
|
func (s *DeviceServiceOp) Update(deviceID string, updateRequest *DeviceUpdateRequest) (*Device, *Response, error) {
|
|
path := fmt.Sprintf("%s/%s?include=facility", deviceBasePath, deviceID)
|
|
device := new(Device)
|
|
|
|
resp, err := s.client.DoRequest("PUT", path, updateRequest, device)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return device, resp, err
|
|
}
|
|
|
|
// Delete deletes a device
|
|
func (s *DeviceServiceOp) Delete(deviceID string) (*Response, error) {
|
|
path := fmt.Sprintf("%s/%s", deviceBasePath, deviceID)
|
|
|
|
return s.client.DoRequest("DELETE", path, nil, nil)
|
|
}
|
|
|
|
// Reboot reboots on a device
|
|
func (s *DeviceServiceOp) Reboot(deviceID string) (*Response, error) {
|
|
path := fmt.Sprintf("%s/%s/actions", deviceBasePath, deviceID)
|
|
action := &DeviceActionRequest{Type: "reboot"}
|
|
|
|
return s.client.DoRequest("POST", path, action, nil)
|
|
}
|
|
|
|
// PowerOff powers on a device
|
|
func (s *DeviceServiceOp) PowerOff(deviceID string) (*Response, error) {
|
|
path := fmt.Sprintf("%s/%s/actions", deviceBasePath, deviceID)
|
|
action := &DeviceActionRequest{Type: "power_off"}
|
|
|
|
return s.client.DoRequest("POST", path, action, nil)
|
|
}
|
|
|
|
// PowerOn powers on a device
|
|
func (s *DeviceServiceOp) PowerOn(deviceID string) (*Response, error) {
|
|
path := fmt.Sprintf("%s/%s/actions", deviceBasePath, deviceID)
|
|
action := &DeviceActionRequest{Type: "power_on"}
|
|
|
|
return s.client.DoRequest("POST", path, action, nil)
|
|
}
|
|
|
|
type lockType struct {
|
|
Locked bool `json:"locked"`
|
|
}
|
|
|
|
// Lock sets a device to "locked"
|
|
func (s *DeviceServiceOp) Lock(deviceID string) (*Response, error) {
|
|
path := fmt.Sprintf("%s/%s", deviceBasePath, deviceID)
|
|
action := lockType{Locked: true}
|
|
|
|
return s.client.DoRequest("PATCH", path, action, nil)
|
|
}
|
|
|
|
// Unlock sets a device to "unlocked"
|
|
func (s *DeviceServiceOp) Unlock(deviceID string) (*Response, error) {
|
|
path := fmt.Sprintf("%s/%s", deviceBasePath, deviceID)
|
|
action := lockType{Locked: false}
|
|
|
|
return s.client.DoRequest("PATCH", path, action, nil)
|
|
}
|