Merge branch 'ayudemura-add_volume'

This commit is contained in:
stack72 2016-08-15 08:40:06 +01:00
commit 71c941e2a3
No known key found for this signature in database
GPG Key ID: 8619A619B085CB16
21 changed files with 933 additions and 73 deletions

View File

@ -21,6 +21,7 @@ func Provider() terraform.ResourceProvider {
"packet_device": resourcePacketDevice(),
"packet_ssh_key": resourcePacketSSHKey(),
"packet_project": resourcePacketProject(),
"packet_volume": resourcePacketVolume(),
},
ConfigureFunc: providerConfigure,

View File

@ -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
}
}

View File

@ -38,7 +38,7 @@ func testAccCheckPacketProjectDestroy(s *terraform.State) error {
continue
}
if _, _, err := client.Projects.Get(rs.Primary.ID); err == nil {
return fmt.Errorf("Project cstill exists")
return fmt.Errorf("Project still exists")
}
}

View File

@ -0,0 +1,281 @@
package packet
import (
"errors"
"fmt"
"time"
"github.com/hashicorp/terraform/helper/resource"
"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{
"id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"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: true,
},
"facility": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"plan": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"billing_cycle": &schema.Schema{
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"state": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"locked": &schema.Schema{
Type: schema.TypeBool,
Optional: 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),
ProjectID: d.Get("project_id").(string),
Size: d.Get("size").(int),
}
if attr, ok := d.GetOk("billing_cycle"); ok {
createRequest.BillingCycle = attr.(string)
} else {
createRequest.BillingCycle = "hourly"
}
if attr, ok := d.GetOk("description"); ok {
createRequest.Description = attr.(string)
}
snapshot_count := d.Get("snapshot_policies.#").(int)
if snapshot_count > 0 {
createRequest.SnapshotPolicies = make([]*packngo.SnapshotPolicy, 0, snapshot_count)
for i := 0; i < snapshot_count; i++ {
policy := new(packngo.SnapshotPolicy)
policy.SnapshotFrequency = d.Get(fmt.Sprintf("snapshot_policies.%d.snapshot_frequency", i)).(string)
policy.SnapshotCount = d.Get(fmt.Sprintf("snapshot_policies.%d.snapshot_count", i)).(int)
createRequest.SnapshotPolicies = append(createRequest.SnapshotPolicies, policy)
}
}
newVolume, _, err := client.Volumes.Create(createRequest)
if err != nil {
return friendlyError(err)
}
d.SetId(newVolume.ID)
_, err = waitForVolumeAttribute(d, "active", []string{"queued", "provisioning"}, "state", meta)
if err != nil {
if isForbidden(err) {
// If the volume doesn't get to the active state, we can't recover it from here.
d.SetId("")
return errors.New("provisioning time limit exceeded; the Packet team will investigate")
}
return err
}
return resourcePacketVolumeRead(d, meta)
}
func waitForVolumeAttribute(d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) {
stateConf := &resource.StateChangeConf{
Pending: pending,
Target: []string{target},
Refresh: newVolumeStateRefreshFunc(d, attribute, meta),
Timeout: 60 * time.Minute,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}
return stateConf.WaitForState()
}
func newVolumeStateRefreshFunc(d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc {
client := meta.(*packngo.Client)
return func() (interface{}, string, error) {
if err := resourcePacketVolumeRead(d, meta); err != nil {
return nil, "", err
}
if attr, ok := d.GetOk(attribute); ok {
volume, _, err := client.Volumes.Get(d.Id())
if err != nil {
return nil, "", friendlyError(err)
}
return &volume, attr.(string), nil
}
return nil, "", nil
}
}
func resourcePacketVolumeRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*packngo.Client)
volume, _, 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", volume.Name)
d.Set("description", volume.Description)
d.Set("size", volume.Size)
d.Set("plan", volume.Plan.Slug)
d.Set("facility", volume.Facility.Code)
d.Set("state", volume.State)
d.Set("billing_cycle", volume.BillingCycle)
d.Set("locked", volume.Locked)
d.Set("created", volume.Created)
d.Set("updated", volume.Updated)
snapshot_policies := make([]map[string]interface{}, 0, len(volume.SnapshotPolicies))
for _, snapshot_policy := range volume.SnapshotPolicies {
policy := map[string]interface{}{
"snapshot_frequency": snapshot_policy.SnapshotFrequency,
"snapshot_count": snapshot_policy.SnapshotCount,
}
snapshot_policies = append(snapshot_policies, policy)
}
d.Set("snapshot_policies", snapshot_policies)
attachments := make([]*packngo.Attachment, 0, len(volume.Attachments))
for _, attachment := range volume.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
}

View File

