add volume
This commit is contained in:
parent
3481d1bf6e
commit
3099fc7b1c
|
@ -21,6 +21,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"packet_device": resourcePacketDevice(),
|
||||
"packet_ssh_key": resourcePacketSSHKey(),
|
||||
"packet_project": resourcePacketProject(),
|
||||
"packet_volume": resourcePacketVolume(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
|
|
|
@ -208,13 +208,13 @@ func resourcePacketDeviceRead(d *schema.ResourceData, meta interface{}) error {
|
|||
network := map[string]interface{}{
|
||||
"address": ip.Address,
|
||||
"gateway": ip.Gateway,
|
||||
"family": ip.Family,
|
||||
"family": ip.AddressFamily,
|
||||
"cidr": ip.Cidr,
|
||||
"public": ip.Public,
|
||||
}
|
||||
networks = append(networks, network)
|
||||
|
||||
if ip.Family == 4 && ip.Public == true {
|
||||
if ip.AddressFamily == 4 && ip.Public == true {
|
||||
host = ip.Address
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
package packet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/packethost/packngo"
|
||||
)
|
||||
|
||||
func resourcePacketVolume() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourcePacketVolumeCreate,
|
||||
Read: resourcePacketVolumeRead,
|
||||
Update: resourcePacketVolumeUpdate,
|
||||
Delete: resourcePacketVolumeDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"project_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: false,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"size": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: false,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"facility": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"plan": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"billing_cycle": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"state": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"locked": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"snapshot_policies": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"snapshot_frequency": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"snapshot_count": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"attachments": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"href": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"created": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"updated": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourcePacketVolumeCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*packngo.Client)
|
||||
|
||||
createRequest := &packngo.VolumeCreateRequest{
|
||||
PlanID: d.Get("plan").(string),
|
||||
FacilityID: d.Get("facility").(string),
|
||||
BillingCycle: d.Get("billing_cycle").(string),
|
||||
ProjectID: d.Get("project_id").(string),
|
||||
}
|
||||
|
||||
if attr, ok := d.GetOk("description"); ok {
|
||||
createRequest.Description = attr.(string)
|
||||
}
|
||||
|
||||
if attr, ok := d.GetOk("size"); ok {
|
||||
createRequest.Size = attr.(int)
|
||||
}
|
||||
|
||||
snapshot_policies := d.Get("snapshot_policies.#").(int)
|
||||
if snapshot_policies > 0 {
|
||||
createRequest.SnapshotPolicies = make([]*packngo.SnapshotPolicy, 0, snapshot_policies)
|
||||
for i := 0; i < snapshot_policies; i++ {
|
||||
key := fmt.Sprintf("snapshot_policies.%d", i)
|
||||
createRequest.SnapshotPolicies = append(createRequest.SnapshotPolicies, d.Get(key).(*packngo.SnapshotPolicy))
|
||||
}
|
||||
}
|
||||
|
||||
newVolume, _, err := client.Volumes.Create(createRequest)
|
||||
if err != nil {
|
||||
return friendlyError(err)
|
||||
}
|
||||
|
||||
d.SetId(newVolume.ID)
|
||||
|
||||
return resourcePacketVolumeRead(d, meta)
|
||||
}
|
||||
|
||||
func resourcePacketVolumeRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*packngo.Client)
|
||||
|
||||
device, _, err := client.Volumes.Get(d.Id())
|
||||
if err != nil {
|
||||
err = friendlyError(err)
|
||||
|
||||
// If the volume somehow already destroyed, mark as succesfully gone.
|
||||
if isNotFound(err) {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("name", device.Name)
|
||||
d.Set("description", device.Description)
|
||||
d.Set("size", device.Size)
|
||||
d.Set("plan", device.Plan.Slug)
|
||||
d.Set("facility", device.Facility.Code)
|
||||
d.Set("state", device.State)
|
||||
d.Set("billing_cycle", device.BillingCycle)
|
||||
d.Set("locked", device.Locked)
|
||||
d.Set("created", device.Created)
|
||||
d.Set("updated", device.Updated)
|
||||
|
||||
snapshot_policies := make([]*packngo.SnapshotPolicy, 0, len(device.SnapshotPolicies))
|
||||
for _, snapshot_policy := range device.SnapshotPolicies {
|
||||
snapshot_policies = append(snapshot_policies, snapshot_policy)
|
||||
}
|
||||
d.Set("snapshot_policies", snapshot_policies)
|
||||
|
||||
attachments := make([]*packngo.Attachment, 0, len(device.Attachments))
|
||||
for _, attachment := range device.Attachments {
|
||||
attachments = append(attachments, attachment)
|
||||
}
|
||||
d.Set("attachments", attachments)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourcePacketVolumeUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*packngo.Client)
|
||||
|
||||
updateRequest := &packngo.VolumeUpdateRequest{
|
||||
ID: d.Get("id").(string),
|
||||
}
|
||||
|
||||
if attr, ok := d.GetOk("description"); ok {
|
||||
updateRequest.Description = attr.(string)
|
||||
}
|
||||
|
||||
if attr, ok := d.GetOk("plan"); ok {
|
||||
updateRequest.Plan = attr.(string)
|
||||
}
|
||||
|
||||
_, _, err := client.Volumes.Update(updateRequest)
|
||||
if err != nil {
|
||||
return friendlyError(err)
|
||||
}
|
||||
|
||||
return resourcePacketVolumeRead(d, meta)
|
||||
}
|
||||
|
||||
func resourcePacketVolumeDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*packngo.Client)
|
||||
|
||||
if _, err := client.Volumes.Delete(d.Id()); err != nil {
|
||||
return friendlyError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package packet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/packethost/packngo"
|
||||
)
|
||||
|
||||
func TestAccPacketVolume_Basic(t *testing.T) {
|
||||
var volume packngo.Volume
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckPacketVolumeDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckPacketVolumeConfig_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckPacketVolumeExists("packet_volume.foobar", &volume),
|
||||
testAccCheckPacketVolumeAttributes(&volume),
|
||||
resource.TestCheckResourceAttr(
|
||||
"packet_volume.foobar", "name", "foobar"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckPacketVolumeDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*packngo.Client)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "packet_volume" {
|
||||
continue
|
||||
}
|
||||
if _, _, err := client.Volumes.Get(rs.Primary.ID); err == nil {
|
||||
return fmt.Errorf("Volume cstill exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckPacketVolumeAttributes(volume *packngo.Volume) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if volume.Name != "foobar" {
|
||||
return fmt.Errorf("Bad name: %s", volume.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckPacketVolumeExists(n string, volume *packngo.Volume) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No Record ID is set")
|
||||
}
|
||||
|
||||
client := testAccProvider.Meta().(*packngo.Client)
|
||||
|
||||
foundVolume, _, err := client.Volumes.Get(rs.Primary.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if foundVolume.ID != rs.Primary.ID {
|
||||
return fmt.Errorf("Record not found: %v - %v", rs.Primary.ID, foundVolume)
|
||||
}
|
||||
|
||||
*volume = *foundVolume
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var testAccCheckPacketVolumeConfig_basic = fmt.Sprintf(`
|
||||
resource "packet_volume" "foobar" {
|
||||
name = "foobar"
|
||||
}`)
|
|
@ -0,0 +1,9 @@
|
|||
# packngo
|
||||
Packet Go Api Client
|
||||
|
||||
![](https://www.packet.net/media/labs/images/1679091c5a880faf6fb5e6087eb1b2dc/ULY7-hero.png)
|
||||
|
||||
Committing
|
||||
----------
|
||||
|
||||
Before committing, it's a good idea to run `gofmt -w *.go`. ([gofmt](https://golang.org/cmd/gofmt/))
|
|
@ -69,19 +69,6 @@ func (d DeviceActionRequest) String() string {
|
|||
return Stringify(d)
|
||||
}
|
||||
|
||||
// IPAddress used to execute actions on devices
|
||||
type IPAddress struct {
|
||||
Family int `json:"address_family"`
|
||||
Cidr int `json:"cidr"`
|
||||
Address string `json:"address"`
|
||||
Gateway string `json:"gateway"`
|
||||
Public bool `json:"public"`
|
||||
}
|
||||
|
||||
func (n IPAddress) String() string {
|
||||
return Stringify(n)
|
||||
}
|
||||
|
||||
// DeviceServiceOp implements DeviceService
|
||||
type DeviceServiceOp struct {
|
||||
client *Client
|
||||
|
|
|
@ -14,6 +14,7 @@ type Email struct {
|
|||
Default bool `json:"default,omitempty"`
|
||||
URL string `json:"href,omitempty"`
|
||||
}
|
||||
|
||||
func (e Email) String() string {
|
||||
return Stringify(e)
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ type Facility struct {
|
|||
Address *Address `json:"address,omitempty"`
|
||||
URL string `json:"href,omitempty"`
|
||||
}
|
||||
|
||||
func (f Facility) String() string {
|
||||
return Stringify(f)
|
||||
}
|
||||
|
@ -28,11 +29,11 @@ func (f Facility) String() string {
|
|||
type Address struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (a Address) String() string {
|
||||
return Stringify(a)
|
||||
}
|
||||
|
||||
|
||||
// FacilityServiceOp implements FacilityService
|
||||
type FacilityServiceOp struct {
|
||||
client *Client
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
package packngo
|
||||
|
||||
import "fmt"
|
||||
|
||||
const ipBasePath = "/ips"
|
||||
|
||||
// IPService interface defines available IP methods
|
||||
type IPService interface {
|
||||
Assign(deviceID string, assignRequest *IPAddressAssignRequest) (*IPAddress, *Response, error)
|
||||
Unassign(ipAddressID string) (*Response, error)
|
||||
Get(ipAddressID string) (*IPAddress, *Response, error)
|
||||
}
|
||||
|
||||
// IPAddress represents a ip address
|
||||
type IPAddress struct {
|
||||
ID string `json:"id"`
|
||||
Address string `json:"address"`
|
||||
Gateway string `json:"gateway"`
|
||||
Network string `json:"network"`
|
||||
AddressFamily int `json:"address_family"`
|
||||
Netmask string `json:"netmask"`
|
||||
Public bool `json:"public"`
|
||||
Cidr int `json:"cidr"`
|
||||
AssignedTo map[string]string `json:"assigned_to"`
|
||||
Href string `json:"href"`
|
||||
}
|
||||
|
||||
// IPAddressAssignRequest represents the body if a ip assign request
|
||||
type IPAddressAssignRequest struct {
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
func (i IPAddress) String() string {
|
||||
return Stringify(i)
|
||||
}
|
||||
|
||||
// IPServiceOp implements IPService
|
||||
type IPServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Get returns IpAddress by ID
|
||||
func (i *IPServiceOp) Get(ipAddressID string) (*IPAddress, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", ipBasePath, ipAddressID)
|
||||
|
||||
req, err := i.client.NewRequest("GET", path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ip := new(IPAddress)
|
||||
resp, err := i.client.Do(req, ip)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return ip, resp, err
|
||||
}
|
||||
|
||||
// Unassign unassigns an IP address record. This will remove the relationship between an IP
|
||||
// and the device and will make the IP address available to be assigned to another device.
|
||||
func (i *IPServiceOp) Unassign(ipAddressID string) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", ipBasePath, ipAddressID)
|
||||
|
||||
req, err := i.client.NewRequest("DELETE", path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := i.client.Do(req, nil)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Assign assigns an IP address to a device. The IP address must be in one of the IP ranges assigned to the device’s project.
|
||||
func (i *IPServiceOp) Assign(deviceID string, assignRequest *IPAddressAssignRequest) (*IPAddress, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s%s", deviceBasePath, deviceID, ipBasePath)
|
||||
|
||||
req, err := i.client.NewRequest("POST", path, assignRequest)
|
||||
|
||||
ip := new(IPAddress)
|
||||
resp, err := i.client.Do(req, ip)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return ip, resp, err
|
||||
}
|
||||
|
||||
// IP RESERVATIONS API
|
||||
|
||||
// IPReservationService interface defines available IPReservation methods
|
||||
type IPReservationService interface {
|
||||
List(projectID string) ([]IPReservation, *Response, error)
|
||||
RequestMore(projectID string, ipReservationReq *IPReservationRequest) (*Response, error)
|
||||
Get(ipReservationID string) (*IPReservation, *Response, error)
|
||||
Remove(ipReservationID string) (*Response, error)
|
||||
}
|
||||
|
||||
// IPReservationServiceOp implements the IPReservationService interface
|
||||
type IPReservationServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// IPReservationRequest represents the body of a reservation request
|
||||
type IPReservationRequest struct {
|
||||
Type string `json:"type"`
|
||||
Quantity int `json:"quantity"`
|
||||
Comments string `json:"comments"`
|
||||
}
|
||||
|
||||
// IPReservation represent an IP reservation for a single project
|
||||
type IPReservation struct {
|
||||
ID string `json:"id"`
|
||||
Network string `json:"network"`
|
||||
Address string `json:"address"`
|
||||
AddressFamily int `json:"address_family"`
|
||||
Netmask string `json:"netmask"`
|
||||
Public bool `json:"public"`
|
||||
Cidr int `json:"cidr"`
|
||||
Management bool `json:"management"`
|
||||
Manageable bool `json:"manageable"`
|
||||
Addon bool `json:"addon"`
|
||||
Bill bool `json:"bill"`
|
||||
Assignments []map[string]string `json:"assignments"`
|
||||
Href string `json:"href"`
|
||||
}
|
||||
|
||||
type ipReservationRoot struct {
|
||||
IPReservations []IPReservation `json:"ip_addresses"`
|
||||
}
|
||||
|
||||
// List provides a list of IP resevations for a single project.
|
||||
func (i *IPReservationServiceOp) List(projectID string) ([]IPReservation, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s%s", projectBasePath, projectID, ipBasePath)
|
||||
|
||||
req, err := i.client.NewRequest("GET", path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
reservations := new(ipReservationRoot)
|
||||
resp, err := i.client.Do(req, reservations)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return reservations.IPReservations, resp, err
|
||||
}
|
||||
|
||||
// RequestMore requests more IP space for a project in order to have additional IP addresses to assign to devices
|
||||
func (i *IPReservationServiceOp) RequestMore(projectID string, ipReservationReq *IPReservationRequest) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/%s%s", projectBasePath, projectID, ipBasePath)
|
||||
|
||||
req, err := i.client.NewRequest("POST", path, &ipReservationReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := i.client.Do(req, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Get returns a single IP reservation object
|
||||
func (i *IPReservationServiceOp) Get(ipReservationID string) (*IPReservation, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", ipBasePath, ipReservationID)
|
||||
|
||||
req, err := i.client.NewRequest("GET", path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
reservation := new(IPReservation)
|
||||
resp, err := i.client.Do(req, reservation)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return reservation, resp, err
|
||||
}
|
||||
|
||||
// Remove removes an IP reservation from the project.
|
||||
func (i *IPReservationServiceOp) Remove(ipReservationID string) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", ipBasePath, ipReservationID)
|
||||
|
||||
req, err := i.client.NewRequest("DELETE", path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := i.client.Do(req, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
|
@ -18,6 +18,7 @@ type OS struct {
|
|||
Distro string `json:"distro"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
func (o OS) String() string {
|
||||
return Stringify(o)
|
||||
}
|
||||
|
|
|
@ -89,6 +89,9 @@ type Client struct {
|
|||
Projects ProjectService
|
||||
Facilities FacilityService
|
||||
OperatingSystems OSService
|
||||
Ips IPService
|
||||
IpReservations IPReservationService
|
||||
Volumes VolumeService
|
||||
}
|
||||
|
||||
// NewRequest inits a new http request with the proper headers
|
||||
|
@ -165,6 +168,10 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
|
|||
// an older version of Go, pass in a custom http.Client with a custom TLS configuration
|
||||
// that sets "InsecureSkipVerify" to "true"
|
||||
func NewClient(consumerToken string, apiKey string, httpClient *http.Client) *Client {
|
||||
client, _ := NewClientWithBaseURL(consumerToken, apiKey, httpClient, baseURL)
|
||||
return client
|
||||
}
|
||||
func NewClientWithBaseURL(consumerToken string, apiKey string, httpClient *http.Client, apiBaseURL string) (*Client, error) {
|
||||
if httpClient == nil {
|
||||
// Don't fall back on http.DefaultClient as it's not nice to adjust state
|
||||
// implicitly. If the client wants to use http.DefaultClient, they can
|
||||
|
@ -172,9 +179,12 @@ func NewClient(consumerToken string, apiKey string, httpClient *http.Client) *Cl
|
|||
httpClient = &http.Client{}
|
||||
}
|
||||
|
||||
BaseURL, _ := url.Parse(baseURL)
|
||||
u, err := url.Parse(apiBaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Client{client: httpClient, BaseURL: BaseURL, UserAgent: userAgent, ConsumerToken: consumerToken, APIKey: apiKey}
|
||||
c := &Client{client: httpClient, BaseURL: u, UserAgent: userAgent, ConsumerToken: consumerToken, APIKey: apiKey}
|
||||
c.Plans = &PlanServiceOp{client: c}
|
||||
c.Users = &UserServiceOp{client: c}
|
||||
c.Emails = &EmailServiceOp{client: c}
|
||||
|
@ -183,8 +193,11 @@ func NewClient(consumerToken string, apiKey string, httpClient *http.Client) *Cl
|
|||
c.Projects = &ProjectServiceOp{client: c}
|
||||
c.Facilities = &FacilityServiceOp{client: c}
|
||||
c.OperatingSystems = &OSServiceOp{client: c}
|
||||
c.Ips = &IPServiceOp{client: c}
|
||||
c.IpReservations = &IPReservationServiceOp{client: c}
|
||||
c.Volumes = &VolumeServiceOp{client: c}
|
||||
|
||||
return c
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func checkResponse(r *http.Response) error {
|
||||
|
|
|
@ -21,6 +21,7 @@ type Plan struct {
|
|||
Specs *Specs `json:"specs,omitempty"`
|
||||
Pricing *Pricing `json:"pricing,omitempty"`
|
||||
}
|
||||
|
||||
func (p Plan) String() string {
|
||||
return Stringify(p)
|
||||
}
|
||||
|
@ -33,6 +34,7 @@ type Specs struct {
|
|||
Nics []*Nics `json:"nics,omitempty"`
|
||||
Features *Features `json:"features,omitempty"`
|
||||
}
|
||||
|
||||
func (s Specs) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
@ -42,6 +44,7 @@ type Cpus struct {
|
|||
Count int `json:"count,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func (c Cpus) String() string {
|
||||
return Stringify(c)
|
||||
}
|
||||
|
@ -50,6 +53,7 @@ func (c Cpus) String() string {
|
|||
type Memory struct {
|
||||
Total string `json:"total,omitempty"`
|
||||
}
|
||||
|
||||
func (m Memory) String() string {
|
||||
return Stringify(m)
|
||||
}
|
||||
|
@ -60,6 +64,7 @@ type Drives struct {
|
|||
Size string `json:"size,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func (d Drives) String() string {
|
||||
return Stringify(d)
|
||||
}
|
||||
|
@ -69,6 +74,7 @@ type Nics struct {
|
|||
Count int `json:"count,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func (n Nics) String() string {
|
||||
return Stringify(n)
|
||||
}
|
||||
|
@ -78,6 +84,7 @@ type Features struct {
|
|||
Raid bool `json:"raid,omitempty"`
|
||||
Txt bool `json:"txt,omitempty"`
|
||||
}
|
||||
|
||||
func (f Features) String() string {
|
||||
return Stringify(f)
|
||||
}
|
||||
|
@ -87,6 +94,7 @@ type Pricing struct {
|
|||
Hourly float32 `json:"hourly,omitempty"`
|
||||
Monthly float32 `json:"monthly,omitempty"`
|
||||
}
|
||||
|
||||
func (p Pricing) String() string {
|
||||
return Stringify(p)
|
||||
}
|
||||
|
|
|
@ -11,11 +11,22 @@ type ProjectService interface {
|
|||
Create(*ProjectCreateRequest) (*Project, *Response, error)
|
||||
Update(*ProjectUpdateRequest) (*Project, *Response, error)
|
||||
Delete(string) (*Response, error)
|
||||
ListIPAddresses(string) ([]IPAddress, *Response, error)
|
||||
ListVolumes(string) ([]Volume, *Response, error)
|
||||
}
|
||||
|
||||
type ipsRoot struct {
|
||||
IPAddresses []IPAddress `json:"ip_addresses"`
|
||||
}
|
||||
|
||||
type volumesRoot struct {
|
||||
Volumes []Volume `json:"volumes"`
|
||||
}
|
||||
|
||||
type projectsRoot struct {
|
||||
Projects []Project `json:"projects"`
|
||||
}
|
||||
|
||||
// Project represents a Packet project
|
||||
type Project struct {
|
||||
ID string `json:"id"`
|
||||
|
@ -27,6 +38,7 @@ type Project struct {
|
|||
SSHKeys []SSHKey `json:"ssh_keys,omitempty"`
|
||||
URL string `json:"href,omitempty"`
|
||||
}
|
||||
|
||||
func (p Project) String() string {
|
||||
return Stringify(p)
|
||||
}
|
||||
|
@ -36,6 +48,7 @@ type ProjectCreateRequest struct {
|
|||
Name string `json:"name"`
|
||||
PaymentMethod string `json:"payment_method,omitempty"`
|
||||
}
|
||||
|
||||
func (p ProjectCreateRequest) String() string {
|
||||
return Stringify(p)
|
||||
}
|
||||
|
@ -46,6 +59,7 @@ type ProjectUpdateRequest struct {
|
|||
Name string `json:"name,omitempty"`
|
||||
PaymentMethod string `json:"payment_method,omitempty"`
|
||||
}
|
||||
|
||||
func (p ProjectUpdateRequest) String() string {
|
||||
return Stringify(p)
|
||||
}
|
||||
|
@ -55,6 +69,22 @@ type ProjectServiceOp struct {
|
|||
client *Client
|
||||
}
|
||||
|
||||
func (s *ProjectServiceOp) ListIPAddresses(projectID string) ([]IPAddress, *Response, error) {
|
||||
url := fmt.Sprintf("%s/%s/ips", projectBasePath, projectID)
|
||||
req, err := s.client.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(ipsRoot)
|
||||
resp, err := s.client.Do(req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.IPAddresses, resp, err
|
||||
}
|
||||
|
||||
// List returns the user's projects
|
||||
func (s *ProjectServiceOp) List() ([]Project, *Response, error) {
|
||||
req, err := s.client.NewRequest("GET", projectBasePath, nil)
|
||||
|
@ -134,3 +164,20 @@ func (s *ProjectServiceOp) Delete(projectID string) (*Response, error) {
|
|||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// List returns Volumes for a project
|
||||
func (s *ProjectServiceOp) ListVolumes(projectID string) ([]Volume, *Response, error) {
|
||||
url := fmt.Sprintf("%s/%s%s", projectBasePath, projectID, volumeBasePath)
|
||||
req, err := s.client.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(volumesRoot)
|
||||
resp, err := s.client.Do(req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return root.Volumes, resp, err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ type Rate struct {
|
|||
RequestsRemaining int `json:"requests_remaining"`
|
||||
Reset Timestamp `json:"rate_reset"`
|
||||
}
|
||||
|
||||
func (r Rate) String() string {
|
||||
return Stringify(r)
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ type SSHKey struct {
|
|||
User User `json:"user,omitempty"`
|
||||
URL string `json:"href,omitempty"`
|
||||
}
|
||||
|
||||
func (s SSHKey) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
@ -37,6 +38,7 @@ type SSHKeyCreateRequest struct {
|
|||
Label string `json:"label"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
func (s SSHKeyCreateRequest) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
@ -47,6 +49,7 @@ type SSHKeyUpdateRequest struct {
|
|||
Label string `json:"label"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
func (s SSHKeyUpdateRequest) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ type User struct {
|
|||
PhoneNumber string `json:"phone_number,omitempty"`
|
||||
URL string `json:"href,omitempty"`
|
||||
}
|
||||
|
||||
func (u User) String() string {
|
||||
return Stringify(u)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
package packngo
|
||||
|
||||
import "fmt"
|
||||
|
||||
const volumeBasePath = "/storage"
|
||||
|
||||
// VolumeService interface defines available Volume methods
|
||||
type VolumeService interface {
|
||||
Get(string) (*Volume, *Response, error)
|
||||
Update(*VolumeUpdateRequest) (*Volume, *Response, error)
|
||||
Delete(string) (*Response, error)
|
||||
Create(*VolumeCreateRequest) (*Volume, *Response, error)
|
||||
}
|
||||
|
||||
// Volume represents a volume
|
||||
type Volume struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Size int `json:"size,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
Locked bool `json:"locked,omitempty"`
|
||||
BillingCycle string `json:"billing_cycle,omitempty"`
|
||||
Created string `json:"created_at,omitempty"`
|
||||
Updated string `json:"updated_at,omitempty"`
|
||||
Href string `json:"href,omitempty"`
|
||||
SnapshotPolicies []*SnapshotPolicy `json:"snapshot_policies,omitempty"`
|
||||
Attachments []*Attachment `json:"attachments,omitempty"`
|
||||
Plan *Plan `json:"plan,omitempty"`
|
||||
Facility *Facility `json:"facility,omitempty"`
|
||||
Project *Project `json:"project,omitempty"`
|
||||
}
|
||||
|
||||
// SnapshotPolicy used to execute actions on volume
|
||||
type SnapshotPolicy struct {
|
||||
ID string `json:"id"`
|
||||
Href string `json:"href"`
|
||||
SnapshotFrequency string `json:"snapshot_frequency,omitempty"`
|
||||
snapshot_count int `json:"snapshot_count,omitempty"`
|
||||
}
|
||||
|
||||
// Attachment used to execute actions on volume
|
||||
type Attachment struct {
|
||||
ID string `json:"id"`
|
||||
Href string `json:"href"`
|
||||
}
|
||||
|
||||
func (v Volume) String() string {
|
||||
return Stringify(v)
|
||||
}
|
||||
|
||||
// VolumeCreateRequest type used to create a Packet volume
|
||||
type VolumeCreateRequest struct {
|
||||
Size int `json:"size"`
|
||||
BillingCycle string `json:"billing_cycle"`
|
||||
ProjectID string `json:"project_id"`
|
||||
PlanID string `json:"plan_id"`
|
||||
FacilityID string `json:"facility_id"`
|
||||
Description string `json:"Description,omitempty"`
|
||||
SnapshotPolicies []*SnapshotPolicy `json:"snapshot_policies,omitempty"`
|
||||
}
|
||||
|
||||
func (v VolumeCreateRequest) String() string {
|
||||
return Stringify(v)
|
||||
}
|
||||
|
||||
// VolumeUpdateRequest type used to update a Packet volume
|
||||
type VolumeUpdateRequest struct {
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Plan string `json:"plan,omitempty"`
|
||||
}
|
||||
|
||||
func (v VolumeUpdateRequest) String() string {
|
||||
return Stringify(v)
|
||||
}
|
||||
|
||||
// VolumeServiceOp implements VolumeService
|
||||
type VolumeServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Get returns a volume by id
|
||||
func (v *VolumeServiceOp) Get(volumeID string) (*Volume, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", volumeBasePath, volumeID)
|
||||
req, err := v.client.NewRequest("GET", path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
volume := new(Volume)
|
||||
resp, err := v.client.Do(req, volume)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return volume, resp, err
|
||||
}
|
||||
|
||||
// Update updates a volume
|
||||
func (v *VolumeServiceOp) Update(updateRequest *VolumeUpdateRequest) (*Volume, *Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", volumeBasePath, updateRequest.ID)
|
||||
req, err := v.client.NewRequest("PATCH", path, updateRequest)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
volume := new(Volume)
|
||||
resp, err := v.client.Do(req, volume)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return volume, resp, err
|
||||
}
|
||||
|
||||
// Delete deletes a volume
|
||||
func (v *VolumeServiceOp) Delete(volumeID string) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", volumeBasePath, volumeID)
|
||||
|
||||
req, err := v.client.NewRequest("DELETE", path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := v.client.Do(req, nil)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Create creates a new volume for a project
|
||||
func (v *VolumeServiceOp) Create(createRequest *VolumeCreateRequest) (*Volume, *Response, error) {
|
||||
url := fmt.Sprintf("%s/%s%s", projectBasePath, createRequest.ProjectID, volumeBasePath)
|
||||
req, err := v.client.NewRequest("POST", url, createRequest)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
volume := new(Volume)
|
||||
resp, err := v.client.Do(req, volume)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return volume, resp, err
|
||||
}
|
|
@ -1464,8 +1464,10 @@
|
|||
"revision": "3d184cea22ee1c41ec1697e0d830ff0c78f7ea97"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "yHIFvxXMD3q3ZvQZFLw+EJBhTq8=",
|
||||
"path": "github.com/packethost/packngo",
|
||||
"revision": "f03d7dc788a8b57b62d301ccb98c950c325756f8"
|
||||
"revision": "a596b01fbf1afdf90188ec02aa61fe7cc9703945",
|
||||
"revisionTime": "2016-07-21T21:43:59Z"
|
||||
},
|
||||
{
|
||||
"path": "github.com/pborman/uuid",
|
||||
|
|
Loading…
Reference in New Issue