@ -0,0 +1,92 @@
package packet
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"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
rs := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckPacketVolumeDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: fmt.Sprintf(testAccCheckPacketVolumeConfig_basic, rs),
Check: resource.ComposeTestCheckFunc(
testAccCheckPacketVolumeExists("packet_volume.foobar", &volume),
resource.TestCheckResourceAttr(
"packet_volume.foobar", "plan", "storage_1"),
resource.TestCheckResourceAttr(
"packet_volume.foobar", "billing_cycle", "hourly"),
resource.TestCheckResourceAttr(
"packet_volume.foobar", "size", "100"),
),
},
},
})
}
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 still exists")
}
}
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
}
}
const testAccCheckPacketVolumeConfig_basic = `
resource "packet_project" "foobar" {
name = "%s"
}
resource "packet_volume" "foobar" {
plan = "storage_1"
billing_cycle = "hourly"
size = 100
project_id = "${packet_project.foobar.id}"
facility = "ewr1"
snapshot_policies = { snapshot_frequency = "1day", snapshot_count = 7 }
}`

9
vendor/github.com/packethost/packngo/README.md generated vendored Normal file
View File

@ -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/))

View File

@ -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

View File

@ -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)
}

View File

@ -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

203
vendor/github.com/packethost/packngo/ip.go generated vendored Normal file
View File

@ -0,0 +1,203 @@
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"`
Created string `json:"created_at,omitempty"`
Updated string `json:"updated_at,omitempty"`
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 devices 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) (*IPReservation, *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"`
Created string `json:"created_at,omitempty"`
Updated string `json:"updated_at,omitempty"`
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) (*IPReservation, *Response, error) {
path := fmt.Sprintf("%s/%s%s", projectBasePath, projectID, ipBasePath)
req, err := i.client.NewRequest("POST", path, &ipReservationReq)
if err != nil {
return nil, nil, err
}
ip := new(IPReservation)
resp, err := i.client.Do(req, ip)
if err != nil {
return nil, resp, err
}
return ip, 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
}

View File

@ -18,6 +18,7 @@ type OS struct {
Distro string `json:"distro"`
Version string `json:"version"`
}
func (o OS) String() string {
return Stringify(o)
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

146
vendor/github.com/packethost/packngo/volumes.go generated vendored Normal file
View File

@ -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"`
SnapshotCount 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?include=facility,snapshot_policies,attachments.device", 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
}

4
vendor/vendor.json vendored
View File

@ -1283,8 +1283,10 @@
"revision": "3d184cea22ee1c41ec1697e0d830ff0c78f7ea97"
},
{
"checksumSHA1": "MexE5QPVAwVfQcJBnMGMgD+s9L0=",
"path": "github.com/packethost/packngo",
"revision": "f03d7dc788a8b57b62d301ccb98c950c325756f8"
"revision": "7cd5fed006859e86dd5641a6cf9812e855b7574a",
"revisionTime": "2016-08-11T16:27:25Z"
},
{
"path": "github.com/pborman/uuid",

View File

@ -0,0 +1,60 @@
---
layout: "packet"
page_title: "Packet: packet_volume"
sidebar_current: "docs-packet-resource-volume"
description: |-
Provides a Packet Block Storage Volume Resource.
---
# packet\_volume
Provides a Packet Block Storage Volume resource to allow you to
manage block volumes on your account.
Once created by Terraform, they must then be attached and mounted
using the api and `packet_block_attach` and `packet_block_detach`
scripts.
## Example Usage
```
# Create a new block volume
resource "packet_volume" "volume1" {
description = "terraform-volume-1"
facility = "ewr1"
project_id = "${packet_project.cool_project.id}"
plan = 'storage_1'
size = 100
billing_cycle = "hourly"
snapshot_policies = { snapshot_frequency = "1day", snapshot_count = 7 }
snapshot_policies = { snapshot_frequency = "1month", snapshot_count = 6 }
}
```
## Argument Reference
The following arguments are supported:
* `plan` - (Required) The service plan slug of the volume
* `facility` - (Required) The facility to create the volume in
* `project_id` - (Required) The packet project ID to deploy the volume in
* `size` - (Required) The size in GB to make the volume
* `billing_cycle` - The billing cycle, defaults to "hourly"
* `description` - Optional description for the volume
* `snapshot_policies` - Optional list of snapshot policies
## Attributes Reference
The following attributes are exported:
* `id` - The unique ID of the volume
* `name` - The name of the volume
* `description` - The description of the volume
* `size` - The size in GB of the volume
* `plan` - Performance plan the volume is on
* `billing_cycle` - The billing cycle, defaults to hourly
* `facility` - The facility slug the volume resides in
* `state` - The state of the volume
* `locked` - Whether the volume is locked or not
* `project_id ` - The project id the volume is in
* `created` - The timestamp for when the volume was created
* `updated` - The timestamp for the last time the volume was updated

View File

@ -22,6 +22,9 @@
<li<%= sidebar_current("docs-packet-resource-ssh-key") %>>
<a href="/docs/providers/packet/r/ssh_key.html">packet_ssh_key</a>
</li>
<li<%= sidebar_current("docs-packet-resource-volume") %>>
<a href="/docs/providers/packet/r/volume.html">packet_volume</a>
</li>
</ul>
</li>
</ul>