Merge pull request #14578 from caiofilipini/digitalocean-certs

provider/digitalocean: Add support for certificates
This commit is contained in:
Jake Champlin 2017-05-26 13:07:15 -04:00 committed by GitHub
commit 24202fb3c1
53 changed files with 1357 additions and 622 deletions

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"log" "log"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
@ -55,7 +56,7 @@ func waitForAction(client *godo.Client, action *godo.Action) error {
pending = "in-progress" pending = "in-progress"
target = "completed" target = "completed"
refreshfn = func() (result interface{}, state string, err error) { refreshfn = func() (result interface{}, state string, err error) {
a, _, err := client.Actions.Get(action.ID) a, _, err := client.Actions.Get(context.Background(), action.ID)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"strconv" "strconv"
@ -54,7 +55,7 @@ func dataSourceDigitalOceanImageRead(d *schema.ResourceData, meta interface{}) e
opts := &godo.ListOptions{} opts := &godo.ListOptions{}
images, _, err := client.Images.ListUser(opts) images, _, err := client.Images.ListUser(context.Background(), opts)
if err != nil { if err != nil {
d.SetId("") d.SetId("")
return err return err

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"regexp" "regexp"
@ -70,7 +71,7 @@ func takeSnapshotsOfDroplet(rInt int, droplet *godo.Droplet, snapshotsId *[]int)
return err return err
} }
} }
retrieveDroplet, _, err := client.Droplets.Get((*droplet).ID) retrieveDroplet, _, err := client.Droplets.Get(context.Background(), (*droplet).ID)
if err != nil { if err != nil {
return err return err
} }
@ -81,7 +82,7 @@ func takeSnapshotsOfDroplet(rInt int, droplet *godo.Droplet, snapshotsId *[]int)
func takeSnapshotOfDroplet(rInt, sInt int, droplet *godo.Droplet) error { func takeSnapshotOfDroplet(rInt, sInt int, droplet *godo.Droplet) error {
client := testAccProvider.Meta().(*godo.Client) client := testAccProvider.Meta().(*godo.Client)
action, _, err := client.DropletActions.Snapshot((*droplet).ID, fmt.Sprintf("snap-%d-%d", rInt, sInt)) action, _, err := client.DropletActions.Snapshot(context.Background(), (*droplet).ID, fmt.Sprintf("snap-%d-%d", rInt, sInt))
if err != nil { if err != nil {
return err return err
} }
@ -96,7 +97,7 @@ func deleteSnapshots(snapshotsId *[]int) resource.TestCheckFunc {
snapshots := *snapshotsId snapshots := *snapshotsId
for _, value := range snapshots { for _, value := range snapshots {
log.Printf("XXX Deleting %d", value) log.Printf("XXX Deleting %d", value)
_, err := client.Images.Delete(value) _, err := client.Images.Delete(context.Background(), value)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"github.com/digitalocean/godo" "github.com/digitalocean/godo"
@ -9,7 +10,7 @@ import (
func loadbalancerStateRefreshFunc(client *godo.Client, loadbalancerId string) resource.StateRefreshFunc { func loadbalancerStateRefreshFunc(client *godo.Client, loadbalancerId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) { return func() (interface{}, string, error) {
lb, _, err := client.LoadBalancers.Get(loadbalancerId) lb, _, err := client.LoadBalancers.Get(context.Background(), loadbalancerId)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("Error issuing read request in LoadbalancerStateRefreshFunc to DigitalOcean for Load Balancer '%s': %s", loadbalancerId, err) return nil, "", fmt.Errorf("Error issuing read request in LoadbalancerStateRefreshFunc to DigitalOcean for Load Balancer '%s': %s", loadbalancerId, err)
} }

View File

@ -22,6 +22,7 @@ func Provider() terraform.ResourceProvider {
}, },
ResourcesMap: map[string]*schema.Resource{ ResourcesMap: map[string]*schema.Resource{
"digitalocean_certificate": resourceDigitalOceanCertificate(),
"digitalocean_domain": resourceDigitalOceanDomain(), "digitalocean_domain": resourceDigitalOceanDomain(),
"digitalocean_droplet": resourceDigitalOceanDroplet(), "digitalocean_droplet": resourceDigitalOceanDroplet(),
"digitalocean_floating_ip": resourceDigitalOceanFloatingIp(), "digitalocean_floating_ip": resourceDigitalOceanFloatingIp(),

View File

@ -0,0 +1,116 @@
package digitalocean
import (
"context"
"fmt"
"log"
"github.com/digitalocean/godo"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceDigitalOceanCertificate() *schema.Resource {
return &schema.Resource{
Create: resourceDigitalOceanCertificateCreate,
Read: resourceDigitalOceanCertificateRead,
Delete: resourceDigitalOceanCertificateDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"private_key": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"leaf_certificate": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"certificate_chain": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"not_after": {
Type: schema.TypeString,
Computed: true,
},
"sha1_fingerprint": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
func buildCertificateRequest(d *schema.ResourceData) (*godo.CertificateRequest, error) {
req := &godo.CertificateRequest{
Name: d.Get("name").(string),
PrivateKey: d.Get("private_key").(string),
LeafCertificate: d.Get("leaf_certificate").(string),
CertificateChain: d.Get("certificate_chain").(string),
}
return req, nil
}
func resourceDigitalOceanCertificateCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client)
log.Printf("[INFO] Create a Certificate Request")
certReq, err := buildCertificateRequest(d)
if err != nil {
return err
}
log.Printf("[DEBUG] Certificate Create: %#v", certReq)
cert, _, err := client.Certificates.Create(context.Background(), certReq)
if err != nil {
return fmt.Errorf("Error creating Certificate: %s", err)
}
d.SetId(cert.ID)
return resourceDigitalOceanCertificateRead(d, meta)
}
func resourceDigitalOceanCertificateRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client)
log.Printf("[INFO] Reading the details of the Certificate %s", d.Id())
cert, _, err := client.Certificates.Get(context.Background(), d.Id())
if err != nil {
return fmt.Errorf("Error retrieving Certificate: %s", err)
}
d.Set("name", cert.Name)
d.Set("not_after", cert.NotAfter)
d.Set("sha1_fingerprint", cert.SHA1Fingerprint)
return nil
}
func resourceDigitalOceanCertificateDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client)
log.Printf("[INFO] Deleting Certificate: %s", d.Id())
_, err := client.Certificates.Delete(context.Background(), d.Id())
if err != nil {
return fmt.Errorf("Error deleting Certificate: %s", err)
}
return nil
}

View File

@ -0,0 +1,114 @@
package digitalocean
import (
"context"
"fmt"
"strings"
"testing"
"github.com/digitalocean/godo"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccDigitalOceanCertificate_Basic(t *testing.T) {
var cert godo.Certificate
rInt := acctest.RandInt()
leafCertMaterial, privateKeyMaterial, err := acctest.RandTLSCert("Acme Co")
if err != nil {
t.Fatalf("Cannot generate test TLS certificate: %s", err)
}
rootCertMaterial, _, err := acctest.RandTLSCert("Acme Go")
if err != nil {
t.Fatalf("Cannot generate test TLS certificate: %s", err)
}
certChainMaterial := fmt.Sprintf("%s\n%s", strings.TrimSpace(rootCertMaterial), leafCertMaterial)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDigitalOceanCertificateDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckDigitalOceanCertificateConfig_basic(rInt, privateKeyMaterial, leafCertMaterial, certChainMaterial),
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanCertificateExists("digitalocean_certificate.foobar", &cert),
resource.TestCheckResourceAttr(
"digitalocean_certificate.foobar", "name", fmt.Sprintf("certificate-%d", rInt)),
resource.TestCheckResourceAttr(
"digitalocean_certificate.foobar", "private_key", fmt.Sprintf("%s\n", privateKeyMaterial)),
resource.TestCheckResourceAttr(
"digitalocean_certificate.foobar", "leaf_certificate", fmt.Sprintf("%s\n", leafCertMaterial)),
resource.TestCheckResourceAttr(
"digitalocean_certificate.foobar", "certificate_chain", fmt.Sprintf("%s\n", certChainMaterial)),
),
},
},
})
}
func testAccCheckDigitalOceanCertificateDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*godo.Client)
for _, rs := range s.RootModule().Resources {
if rs.Type != "digitalocean_certificate" {
continue
}
_, _, err := client.Certificates.Get(context.Background(), rs.Primary.ID)
if err != nil && !strings.Contains(err.Error(), "404") {
return fmt.Errorf(
"Error waiting for certificate (%s) to be destroyed: %s",
rs.Primary.ID, err)
}
}
return nil
}
func testAccCheckDigitalOceanCertificateExists(n string, cert *godo.Certificate) 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 Certificate ID is set")
}
client := testAccProvider.Meta().(*godo.Client)
c, _, err := client.Certificates.Get(context.Background(), rs.Primary.ID)
if err != nil {
return err
}
if c.ID != rs.Primary.ID {
return fmt.Errorf("Certificate not found")
}
*cert = *c
return nil
}
}
func testAccCheckDigitalOceanCertificateConfig_basic(rInt int, privateKeyMaterial, leafCert, certChain string) string {
return fmt.Sprintf(`
resource "digitalocean_certificate" "foobar" {
name = "certificate-%d"
private_key = <<EOF
%s
EOF
leaf_certificate = <<EOF
%s
EOF
certificate_chain = <<EOF
%s
EOF
}`, rInt, privateKeyMaterial, leafCert, certChain)
}

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
@ -44,7 +45,7 @@ func resourceDigitalOceanDomainCreate(d *schema.ResourceData, meta interface{})
} }
log.Printf("[DEBUG] Domain create configuration: %#v", opts) log.Printf("[DEBUG] Domain create configuration: %#v", opts)
domain, _, err := client.Domains.Create(opts) domain, _, err := client.Domains.Create(context.Background(), opts)
if err != nil { if err != nil {
return fmt.Errorf("Error creating Domain: %s", err) return fmt.Errorf("Error creating Domain: %s", err)
} }
@ -58,7 +59,7 @@ func resourceDigitalOceanDomainCreate(d *schema.ResourceData, meta interface{})
func resourceDigitalOceanDomainRead(d *schema.ResourceData, meta interface{}) error { func resourceDigitalOceanDomainRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client) client := meta.(*godo.Client)
domain, resp, err := client.Domains.Get(d.Id()) domain, resp, err := client.Domains.Get(context.Background(), d.Id())
if err != nil { if err != nil {
// If the domain is somehow already destroyed, mark as // If the domain is somehow already destroyed, mark as
// successfully gone // successfully gone
@ -79,7 +80,7 @@ func resourceDigitalOceanDomainDelete(d *schema.ResourceData, meta interface{})
client := meta.(*godo.Client) client := meta.(*godo.Client)
log.Printf("[INFO] Deleting Domain: %s", d.Id()) log.Printf("[INFO] Deleting Domain: %s", d.Id())
_, err := client.Domains.Delete(d.Id()) _, err := client.Domains.Delete(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf("Error deleting Domain: %s", err) return fmt.Errorf("Error deleting Domain: %s", err)
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"testing" "testing"
@ -43,7 +44,7 @@ func testAccCheckDigitalOceanDomainDestroy(s *terraform.State) error {
} }
// Try to find the domain // Try to find the domain
_, _, err := client.Domains.Get(rs.Primary.ID) _, _, err := client.Domains.Get(context.Background(), rs.Primary.ID)
if err == nil { if err == nil {
return fmt.Errorf("Domain still exists") return fmt.Errorf("Domain still exists")
@ -78,7 +79,7 @@ func testAccCheckDigitalOceanDomainExists(n string, domain *godo.Domain) resourc
client := testAccProvider.Meta().(*godo.Client) client := testAccProvider.Meta().(*godo.Client)
foundDomain, _, err := client.Domains.Get(rs.Primary.ID) foundDomain, _, err := client.Domains.Get(context.Background(), rs.Primary.ID)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"strconv" "strconv"
@ -213,7 +214,7 @@ func resourceDigitalOceanDropletCreate(d *schema.ResourceData, meta interface{})
log.Printf("[DEBUG] Droplet create configuration: %#v", opts) log.Printf("[DEBUG] Droplet create configuration: %#v", opts)
droplet, _, err := client.Droplets.Create(opts) droplet, _, err := client.Droplets.Create(context.Background(), opts)
if err != nil { if err != nil {
return fmt.Errorf("Error creating droplet: %s", err) return fmt.Errorf("Error creating droplet: %s", err)
@ -248,7 +249,7 @@ func resourceDigitalOceanDropletRead(d *schema.ResourceData, meta interface{}) e
} }
// Retrieve the droplet properties for updating the state // Retrieve the droplet properties for updating the state
droplet, resp, err := client.Droplets.Get(id) droplet, resp, err := client.Droplets.Get(context.Background(), id)
if err != nil { if err != nil {
// check if the droplet no longer exists. // check if the droplet no longer exists.
if resp != nil && resp.StatusCode == 404 { if resp != nil && resp.StatusCode == 404 {
@ -341,7 +342,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
if d.HasChange("size") || d.HasChange("resize_disk") && resize_disk { if d.HasChange("size") || d.HasChange("resize_disk") && resize_disk {
newSize := d.Get("size") newSize := d.Get("size")
_, _, err = client.DropletActions.PowerOff(id) _, _, err = client.DropletActions.PowerOff(context.Background(), id)
if err != nil && !strings.Contains(err.Error(), "Droplet is already powered off") { if err != nil && !strings.Contains(err.Error(), "Droplet is already powered off") {
return fmt.Errorf( return fmt.Errorf(
"Error powering off droplet (%s): %s", d.Id(), err) "Error powering off droplet (%s): %s", d.Id(), err)
@ -355,7 +356,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
} }
// Resize the droplet // Resize the droplet
action, _, err := client.DropletActions.Resize(id, newSize.(string), resize_disk) action, _, err := client.DropletActions.Resize(context.Background(), id, newSize.(string), resize_disk)
if err != nil { if err != nil {
newErr := powerOnAndWait(d, meta) newErr := powerOnAndWait(d, meta)
if newErr != nil { if newErr != nil {
@ -377,7 +378,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
"Error waiting for resize droplet (%s) to finish: %s", d.Id(), err) "Error waiting for resize droplet (%s) to finish: %s", d.Id(), err)
} }
_, _, err = client.DropletActions.PowerOn(id) _, _, err = client.DropletActions.PowerOn(context.Background(), id)
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
@ -395,7 +396,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
oldName, newName := d.GetChange("name") oldName, newName := d.GetChange("name")
// Rename the droplet // Rename the droplet
_, _, err = client.DropletActions.Rename(id, newName.(string)) _, _, err = client.DropletActions.Rename(context.Background(), id, newName.(string))
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
@ -415,7 +416,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
// As there is no way to disable private networking, // As there is no way to disable private networking,
// we only check if it needs to be enabled // we only check if it needs to be enabled
if d.HasChange("private_networking") && d.Get("private_networking").(bool) { if d.HasChange("private_networking") && d.Get("private_networking").(bool) {
_, _, err = client.DropletActions.EnablePrivateNetworking(id) _, _, err = client.DropletActions.EnablePrivateNetworking(context.Background(), id)
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
@ -432,7 +433,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
// As there is no way to disable IPv6, we only check if it needs to be enabled // As there is no way to disable IPv6, we only check if it needs to be enabled
if d.HasChange("ipv6") && d.Get("ipv6").(bool) { if d.HasChange("ipv6") && d.Get("ipv6").(bool) {
_, _, err = client.DropletActions.EnableIPv6(id) _, _, err = client.DropletActions.EnableIPv6(context.Background(), id)
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
@ -478,7 +479,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
oldIDSet := newSet(oldIDs.([]interface{})) oldIDSet := newSet(oldIDs.([]interface{}))
newIDSet := newSet(newIDs.([]interface{})) newIDSet := newSet(newIDs.([]interface{}))
for volumeID := range leftDiff(newIDSet, oldIDSet) { for volumeID := range leftDiff(newIDSet, oldIDSet) {
action, _, err := client.StorageActions.Attach(volumeID, id) action, _, err := client.StorageActions.Attach(context.Background(), volumeID, id)
if err != nil { if err != nil {
return fmt.Errorf("Error attaching volume %q to droplet (%s): %s", volumeID, d.Id(), err) return fmt.Errorf("Error attaching volume %q to droplet (%s): %s", volumeID, d.Id(), err)
} }
@ -488,7 +489,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
} }
} }
for volumeID := range leftDiff(oldIDSet, newIDSet) { for volumeID := range leftDiff(oldIDSet, newIDSet) {
action, _, err := client.StorageActions.Detach(volumeID) action, _, err := client.StorageActions.DetachByDropletID(context.Background(), volumeID, id)
if err != nil { if err != nil {
return fmt.Errorf("Error detaching volume %q from droplet (%s): %s", volumeID, d.Id(), err) return fmt.Errorf("Error detaching volume %q from droplet (%s): %s", volumeID, d.Id(), err)
} }
@ -521,7 +522,7 @@ func resourceDigitalOceanDropletDelete(d *schema.ResourceData, meta interface{})
log.Printf("[INFO] Deleting droplet: %s", d.Id()) log.Printf("[INFO] Deleting droplet: %s", d.Id())
// Destroy the droplet // Destroy the droplet
_, err = client.Droplets.Delete(id) _, err = client.Droplets.Delete(context.Background(), id)
// Handle remotely destroyed droplets // Handle remotely destroyed droplets
if err != nil && strings.Contains(err.Error(), "404 Not Found") { if err != nil && strings.Contains(err.Error(), "404 Not Found") {
@ -587,7 +588,7 @@ func newDropletStateRefreshFunc(
// See if we can access our attribute // See if we can access our attribute
if attr, ok := d.GetOk(attribute); ok { if attr, ok := d.GetOk(attribute); ok {
// Retrieve the droplet properties // Retrieve the droplet properties
droplet, _, err := client.Droplets.Get(id) droplet, _, err := client.Droplets.Get(context.Background(), id)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("Error retrieving droplet: %s", err) return nil, "", fmt.Errorf("Error retrieving droplet: %s", err)
} }
@ -607,7 +608,7 @@ func powerOnAndWait(d *schema.ResourceData, meta interface{}) error {
} }
client := meta.(*godo.Client) client := meta.(*godo.Client)
_, _, err = client.DropletActions.PowerOn(id) _, _, err = client.DropletActions.PowerOn(context.Background(), id)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
@ -332,7 +333,7 @@ func testAccCheckDigitalOceanDropletDestroy(s *terraform.State) error {
} }
// Try to find the Droplet // Try to find the Droplet
_, _, err = client.Droplets.Get(id) _, _, err = client.Droplets.Get(context.Background(), id)
// Wait // Wait
@ -482,7 +483,7 @@ func testAccCheckDigitalOceanDropletExists(n string, droplet *godo.Droplet) reso
} }
// Try to find the Droplet // Try to find the Droplet
retrieveDroplet, _, err := client.Droplets.Get(id) retrieveDroplet, _, err := client.Droplets.Get(context.Background(), id)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"time" "time"
@ -50,7 +51,7 @@ func resourceDigitalOceanFloatingIpCreate(d *schema.ResourceData, meta interface
} }
log.Printf("[DEBUG] FloatingIP Create: %#v", regionOpts) log.Printf("[DEBUG] FloatingIP Create: %#v", regionOpts)
floatingIp, _, err := client.FloatingIPs.Create(regionOpts) floatingIp, _, err := client.FloatingIPs.Create(context.Background(), regionOpts)
if err != nil { if err != nil {
return fmt.Errorf("Error creating FloatingIP: %s", err) return fmt.Errorf("Error creating FloatingIP: %s", err)
} }
@ -60,7 +61,7 @@ func resourceDigitalOceanFloatingIpCreate(d *schema.ResourceData, meta interface
if v, ok := d.GetOk("droplet_id"); ok { if v, ok := d.GetOk("droplet_id"); ok {
log.Printf("[INFO] Assigning the Floating IP to the Droplet %d", v.(int)) log.Printf("[INFO] Assigning the Floating IP to the Droplet %d", v.(int))
action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int)) action, _, err := client.FloatingIPActions.Assign(context.Background(), d.Id(), v.(int))
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err) "Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
@ -82,7 +83,7 @@ func resourceDigitalOceanFloatingIpUpdate(d *schema.ResourceData, meta interface
if d.HasChange("droplet_id") { if d.HasChange("droplet_id") {
if v, ok := d.GetOk("droplet_id"); ok { if v, ok := d.GetOk("droplet_id"); ok {
log.Printf("[INFO] Assigning the Floating IP %s to the Droplet %d", d.Id(), v.(int)) log.Printf("[INFO] Assigning the Floating IP %s to the Droplet %d", d.Id(), v.(int))
action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int)) action, _, err := client.FloatingIPActions.Assign(context.Background(), d.Id(), v.(int))
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err) "Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
@ -95,7 +96,7 @@ func resourceDigitalOceanFloatingIpUpdate(d *schema.ResourceData, meta interface
} }
} else { } else {
log.Printf("[INFO] Unassigning the Floating IP %s", d.Id()) log.Printf("[INFO] Unassigning the Floating IP %s", d.Id())
action, _, err := client.FloatingIPActions.Unassign(d.Id()) action, _, err := client.FloatingIPActions.Unassign(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
"Error Unassigning FloatingIP (%s): %s", d.Id(), err) "Error Unassigning FloatingIP (%s): %s", d.Id(), err)
@ -116,7 +117,7 @@ func resourceDigitalOceanFloatingIpRead(d *schema.ResourceData, meta interface{}
client := meta.(*godo.Client) client := meta.(*godo.Client)
log.Printf("[INFO] Reading the details of the FloatingIP %s", d.Id()) log.Printf("[INFO] Reading the details of the FloatingIP %s", d.Id())
floatingIp, _, err := client.FloatingIPs.Get(d.Id()) floatingIp, _, err := client.FloatingIPs.Get(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf("Error retrieving FloatingIP: %s", err) return fmt.Errorf("Error retrieving FloatingIP: %s", err)
} }
@ -140,7 +141,7 @@ func resourceDigitalOceanFloatingIpDelete(d *schema.ResourceData, meta interface
if _, ok := d.GetOk("droplet_id"); ok { if _, ok := d.GetOk("droplet_id"); ok {
log.Printf("[INFO] Unassigning the Floating IP from the Droplet") log.Printf("[INFO] Unassigning the Floating IP from the Droplet")
action, _, err := client.FloatingIPActions.Unassign(d.Id()) action, _, err := client.FloatingIPActions.Unassign(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
"Error Unassigning FloatingIP (%s) from the droplet: %s", d.Id(), err) "Error Unassigning FloatingIP (%s) from the droplet: %s", d.Id(), err)
@ -154,7 +155,7 @@ func resourceDigitalOceanFloatingIpDelete(d *schema.ResourceData, meta interface
} }
log.Printf("[INFO] Deleting FloatingIP: %s", d.Id()) log.Printf("[INFO] Deleting FloatingIP: %s", d.Id())
_, err := client.FloatingIPs.Delete(d.Id()) _, err := client.FloatingIPs.Delete(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf("Error deleting FloatingIP: %s", err) return fmt.Errorf("Error deleting FloatingIP: %s", err)
} }
@ -189,7 +190,7 @@ func newFloatingIPStateRefreshFunc(
return func() (interface{}, string, error) { return func() (interface{}, string, error) {
log.Printf("[INFO] Assigning the Floating IP to the Droplet") log.Printf("[INFO] Assigning the Floating IP to the Droplet")
action, _, err := client.FloatingIPActions.Get(d.Id(), actionId) action, _, err := client.FloatingIPActions.Get(context.Background(), d.Id(), actionId)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("Error retrieving FloatingIP (%s) ActionId (%d): %s", d.Id(), actionId, err) return nil, "", fmt.Errorf("Error retrieving FloatingIP (%s) ActionId (%d): %s", d.Id(), actionId, err)
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"testing" "testing"
@ -60,7 +61,7 @@ func testAccCheckDigitalOceanFloatingIPDestroy(s *terraform.State) error {
} }
// Try to find the key // Try to find the key
_, _, err := client.FloatingIPs.Get(rs.Primary.ID) _, _, err := client.FloatingIPs.Get(context.Background(), rs.Primary.ID)
if err == nil { if err == nil {
return fmt.Errorf("Floating IP still exists") return fmt.Errorf("Floating IP still exists")
@ -85,7 +86,7 @@ func testAccCheckDigitalOceanFloatingIPExists(n string, floatingIP *godo.Floatin
client := testAccProvider.Meta().(*godo.Client) client := testAccProvider.Meta().(*godo.Client)
// Try to find the FloatingIP // Try to find the FloatingIP
foundFloatingIP, _, err := client.FloatingIPs.Get(rs.Primary.ID) foundFloatingIP, _, err := client.FloatingIPs.Get(context.Background(), rs.Primary.ID)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"strconv" "strconv"
@ -210,7 +211,7 @@ func resourceDigitalOceanLoadbalancerCreate(d *schema.ResourceData, meta interfa
} }
log.Printf("[DEBUG] Loadbalancer Create: %#v", lbOpts) log.Printf("[DEBUG] Loadbalancer Create: %#v", lbOpts)
loadbalancer, _, err := client.LoadBalancers.Create(lbOpts) loadbalancer, _, err := client.LoadBalancers.Create(context.Background(), lbOpts)
if err != nil { if err != nil {
return fmt.Errorf("Error creating Load Balancer: %s", err) return fmt.Errorf("Error creating Load Balancer: %s", err)
} }
@ -236,7 +237,7 @@ func resourceDigitalOceanLoadbalancerRead(d *schema.ResourceData, meta interface
client := meta.(*godo.Client) client := meta.(*godo.Client)
log.Printf("[INFO] Reading the details of the Loadbalancer %s", d.Id()) log.Printf("[INFO] Reading the details of the Loadbalancer %s", d.Id())
loadbalancer, _, err := client.LoadBalancers.Get(d.Id()) loadbalancer, _, err := client.LoadBalancers.Get(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf("Error retrieving Loadbalancer: %s", err) return fmt.Errorf("Error retrieving Loadbalancer: %s", err)
} }
@ -274,7 +275,7 @@ func resourceDigitalOceanLoadbalancerUpdate(d *schema.ResourceData, meta interfa
} }
log.Printf("[DEBUG] Load Balancer Update: %#v", lbOpts) log.Printf("[DEBUG] Load Balancer Update: %#v", lbOpts)
_, _, err = client.LoadBalancers.Update(d.Id(), lbOpts) _, _, err = client.LoadBalancers.Update(context.Background(), d.Id(), lbOpts)
if err != nil { if err != nil {
return fmt.Errorf("Error updating Load Balancer: %s", err) return fmt.Errorf("Error updating Load Balancer: %s", err)
} }
@ -286,7 +287,7 @@ func resourceDigitalOceanLoadbalancerDelete(d *schema.ResourceData, meta interfa
client := meta.(*godo.Client) client := meta.(*godo.Client)
log.Printf("[INFO] Deleting Load Balancer: %s", d.Id()) log.Printf("[INFO] Deleting Load Balancer: %s", d.Id())
_, err := client.LoadBalancers.Delete(d.Id()) _, err := client.LoadBalancers.Delete(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf("Error deleting Load Balancer: %s", err) return fmt.Errorf("Error deleting Load Balancer: %s", err)
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"strings" "strings"
"testing" "testing"
@ -170,7 +171,7 @@ func testAccCheckDigitalOceanLoadbalancerDestroy(s *terraform.State) error {
continue continue
} }
_, _, err := client.LoadBalancers.Get(rs.Primary.ID) _, _, err := client.LoadBalancers.Get(context.Background(), rs.Primary.ID)
if err != nil && !strings.Contains(err.Error(), "404") { if err != nil && !strings.Contains(err.Error(), "404") {
return fmt.Errorf( return fmt.Errorf(
@ -195,7 +196,7 @@ func testAccCheckDigitalOceanLoadbalancerExists(n string, loadbalancer *godo.Loa
client := testAccProvider.Meta().(*godo.Client) client := testAccProvider.Meta().(*godo.Client)
lb, _, err := client.LoadBalancers.Get(rs.Primary.ID) lb, _, err := client.LoadBalancers.Get(context.Background(), rs.Primary.ID)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"strconv" "strconv"
@ -101,7 +102,7 @@ func resourceDigitalOceanRecordCreate(d *schema.ResourceData, meta interface{})
} }
log.Printf("[DEBUG] record create configuration: %#v", newRecord) log.Printf("[DEBUG] record create configuration: %#v", newRecord)
rec, _, err := client.Domains.CreateRecord(d.Get("domain").(string), &newRecord) rec, _, err := client.Domains.CreateRecord(context.Background(), d.Get("domain").(string), &newRecord)
if err != nil { if err != nil {
return fmt.Errorf("Failed to create record: %s", err) return fmt.Errorf("Failed to create record: %s", err)
} }
@ -120,7 +121,7 @@ func resourceDigitalOceanRecordRead(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("invalid record ID: %v", err) return fmt.Errorf("invalid record ID: %v", err)
} }
rec, resp, err := client.Domains.Record(domain, id) rec, resp, err := client.Domains.Record(context.Background(), domain, id)
if err != nil { if err != nil {
// If the record is somehow already destroyed, mark as // If the record is somehow already destroyed, mark as
// successfully gone // successfully gone
@ -168,7 +169,7 @@ func resourceDigitalOceanRecordUpdate(d *schema.ResourceData, meta interface{})
} }
log.Printf("[DEBUG] record update configuration: %#v", editRecord) log.Printf("[DEBUG] record update configuration: %#v", editRecord)
_, _, err = client.Domains.EditRecord(domain, id, &editRecord) _, _, err = client.Domains.EditRecord(context.Background(), domain, id, &editRecord)
if err != nil { if err != nil {
return fmt.Errorf("Failed to update record: %s", err) return fmt.Errorf("Failed to update record: %s", err)
} }
@ -187,7 +188,7 @@ func resourceDigitalOceanRecordDelete(d *schema.ResourceData, meta interface{})
log.Printf("[INFO] Deleting record: %s, %d", domain, id) log.Printf("[INFO] Deleting record: %s, %d", domain, id)
resp, delErr := client.Domains.DeleteRecord(domain, id) resp, delErr := client.Domains.DeleteRecord(context.Background(), domain, id)
if delErr != nil { if delErr != nil {
// If the record is somehow already destroyed, mark as // If the record is somehow already destroyed, mark as
// successfully gone // successfully gone

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"strconv" "strconv"
"testing" "testing"
@ -235,7 +236,7 @@ func testAccCheckDigitalOceanRecordDestroy(s *terraform.State) error {
return err return err
} }
_, _, err = client.Domains.Record(domain, id) _, _, err = client.Domains.Record(context.Background(), domain, id)
if err == nil { if err == nil {
return fmt.Errorf("Record still exists") return fmt.Errorf("Record still exists")
@ -287,7 +288,7 @@ func testAccCheckDigitalOceanRecordExists(n string, record *godo.DomainRecord) r
return err return err
} }
foundRecord, _, err := client.Domains.Record(domain, id) foundRecord, _, err := client.Domains.Record(context.Background(), domain, id)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"strconv" "strconv"
@ -60,7 +61,7 @@ func resourceDigitalOceanSSHKeyCreate(d *schema.ResourceData, meta interface{})
} }
log.Printf("[DEBUG] SSH Key create configuration: %#v", opts) log.Printf("[DEBUG] SSH Key create configuration: %#v", opts)
key, _, err := client.Keys.Create(opts) key, _, err := client.Keys.Create(context.Background(), opts)
if err != nil { if err != nil {
return fmt.Errorf("Error creating SSH Key: %s", err) return fmt.Errorf("Error creating SSH Key: %s", err)
} }
@ -79,7 +80,7 @@ func resourceDigitalOceanSSHKeyRead(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("invalid SSH key id: %v", err) return fmt.Errorf("invalid SSH key id: %v", err)
} }
key, resp, err := client.Keys.GetByID(id) key, resp, err := client.Keys.GetByID(context.Background(), id)
if err != nil { if err != nil {
// If the key is somehow already destroyed, mark as // If the key is somehow already destroyed, mark as
// successfully gone // successfully gone
@ -115,7 +116,7 @@ func resourceDigitalOceanSSHKeyUpdate(d *schema.ResourceData, meta interface{})
opts := &godo.KeyUpdateRequest{ opts := &godo.KeyUpdateRequest{
Name: newName, Name: newName,
} }
_, _, err = client.Keys.UpdateByID(id, opts) _, _, err = client.Keys.UpdateByID(context.Background(), id, opts)
if err != nil { if err != nil {
return fmt.Errorf("Failed to update SSH key: %s", err) return fmt.Errorf("Failed to update SSH key: %s", err)
} }
@ -132,7 +133,7 @@ func resourceDigitalOceanSSHKeyDelete(d *schema.ResourceData, meta interface{})
} }
log.Printf("[INFO] Deleting SSH key: %d", id) log.Printf("[INFO] Deleting SSH key: %d", id)
_, err = client.Keys.DeleteByID(id) _, err = client.Keys.DeleteByID(context.Background(), id)
if err != nil { if err != nil {
return fmt.Errorf("Error deleting SSH key: %s", err) return fmt.Errorf("Error deleting SSH key: %s", err)
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"strconv" "strconv"
"testing" "testing"
@ -52,7 +53,7 @@ func testAccCheckDigitalOceanSSHKeyDestroy(s *terraform.State) error {
} }
// Try to find the key // Try to find the key
_, _, err = client.Keys.GetByID(id) _, _, err = client.Keys.GetByID(context.Background(), id)
if err == nil { if err == nil {
return fmt.Errorf("SSH key still exists") return fmt.Errorf("SSH key still exists")
@ -82,7 +83,7 @@ func testAccCheckDigitalOceanSSHKeyExists(n string, key *godo.Key) resource.Test
} }
// Try to find the key // Try to find the key
foundKey, _, err := client.Keys.GetByID(id) foundKey, _, err := client.Keys.GetByID(context.Background(), id)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
@ -12,7 +13,6 @@ func resourceDigitalOceanTag() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
Create: resourceDigitalOceanTagCreate, Create: resourceDigitalOceanTagCreate,
Read: resourceDigitalOceanTagRead, Read: resourceDigitalOceanTagRead,
Update: resourceDigitalOceanTagUpdate,
Delete: resourceDigitalOceanTagDelete, Delete: resourceDigitalOceanTagDelete,
Importer: &schema.ResourceImporter{ Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough, State: schema.ImportStatePassthrough,
@ -22,6 +22,7 @@ func resourceDigitalOceanTag() *schema.Resource {
"name": { "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true,
}, },
}, },
} }
@ -36,7 +37,7 @@ func resourceDigitalOceanTagCreate(d *schema.ResourceData, meta interface{}) err
} }
log.Printf("[DEBUG] Tag create configuration: %#v", opts) log.Printf("[DEBUG] Tag create configuration: %#v", opts)
tag, _, err := client.Tags.Create(opts) tag, _, err := client.Tags.Create(context.Background(), opts)
if err != nil { if err != nil {
return fmt.Errorf("Error creating tag: %s", err) return fmt.Errorf("Error creating tag: %s", err)
} }
@ -50,7 +51,7 @@ func resourceDigitalOceanTagCreate(d *schema.ResourceData, meta interface{}) err
func resourceDigitalOceanTagRead(d *schema.ResourceData, meta interface{}) error { func resourceDigitalOceanTagRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client) client := meta.(*godo.Client)
tag, resp, err := client.Tags.Get(d.Id()) tag, resp, err := client.Tags.Get(context.Background(), d.Id())
if err != nil { if err != nil {
// If the tag is somehow already destroyed, mark as // If the tag is somehow already destroyed, mark as
// successfully gone // successfully gone
@ -67,34 +68,11 @@ func resourceDigitalOceanTagRead(d *schema.ResourceData, meta interface{}) error
return nil return nil
} }
func resourceDigitalOceanTagUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client)
var newName string
if v, ok := d.GetOk("name"); ok {
newName = v.(string)
}
log.Printf("[DEBUG] tag update name: %#v", newName)
opts := &godo.TagUpdateRequest{
Name: newName,
}
_, err := client.Tags.Update(d.Id(), opts)
if err != nil {
return fmt.Errorf("Failed to update tag: %s", err)
}
d.Set("name", newName)
return resourceDigitalOceanTagRead(d, meta)
}
func resourceDigitalOceanTagDelete(d *schema.ResourceData, meta interface{}) error { func resourceDigitalOceanTagDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client) client := meta.(*godo.Client)
log.Printf("[INFO] Deleting tag: %s", d.Id()) log.Printf("[INFO] Deleting tag: %s", d.Id())
_, err := client.Tags.Delete(d.Id()) _, err := client.Tags.Delete(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf("Error deleting tag: %s", err) return fmt.Errorf("Error deleting tag: %s", err)
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"testing" "testing"
@ -39,7 +40,7 @@ func testAccCheckDigitalOceanTagDestroy(s *terraform.State) error {
} }
// Try to find the key // Try to find the key
_, _, err := client.Tags.Get(rs.Primary.ID) _, _, err := client.Tags.Get(context.Background(), rs.Primary.ID)
if err == nil { if err == nil {
return fmt.Errorf("Tag still exists") return fmt.Errorf("Tag still exists")
@ -75,7 +76,7 @@ func testAccCheckDigitalOceanTagExists(n string, tag *godo.Tag) resource.TestChe
client := testAccProvider.Meta().(*godo.Client) client := testAccProvider.Meta().(*godo.Client)
// Try to find the tag // Try to find the tag
foundTag, _, err := client.Tags.Get(rs.Primary.ID) foundTag, _, err := client.Tags.Get(context.Background(), rs.Primary.ID)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"log" "log"
@ -67,7 +68,7 @@ func resourceDigitalOceanVolumeCreate(d *schema.ResourceData, meta interface{})
} }
log.Printf("[DEBUG] Volume create configuration: %#v", opts) log.Printf("[DEBUG] Volume create configuration: %#v", opts)
volume, _, err := client.Storage.CreateVolume(opts) volume, _, err := client.Storage.CreateVolume(context.Background(), opts)
if err != nil { if err != nil {
return fmt.Errorf("Error creating Volume: %s", err) return fmt.Errorf("Error creating Volume: %s", err)
} }
@ -81,7 +82,7 @@ func resourceDigitalOceanVolumeCreate(d *schema.ResourceData, meta interface{})
func resourceDigitalOceanVolumeRead(d *schema.ResourceData, meta interface{}) error { func resourceDigitalOceanVolumeRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client) client := meta.(*godo.Client)
volume, resp, err := client.Storage.GetVolume(d.Id()) volume, resp, err := client.Storage.GetVolume(context.Background(), d.Id())
if err != nil { if err != nil {
// If the volume is somehow already destroyed, mark as // If the volume is somehow already destroyed, mark as
// successfully gone // successfully gone
@ -111,7 +112,7 @@ func resourceDigitalOceanVolumeDelete(d *schema.ResourceData, meta interface{})
client := meta.(*godo.Client) client := meta.(*godo.Client)
log.Printf("[INFO] Deleting volume: %s", d.Id()) log.Printf("[INFO] Deleting volume: %s", d.Id())
_, err := client.Storage.DeleteVolume(d.Id()) _, err := client.Storage.DeleteVolume(context.Background(), d.Id())
if err != nil { if err != nil {
return fmt.Errorf("Error deleting volume: %s", err) return fmt.Errorf("Error deleting volume: %s", err)
} }
@ -122,7 +123,7 @@ func resourceDigitalOceanVolumeDelete(d *schema.ResourceData, meta interface{})
func resourceDigitalOceanVolumeImport(rs *schema.ResourceData, v interface{}) ([]*schema.ResourceData, error) { func resourceDigitalOceanVolumeImport(rs *schema.ResourceData, v interface{}) ([]*schema.ResourceData, error) {
client := v.(*godo.Client) client := v.(*godo.Client)
volume, _, err := client.Storage.GetVolume(rs.Id()) volume, _, err := client.Storage.GetVolume(context.Background(), rs.Id())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"fmt" "fmt"
"testing" "testing"
@ -60,7 +61,7 @@ func testAccCheckDigitalOceanVolumeExists(rn string, volume *godo.Volume) resour
client := testAccProvider.Meta().(*godo.Client) client := testAccProvider.Meta().(*godo.Client)
got, _, err := client.Storage.GetVolume(rs.Primary.ID) got, _, err := client.Storage.GetVolume(context.Background(), rs.Primary.ID)
if err != nil { if err != nil {
return err return err
} }
@ -82,7 +83,7 @@ func testAccCheckDigitalOceanVolumeDestroy(s *terraform.State) error {
} }
// Try to find the volume // Try to find the volume
_, _, err := client.Storage.GetVolume(rs.Primary.ID) _, _, err := client.Storage.GetVolume(context.Background(), rs.Primary.ID)
if err == nil { if err == nil {
return fmt.Errorf("Volume still exists") return fmt.Errorf("Volume still exists")

View File

@ -1,6 +1,7 @@
package digitalocean package digitalocean
import ( import (
"context"
"log" "log"
"github.com/digitalocean/godo" "github.com/digitalocean/godo"
@ -15,7 +16,7 @@ func setTags(conn *godo.Client, d *schema.ResourceData) error {
log.Printf("[DEBUG] Removing tags: %#v from %s", remove, d.Id()) log.Printf("[DEBUG] Removing tags: %#v from %s", remove, d.Id())
for _, tag := range remove { for _, tag := range remove {
_, err := conn.Tags.UntagResources(tag, &godo.UntagResourcesRequest{ _, err := conn.Tags.UntagResources(context.Background(), tag, &godo.UntagResourcesRequest{
Resources: []godo.Resource{ Resources: []godo.Resource{
{ {
ID: d.Id(), ID: d.Id(),
@ -30,7 +31,7 @@ func setTags(conn *godo.Client, d *schema.ResourceData) error {
log.Printf("[DEBUG] Creating tags: %s for %s", create, d.Id()) log.Printf("[DEBUG] Creating tags: %s for %s", create, d.Id())
for _, tag := range create { for _, tag := range create {
_, err := conn.Tags.TagResources(tag, &godo.TagResourcesRequest{ _, err := conn.Tags.TagResources(context.Background(), tag, &godo.TagResourcesRequest{
Resources: []godo.Resource{ Resources: []godo.Resource{
{ {
ID: d.Id(), ID: d.Id(),

View File

@ -1,13 +1,14 @@
package acctest package acctest
import ( import (
"bufio"
"bytes" "bytes"
crand "crypto/rand" crand "crypto/rand"
"crypto/rsa" "crypto/rsa"
"crypto/x509" "crypto/x509"
"crypto/x509/pkix"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"math/big"
"math/rand" "math/rand"
"strings" "strings"
"time" "time"
@ -58,23 +59,71 @@ func RandStringFromCharSet(strlen int, charSet string) string {
// RandSSHKeyPair generates a public and private SSH key pair. The public key is // RandSSHKeyPair generates a public and private SSH key pair. The public key is
// returned in OpenSSH format, and the private key is PEM encoded. // returned in OpenSSH format, and the private key is PEM encoded.
func RandSSHKeyPair(comment string) (string, string, error) { func RandSSHKeyPair(comment string) (string, string, error) {
privateKey, err := rsa.GenerateKey(crand.Reader, 1024) privateKey, privateKeyPEM, err := genPrivateKey()
if err != nil {
return "", "", err
}
var privateKeyBuffer bytes.Buffer
privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
if err := pem.Encode(bufio.NewWriter(&privateKeyBuffer), privateKeyPEM); err != nil {
return "", "", err
}
publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey) publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
keyMaterial := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey))) keyMaterial := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey)))
return fmt.Sprintf("%s %s", keyMaterial, comment), privateKeyBuffer.String(), nil return fmt.Sprintf("%s %s", keyMaterial, comment), privateKeyPEM, nil
}
// RandTLSCert generates a self-signed TLS certificate with a newly created
// private key, and returns both the cert and the private key PEM encoded.
func RandTLSCert(orgName string) (string, string, error) {
template := &x509.Certificate{
SerialNumber: big.NewInt(int64(RandInt())),
Subject: pkix.Name{
Organization: []string{orgName},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
privateKey, privateKeyPEM, err := genPrivateKey()
if err != nil {
return "", "", err
}
cert, err := x509.CreateCertificate(crand.Reader, template, template, &privateKey.PublicKey, privateKey)
if err != nil {
return "", "", err
}
certPEM, err := pemEncode(cert, "CERTIFICATE")
if err != nil {
return "", "", err
}
return certPEM, privateKeyPEM, nil
}
func genPrivateKey() (*rsa.PrivateKey, string, error) {
privateKey, err := rsa.GenerateKey(crand.Reader, 1024)
if err != nil {
return nil, "", err
}
privateKeyPEM, err := pemEncode(x509.MarshalPKCS1PrivateKey(privateKey), "RSA PRIVATE KEY")
if err != nil {
return nil, "", err
}
return privateKey, privateKeyPEM, nil
}
func pemEncode(b []byte, block string) (string, error) {
var buf bytes.Buffer
pb := &pem.Block{Type: block, Bytes: b}
if err := pem.Encode(&buf, pb); err != nil {
return "", err
}
return buf.String(), nil
} }
// Seeds random with current timestamp // Seeds random with current timestamp

10
vendor/github.com/digitalocean/godo/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,10 @@
# Change Log
## [v1.0.0] - 2017-03-10
### Added
- #130 Add Convert to ImageActionsService. - @xmudrii
- #126 Add CertificatesService for managing certificates with the DigitalOcean API. - @viola
- #125 Add LoadBalancersService for managing load balancers with the DigitalOcean API. - @viola
- #122 Add GetVolumeByName to StorageService. - @protochron
- #113 Add context.Context to all calls. - @aybabtme

View File

@ -65,7 +65,9 @@ createRequest := &godo.DropletCreateRequest{
}, },
} }
newDroplet, _, err := client.Droplets.Create(createRequest) ctx := context.TODO()
newDroplet, _, err := client.Droplets.Create(ctx, createRequest)
if err != nil { if err != nil {
fmt.Printf("Something bad happened: %s\n\n", err) fmt.Printf("Something bad happened: %s\n\n", err)
@ -78,14 +80,14 @@ if err != nil {
If a list of items is paginated by the API, you must request pages individually. For example, to fetch all Droplets: If a list of items is paginated by the API, you must request pages individually. For example, to fetch all Droplets:
```go ```go
func DropletList(client *godo.Client) ([]godo.Droplet, error) { func DropletList(ctx context.Context, client *godo.Client) ([]godo.Droplet, error) {
// create a list to hold our droplets // create a list to hold our droplets
list := []godo.Droplet{} list := []godo.Droplet{}
// create options. initially, these will be blank // create options. initially, these will be blank
opt := &godo.ListOptions{} opt := &godo.ListOptions{}
for { for {
droplets, resp, err := client.Droplets.List(opt) droplets, resp, err := client.Droplets.List(ctx, opt)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,10 +1,12 @@
package godo package godo
import "github.com/digitalocean/godo/context"
// AccountService is an interface for interfacing with the Account // AccountService is an interface for interfacing with the Account
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2/#account // See: https://developers.digitalocean.com/documentation/v2/#account
type AccountService interface { type AccountService interface {
Get() (*Account, *Response, error) Get(context.Context) (*Account, *Response, error)
} }
// AccountServiceOp handles communication with the Account related methods of // AccountServiceOp handles communication with the Account related methods of
@ -35,16 +37,17 @@ func (r Account) String() string {
} }
// Get DigitalOcean account info // Get DigitalOcean account info
func (s *AccountServiceOp) Get() (*Account, *Response, error) { func (s *AccountServiceOp) Get(ctx context.Context) (*Account, *Response, error) {
path := "v2/account" path := "v2/account"
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(accountRoot) root := new(accountRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -1,6 +1,10 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
const ( const (
actionsBasePath = "v2/actions" actionsBasePath = "v2/actions"
@ -15,8 +19,8 @@ const (
// ActionsService handles communction with action related methods of the // ActionsService handles communction with action related methods of the
// DigitalOcean API: https://developers.digitalocean.com/documentation/v2#actions // DigitalOcean API: https://developers.digitalocean.com/documentation/v2#actions
type ActionsService interface { type ActionsService interface {
List(*ListOptions) ([]Action, *Response, error) List(context.Context, *ListOptions) ([]Action, *Response, error)
Get(int) (*Action, *Response, error) Get(context.Context, int) (*Action, *Response, error)
} }
// ActionsServiceOp handles communition with the image action related methods of the // ActionsServiceOp handles communition with the image action related methods of the
@ -50,20 +54,20 @@ type Action struct {
} }
// List all actions // List all actions
func (s *ActionsServiceOp) List(opt *ListOptions) ([]Action, *Response, error) { func (s *ActionsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Action, *Response, error) {
path := actionsBasePath path := actionsBasePath
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionsRoot) root := new(actionsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -75,19 +79,19 @@ func (s *ActionsServiceOp) List(opt *ListOptions) ([]Action, *Response, error) {
} }
// Get an action by ID. // Get an action by ID.
func (s *ActionsServiceOp) Get(id int) (*Action, *Response, error) { func (s *ActionsServiceOp) Get(ctx context.Context, id int) (*Action, *Response, error) {
if id < 1 { if id < 1 {
return nil, nil, NewArgError("id", "cannot be less than 1") return nil, nil, NewArgError("id", "cannot be less than 1")
} }
path := fmt.Sprintf("%s/%d", actionsBasePath, id) path := fmt.Sprintf("%s/%d", actionsBasePath, id)
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

121
vendor/github.com/digitalocean/godo/certificates.go generated vendored Normal file
View File

@ -0,0 +1,121 @@
package godo
import (
"path"
"github.com/digitalocean/godo/context"
)
const certificatesBasePath = "/v2/certificates"
// CertificatesService is an interface for managing certificates with the DigitalOcean API.
// See: https://developers.digitalocean.com/documentation/v2/#certificates
type CertificatesService interface {
Get(context.Context, string) (*Certificate, *Response, error)
List(context.Context, *ListOptions) ([]Certificate, *Response, error)
Create(context.Context, *CertificateRequest) (*Certificate, *Response, error)
Delete(context.Context, string) (*Response, error)
}
// Certificate represents a DigitalOcean certificate configuration.
type Certificate struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
NotAfter string `json:"not_after,omitempty"`
SHA1Fingerprint string `json:"sha1_fingerprint,omitempty"`
Created string `json:"created_at,omitempty"`
}
// CertificateRequest represents configuration for a new certificate.
type CertificateRequest struct {
Name string `json:"name,omitempty"`
PrivateKey string `json:"private_key,omitempty"`
LeafCertificate string `json:"leaf_certificate,omitempty"`
CertificateChain string `json:"certificate_chain,omitempty"`
}
type certificateRoot struct {
Certificate *Certificate `json:"certificate"`
}
type certificatesRoot struct {
Certificates []Certificate `json:"certificates"`
Links *Links `json:"links"`
}
// CertificatesServiceOp handles communication with certificates methods of the DigitalOcean API.
type CertificatesServiceOp struct {
client *Client
}
var _ CertificatesService = &CertificatesServiceOp{}
// Get an existing certificate by its identifier.
func (c *CertificatesServiceOp) Get(ctx context.Context, cID string) (*Certificate, *Response, error) {
urlStr := path.Join(certificatesBasePath, cID)
req, err := c.client.NewRequest(ctx, "GET", urlStr, nil)
if err != nil {
return nil, nil, err
}
root := new(certificateRoot)
resp, err := c.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Certificate, resp, nil
}
// List all certificates.
func (c *CertificatesServiceOp) List(ctx context.Context, opt *ListOptions) ([]Certificate, *Response, error) {
urlStr, err := addOptions(certificatesBasePath, opt)
if err != nil {
return nil, nil, err
}
req, err := c.client.NewRequest(ctx, "GET", urlStr, nil)
if err != nil {
return nil, nil, err
}
root := new(certificatesRoot)
resp, err := c.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
if l := root.Links; l != nil {
resp.Links = l
}
return root.Certificates, resp, nil
}
// Create a new certificate with provided configuration.
func (c *CertificatesServiceOp) Create(ctx context.Context, cr *CertificateRequest) (*Certificate, *Response, error) {
req, err := c.client.NewRequest(ctx, "POST", certificatesBasePath, cr)
if err != nil {
return nil, nil, err
}
root := new(certificateRoot)
resp, err := c.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Certificate, resp, nil
}
// Delete a certificate by its identifier.
func (c *CertificatesServiceOp) Delete(ctx context.Context, cID string) (*Response, error) {
urlStr := path.Join(certificatesBasePath, cID)
req, err := c.client.NewRequest(ctx, "DELETE", urlStr, nil)
if err != nil {
return nil, err
}
return c.client.Do(ctx, req, nil)
}

98
vendor/github.com/digitalocean/godo/context/context.go generated vendored Normal file
View File

@ -0,0 +1,98 @@
package context
import "time"
// A Context carries a deadline, a cancelation signal, and other values across
// API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
//
// WithCancel arranges for Done to be closed when cancel is called;
// WithDeadline arranges for Done to be closed when the deadline
// expires; WithTimeout arranges for Done to be closed when the timeout
// elapses.
//
// Done is provided for use in select statements:s
//
// // Stream generates values with DoSomething and sends them to out
// // until DoSomething returns an error or ctx.Done is closed.
// func Stream(ctx context.Context, out chan<- Value) error {
// for {
// v, err := DoSomething(ctx)
// if err != nil {
// return err
// }
// select {
// case <-ctx.Done():
// return ctx.Err()
// case out <- v:
// }
// }
// }
//
// See http://blog.golang.org/pipelines for more examples of how to use
// a Done channel for cancelation.
Done() <-chan struct{}
// Err returns a non-nil error value after Done is closed. Err returns
// Canceled if the context was canceled or DeadlineExceeded if the
// context's deadline passed. No other values for Err are defined.
// After Done is closed, successive calls to Err return the same value.
Err() error
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
//
// Use context values only for request-scoped data that transits
// processes and API boundaries, not for passing optional parameters to
// functions.
//
// A key identifies a specific value in a Context. Functions that wish
// to store values in Context typically allocate a key in a global
// variable then use that key as the argument to context.WithValue and
// Context.Value. A key can be any type that supports equality;
// packages should define keys as an unexported type to avoid
// collisions.
//
// Packages that define a Context key should provide type-safe accessors
// for the values stores using that key:
//
// // Package user defines a User type that's stored in Contexts.
// package user
//
// import "golang.org/x/net/context"
//
// // User is the type of value stored in the Contexts.
// type User struct {...}
//
// // key is an unexported type for keys defined in this package.
// // This prevents collisions with keys defined in other packages.
// type key int
//
// // userKey is the key for user.User values in Contexts. It is
// // unexported; clients use user.NewContext and user.FromContext
// // instead of using this key directly.
// var userKey key = 0
//
// // NewContext returns a new Context that carries value u.
// func NewContext(ctx context.Context, u *User) context.Context {
// return context.WithValue(ctx, userKey, u)
// }
//
// // FromContext returns the User value stored in ctx, if any.
// func FromContext(ctx context.Context) (*User, bool) {
// u, ok := ctx.Value(userKey).(*User)
// return u, ok
// }
Value(key interface{}) interface{}
}

View File

@ -0,0 +1,39 @@
// +build go1.7
package context
import (
"context"
"net/http"
)
// DoRequest submits an HTTP request.
func DoRequest(ctx Context, req *http.Request) (*http.Response, error) {
return DoRequestWithClient(ctx, http.DefaultClient, req)
}
// DoRequestWithClient submits an HTTP request using the specified client.
func DoRequestWithClient(
ctx Context,
client *http.Client,
req *http.Request) (*http.Response, error) {
req = req.WithContext(ctx)
return client.Do(req)
}
// TODO returns a non-nil, empty Context. Code should use context.TODO when
// it's unclear which Context to use or it is not yet available (because the
// surrounding function has not yet been extended to accept a Context
// parameter). TODO is recognized by static analysis tools that determine
// whether Contexts are propagated correctly in a program.
func TODO() Context {
return context.TODO()
}
// Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming
// requests.
func Background() Context {
return context.Background()
}

View File

@ -0,0 +1,41 @@
// +build !go1.7
package context
import (
"net/http"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
)
// DoRequest submits an HTTP request.
func DoRequest(ctx Context, req *http.Request) (*http.Response, error) {
return DoRequestWithClient(ctx, http.DefaultClient, req)
}
// DoRequestWithClient submits an HTTP request using the specified client.
func DoRequestWithClient(
ctx Context,
client *http.Client,
req *http.Request) (*http.Response, error) {
return ctxhttp.Do(ctx, client, req)
}
// TODO returns a non-nil, empty Context. Code should use context.TODO when
// it's unclear which Context to use or it is not yet available (because the
// surrounding function has not yet been extended to accept a Context
// parameter). TODO is recognized by static analysis tools that determine
// whether Contexts are propagated correctly in a program.
func TODO() Context {
return context.TODO()
}
// Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming
// requests.
func Background() Context {
return context.Background()
}

View File

@ -1,6 +1,10 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
const domainsBasePath = "v2/domains" const domainsBasePath = "v2/domains"
@ -8,16 +12,16 @@ const domainsBasePath = "v2/domains"
// See: https://developers.digitalocean.com/documentation/v2#domains and // See: https://developers.digitalocean.com/documentation/v2#domains and
// https://developers.digitalocean.com/documentation/v2#domain-records // https://developers.digitalocean.com/documentation/v2#domain-records
type DomainsService interface { type DomainsService interface {
List(*ListOptions) ([]Domain, *Response, error) List(context.Context, *ListOptions) ([]Domain, *Response, error)
Get(string) (*Domain, *Response, error) Get(context.Context, string) (*Domain, *Response, error)
Create(*DomainCreateRequest) (*Domain, *Response, error) Create(context.Context, *DomainCreateRequest) (*Domain, *Response, error)
Delete(string) (*Response, error) Delete(context.Context, string) (*Response, error)
Records(string, *ListOptions) ([]DomainRecord, *Response, error) Records(context.Context, string, *ListOptions) ([]DomainRecord, *Response, error)
Record(string, int) (*DomainRecord, *Response, error) Record(context.Context, string, int) (*DomainRecord, *Response, error)
DeleteRecord(string, int) (*Response, error) DeleteRecord(context.Context, string, int) (*Response, error)
EditRecord(string, int, *DomainRecordEditRequest) (*DomainRecord, *Response, error) EditRecord(context.Context, string, int, *DomainRecordEditRequest) (*DomainRecord, *Response, error)
CreateRecord(string, *DomainRecordEditRequest) (*DomainRecord, *Response, error) CreateRecord(context.Context, string, *DomainRecordEditRequest) (*DomainRecord, *Response, error)
} }
// DomainsServiceOp handles communication with the domain related methods of the // DomainsServiceOp handles communication with the domain related methods of the
@ -70,6 +74,7 @@ type DomainRecord struct {
Data string `json:"data,omitempty"` Data string `json:"data,omitempty"`
Priority int `json:"priority,omitempty"` Priority int `json:"priority,omitempty"`
Port int `json:"port,omitempty"` Port int `json:"port,omitempty"`
TTL int `json:"ttl,omitempty"`
Weight int `json:"weight,omitempty"` Weight int `json:"weight,omitempty"`
} }
@ -80,6 +85,7 @@ type DomainRecordEditRequest struct {
Data string `json:"data,omitempty"` Data string `json:"data,omitempty"`
Priority int `json:"priority,omitempty"` Priority int `json:"priority,omitempty"`
Port int `json:"port,omitempty"` Port int `json:"port,omitempty"`
TTL int `json:"ttl,omitempty"`
Weight int `json:"weight,omitempty"` Weight int `json:"weight,omitempty"`
} }
@ -88,20 +94,20 @@ func (d Domain) String() string {
} }
// List all domains. // List all domains.
func (s DomainsServiceOp) List(opt *ListOptions) ([]Domain, *Response, error) { func (s DomainsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Domain, *Response, error) {
path := domainsBasePath path := domainsBasePath
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(domainsRoot) root := new(domainsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -113,20 +119,20 @@ func (s DomainsServiceOp) List(opt *ListOptions) ([]Domain, *Response, error) {
} }
// Get individual domain. It requires a non-empty domain name. // Get individual domain. It requires a non-empty domain name.
func (s *DomainsServiceOp) Get(name string) (*Domain, *Response, error) { func (s *DomainsServiceOp) Get(ctx context.Context, name string) (*Domain, *Response, error) {
if len(name) < 1 { if len(name) < 1 {
return nil, nil, NewArgError("name", "cannot be an empty string") return nil, nil, NewArgError("name", "cannot be an empty string")
} }
path := fmt.Sprintf("%s/%s", domainsBasePath, name) path := fmt.Sprintf("%s/%s", domainsBasePath, name)
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(domainRoot) root := new(domainRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -135,20 +141,20 @@ func (s *DomainsServiceOp) Get(name string) (*Domain, *Response, error) {
} }
// Create a new domain // Create a new domain
func (s *DomainsServiceOp) Create(createRequest *DomainCreateRequest) (*Domain, *Response, error) { func (s *DomainsServiceOp) Create(ctx context.Context, createRequest *DomainCreateRequest) (*Domain, *Response, error) {
if createRequest == nil { if createRequest == nil {
return nil, nil, NewArgError("createRequest", "cannot be nil") return nil, nil, NewArgError("createRequest", "cannot be nil")
} }
path := domainsBasePath path := domainsBasePath
req, err := s.client.NewRequest("POST", path, createRequest) req, err := s.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(domainRoot) root := new(domainRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -156,19 +162,19 @@ func (s *DomainsServiceOp) Create(createRequest *DomainCreateRequest) (*Domain,
} }
// Delete domain // Delete domain
func (s *DomainsServiceOp) Delete(name string) (*Response, error) { func (s *DomainsServiceOp) Delete(ctx context.Context, name string) (*Response, error) {
if len(name) < 1 { if len(name) < 1 {
return nil, NewArgError("name", "cannot be an empty string") return nil, NewArgError("name", "cannot be an empty string")
} }
path := fmt.Sprintf("%s/%s", domainsBasePath, name) path := fmt.Sprintf("%s/%s", domainsBasePath, name)
req, err := s.client.NewRequest("DELETE", path, nil) req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }
@ -184,7 +190,7 @@ func (d DomainRecordEditRequest) String() string {
} }
// Records returns a slice of DomainRecords for a domain // Records returns a slice of DomainRecords for a domain
func (s *DomainsServiceOp) Records(domain string, opt *ListOptions) ([]DomainRecord, *Response, error) { func (s *DomainsServiceOp) Records(ctx context.Context, domain string, opt *ListOptions) ([]DomainRecord, *Response, error) {
if len(domain) < 1 { if len(domain) < 1 {
return nil, nil, NewArgError("domain", "cannot be an empty string") return nil, nil, NewArgError("domain", "cannot be an empty string")
} }
@ -195,13 +201,13 @@ func (s *DomainsServiceOp) Records(domain string, opt *ListOptions) ([]DomainRec
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(domainRecordsRoot) root := new(domainRecordsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -213,7 +219,7 @@ func (s *DomainsServiceOp) Records(domain string, opt *ListOptions) ([]DomainRec
} }
// Record returns the record id from a domain // Record returns the record id from a domain
func (s *DomainsServiceOp) Record(domain string, id int) (*DomainRecord, *Response, error) { func (s *DomainsServiceOp) Record(ctx context.Context, domain string, id int) (*DomainRecord, *Response, error) {
if len(domain) < 1 { if len(domain) < 1 {
return nil, nil, NewArgError("domain", "cannot be an empty string") return nil, nil, NewArgError("domain", "cannot be an empty string")
} }
@ -224,13 +230,13 @@ func (s *DomainsServiceOp) Record(domain string, id int) (*DomainRecord, *Respon
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id) path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
record := new(domainRecordRoot) record := new(domainRecordRoot)
resp, err := s.client.Do(req, record) resp, err := s.client.Do(ctx, req, record)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -239,7 +245,7 @@ func (s *DomainsServiceOp) Record(domain string, id int) (*DomainRecord, *Respon
} }
// DeleteRecord deletes a record from a domain identified by id // DeleteRecord deletes a record from a domain identified by id
func (s *DomainsServiceOp) DeleteRecord(domain string, id int) (*Response, error) { func (s *DomainsServiceOp) DeleteRecord(ctx context.Context, domain string, id int) (*Response, error) {
if len(domain) < 1 { if len(domain) < 1 {
return nil, NewArgError("domain", "cannot be an empty string") return nil, NewArgError("domain", "cannot be an empty string")
} }
@ -250,18 +256,18 @@ func (s *DomainsServiceOp) DeleteRecord(domain string, id int) (*Response, error
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id) path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
req, err := s.client.NewRequest("DELETE", path, nil) req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }
// EditRecord edits a record using a DomainRecordEditRequest // EditRecord edits a record using a DomainRecordEditRequest
func (s *DomainsServiceOp) EditRecord( func (s *DomainsServiceOp) EditRecord(ctx context.Context,
domain string, domain string,
id int, id int,
editRequest *DomainRecordEditRequest, editRequest *DomainRecordEditRequest,
@ -280,13 +286,13 @@ func (s *DomainsServiceOp) EditRecord(
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id) path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
req, err := s.client.NewRequest("PUT", path, editRequest) req, err := s.client.NewRequest(ctx, "PUT", path, editRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
d := new(DomainRecord) d := new(DomainRecord)
resp, err := s.client.Do(req, d) resp, err := s.client.Do(ctx, req, d)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -295,7 +301,7 @@ func (s *DomainsServiceOp) EditRecord(
} }
// CreateRecord creates a record using a DomainRecordEditRequest // CreateRecord creates a record using a DomainRecordEditRequest
func (s *DomainsServiceOp) CreateRecord( func (s *DomainsServiceOp) CreateRecord(ctx context.Context,
domain string, domain string,
createRequest *DomainRecordEditRequest) (*DomainRecord, *Response, error) { createRequest *DomainRecordEditRequest) (*DomainRecord, *Response, error) {
if len(domain) < 1 { if len(domain) < 1 {
@ -307,14 +313,14 @@ func (s *DomainsServiceOp) CreateRecord(
} }
path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain) path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain)
req, err := s.client.NewRequest("POST", path, createRequest) req, err := s.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
d := new(domainRecordRoot) d := new(domainRecordRoot)
resp, err := s.client.Do(req, d) resp, err := s.client.Do(ctx, req, d)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -3,6 +3,8 @@ package godo
import ( import (
"fmt" "fmt"
"net/url" "net/url"
"github.com/digitalocean/godo/context"
) )
// ActionRequest reprents DigitalOcean Action Request // ActionRequest reprents DigitalOcean Action Request
@ -12,35 +14,35 @@ type ActionRequest map[string]interface{}
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#droplet-actions // See: https://developers.digitalocean.com/documentation/v2#droplet-actions
type DropletActionsService interface { type DropletActionsService interface {
Shutdown(int) (*Action, *Response, error) Shutdown(context.Context, int) (*Action, *Response, error)
ShutdownByTag(string) (*Action, *Response, error) ShutdownByTag(context.Context, string) (*Action, *Response, error)
PowerOff(int) (*Action, *Response, error) PowerOff(context.Context, int) (*Action, *Response, error)
PowerOffByTag(string) (*Action, *Response, error) PowerOffByTag(context.Context, string) (*Action, *Response, error)
PowerOn(int) (*Action, *Response, error) PowerOn(context.Context, int) (*Action, *Response, error)
PowerOnByTag(string) (*Action, *Response, error) PowerOnByTag(context.Context, string) (*Action, *Response, error)
PowerCycle(int) (*Action, *Response, error) PowerCycle(context.Context, int) (*Action, *Response, error)
PowerCycleByTag(string) (*Action, *Response, error) PowerCycleByTag(context.Context, string) (*Action, *Response, error)
Reboot(int) (*Action, *Response, error) Reboot(context.Context, int) (*Action, *Response, error)
Restore(int, int) (*Action, *Response, error) Restore(context.Context, int, int) (*Action, *Response, error)
Resize(int, string, bool) (*Action, *Response, error) Resize(context.Context, int, string, bool) (*Action, *Response, error)
Rename(int, string) (*Action, *Response, error) Rename(context.Context, int, string) (*Action, *Response, error)
Snapshot(int, string) (*Action, *Response, error) Snapshot(context.Context, int, string) (*Action, *Response, error)
SnapshotByTag(string, string) (*Action, *Response, error) SnapshotByTag(context.Context, string, string) (*Action, *Response, error)
EnableBackups(int) (*Action, *Response, error) EnableBackups(context.Context, int) (*Action, *Response, error)
EnableBackupsByTag(string) (*Action, *Response, error) EnableBackupsByTag(context.Context, string) (*Action, *Response, error)
DisableBackups(int) (*Action, *Response, error) DisableBackups(context.Context, int) (*Action, *Response, error)
DisableBackupsByTag(string) (*Action, *Response, error) DisableBackupsByTag(context.Context, string) (*Action, *Response, error)
PasswordReset(int) (*Action, *Response, error) PasswordReset(context.Context, int) (*Action, *Response, error)
RebuildByImageID(int, int) (*Action, *Response, error) RebuildByImageID(context.Context, int, int) (*Action, *Response, error)
RebuildByImageSlug(int, string) (*Action, *Response, error) RebuildByImageSlug(context.Context, int, string) (*Action, *Response, error)
ChangeKernel(int, int) (*Action, *Response, error) ChangeKernel(context.Context, int, int) (*Action, *Response, error)
EnableIPv6(int) (*Action, *Response, error) EnableIPv6(context.Context, int) (*Action, *Response, error)
EnableIPv6ByTag(string) (*Action, *Response, error) EnableIPv6ByTag(context.Context, string) (*Action, *Response, error)
EnablePrivateNetworking(int) (*Action, *Response, error) EnablePrivateNetworking(context.Context, int) (*Action, *Response, error)
EnablePrivateNetworkingByTag(string) (*Action, *Response, error) EnablePrivateNetworkingByTag(context.Context, string) (*Action, *Response, error)
Upgrade(int) (*Action, *Response, error) Upgrade(context.Context, int) (*Action, *Response, error)
Get(int, int) (*Action, *Response, error) Get(context.Context, int, int) (*Action, *Response, error)
GetByURI(string) (*Action, *Response, error) GetByURI(context.Context, string) (*Action, *Response, error)
} }
// DropletActionsServiceOp handles communication with the Droplet action related // DropletActionsServiceOp handles communication with the Droplet action related
@ -52,189 +54,189 @@ type DropletActionsServiceOp struct {
var _ DropletActionsService = &DropletActionsServiceOp{} var _ DropletActionsService = &DropletActionsServiceOp{}
// Shutdown a Droplet // Shutdown a Droplet
func (s *DropletActionsServiceOp) Shutdown(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) Shutdown(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "shutdown"} request := &ActionRequest{"type": "shutdown"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// ShutdownByTag shuts down Droplets matched by a Tag. // ShutdownByTag shuts down Droplets matched by a Tag.
func (s *DropletActionsServiceOp) ShutdownByTag(tag string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) ShutdownByTag(ctx context.Context, tag string) (*Action, *Response, error) {
request := &ActionRequest{"type": "shutdown"} request := &ActionRequest{"type": "shutdown"}
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// PowerOff a Droplet // PowerOff a Droplet
func (s *DropletActionsServiceOp) PowerOff(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) PowerOff(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "power_off"} request := &ActionRequest{"type": "power_off"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// PowerOffByTag powers off Droplets matched by a Tag. // PowerOffByTag powers off Droplets matched by a Tag.
func (s *DropletActionsServiceOp) PowerOffByTag(tag string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) PowerOffByTag(ctx context.Context, tag string) (*Action, *Response, error) {
request := &ActionRequest{"type": "power_off"} request := &ActionRequest{"type": "power_off"}
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// PowerOn a Droplet // PowerOn a Droplet
func (s *DropletActionsServiceOp) PowerOn(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) PowerOn(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "power_on"} request := &ActionRequest{"type": "power_on"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// PowerOnByTag powers on Droplets matched by a Tag. // PowerOnByTag powers on Droplets matched by a Tag.
func (s *DropletActionsServiceOp) PowerOnByTag(tag string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) PowerOnByTag(ctx context.Context, tag string) (*Action, *Response, error) {
request := &ActionRequest{"type": "power_on"} request := &ActionRequest{"type": "power_on"}
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// PowerCycle a Droplet // PowerCycle a Droplet
func (s *DropletActionsServiceOp) PowerCycle(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) PowerCycle(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "power_cycle"} request := &ActionRequest{"type": "power_cycle"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// PowerCycleByTag power cycles Droplets matched by a Tag. // PowerCycleByTag power cycles Droplets matched by a Tag.
func (s *DropletActionsServiceOp) PowerCycleByTag(tag string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) PowerCycleByTag(ctx context.Context, tag string) (*Action, *Response, error) {
request := &ActionRequest{"type": "power_cycle"} request := &ActionRequest{"type": "power_cycle"}
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// Reboot a Droplet // Reboot a Droplet
func (s *DropletActionsServiceOp) Reboot(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) Reboot(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "reboot"} request := &ActionRequest{"type": "reboot"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// Restore an image to a Droplet // Restore an image to a Droplet
func (s *DropletActionsServiceOp) Restore(id, imageID int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) Restore(ctx context.Context, id, imageID int) (*Action, *Response, error) {
requestType := "restore" requestType := "restore"
request := &ActionRequest{ request := &ActionRequest{
"type": requestType, "type": requestType,
"image": float64(imageID), "image": float64(imageID),
} }
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// Resize a Droplet // Resize a Droplet
func (s *DropletActionsServiceOp) Resize(id int, sizeSlug string, resizeDisk bool) (*Action, *Response, error) { func (s *DropletActionsServiceOp) Resize(ctx context.Context, id int, sizeSlug string, resizeDisk bool) (*Action, *Response, error) {
requestType := "resize" requestType := "resize"
request := &ActionRequest{ request := &ActionRequest{
"type": requestType, "type": requestType,
"size": sizeSlug, "size": sizeSlug,
"disk": resizeDisk, "disk": resizeDisk,
} }
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// Rename a Droplet // Rename a Droplet
func (s *DropletActionsServiceOp) Rename(id int, name string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) Rename(ctx context.Context, id int, name string) (*Action, *Response, error) {
requestType := "rename" requestType := "rename"
request := &ActionRequest{ request := &ActionRequest{
"type": requestType, "type": requestType,
"name": name, "name": name,
} }
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// Snapshot a Droplet. // Snapshot a Droplet.
func (s *DropletActionsServiceOp) Snapshot(id int, name string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) Snapshot(ctx context.Context, id int, name string) (*Action, *Response, error) {
requestType := "snapshot" requestType := "snapshot"
request := &ActionRequest{ request := &ActionRequest{
"type": requestType, "type": requestType,
"name": name, "name": name,
} }
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// SnapshotByTag snapshots Droplets matched by a Tag. // SnapshotByTag snapshots Droplets matched by a Tag.
func (s *DropletActionsServiceOp) SnapshotByTag(tag string, name string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) SnapshotByTag(ctx context.Context, tag string, name string) (*Action, *Response, error) {
requestType := "snapshot" requestType := "snapshot"
request := &ActionRequest{ request := &ActionRequest{
"type": requestType, "type": requestType,
"name": name, "name": name,
} }
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// EnableBackups enables backups for a Droplet. // EnableBackups enables backups for a Droplet.
func (s *DropletActionsServiceOp) EnableBackups(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) EnableBackups(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "enable_backups"} request := &ActionRequest{"type": "enable_backups"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// EnableBackupsByTag enables backups for Droplets matched by a Tag. // EnableBackupsByTag enables backups for Droplets matched by a Tag.
func (s *DropletActionsServiceOp) EnableBackupsByTag(tag string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) EnableBackupsByTag(ctx context.Context, tag string) (*Action, *Response, error) {
request := &ActionRequest{"type": "enable_backups"} request := &ActionRequest{"type": "enable_backups"}
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// DisableBackups disables backups for a Droplet. // DisableBackups disables backups for a Droplet.
func (s *DropletActionsServiceOp) DisableBackups(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) DisableBackups(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "disable_backups"} request := &ActionRequest{"type": "disable_backups"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// DisableBackupsByTag disables backups for Droplet matched by a Tag. // DisableBackupsByTag disables backups for Droplet matched by a Tag.
func (s *DropletActionsServiceOp) DisableBackupsByTag(tag string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) DisableBackupsByTag(ctx context.Context, tag string) (*Action, *Response, error) {
request := &ActionRequest{"type": "disable_backups"} request := &ActionRequest{"type": "disable_backups"}
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// PasswordReset resets the password for a Droplet. // PasswordReset resets the password for a Droplet.
func (s *DropletActionsServiceOp) PasswordReset(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) PasswordReset(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "password_reset"} request := &ActionRequest{"type": "password_reset"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// RebuildByImageID rebuilds a Droplet from an image with a given id. // RebuildByImageID rebuilds a Droplet from an image with a given id.
func (s *DropletActionsServiceOp) RebuildByImageID(id, imageID int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) RebuildByImageID(ctx context.Context, id, imageID int) (*Action, *Response, error) {
request := &ActionRequest{"type": "rebuild", "image": imageID} request := &ActionRequest{"type": "rebuild", "image": imageID}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// RebuildByImageSlug rebuilds a Droplet from an Image matched by a given Slug. // RebuildByImageSlug rebuilds a Droplet from an Image matched by a given Slug.
func (s *DropletActionsServiceOp) RebuildByImageSlug(id int, slug string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) RebuildByImageSlug(ctx context.Context, id int, slug string) (*Action, *Response, error) {
request := &ActionRequest{"type": "rebuild", "image": slug} request := &ActionRequest{"type": "rebuild", "image": slug}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// ChangeKernel changes the kernel for a Droplet. // ChangeKernel changes the kernel for a Droplet.
func (s *DropletActionsServiceOp) ChangeKernel(id, kernelID int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) ChangeKernel(ctx context.Context, id, kernelID int) (*Action, *Response, error) {
request := &ActionRequest{"type": "change_kernel", "kernel": kernelID} request := &ActionRequest{"type": "change_kernel", "kernel": kernelID}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// EnableIPv6 enables IPv6 for a Droplet. // EnableIPv6 enables IPv6 for a Droplet.
func (s *DropletActionsServiceOp) EnableIPv6(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) EnableIPv6(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "enable_ipv6"} request := &ActionRequest{"type": "enable_ipv6"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// EnableIPv6ByTag enables IPv6 for Droplets matched by a Tag. // EnableIPv6ByTag enables IPv6 for Droplets matched by a Tag.
func (s *DropletActionsServiceOp) EnableIPv6ByTag(tag string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) EnableIPv6ByTag(ctx context.Context, tag string) (*Action, *Response, error) {
request := &ActionRequest{"type": "enable_ipv6"} request := &ActionRequest{"type": "enable_ipv6"}
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// EnablePrivateNetworking enables private networking for a Droplet. // EnablePrivateNetworking enables private networking for a Droplet.
func (s *DropletActionsServiceOp) EnablePrivateNetworking(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) EnablePrivateNetworking(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "enable_private_networking"} request := &ActionRequest{"type": "enable_private_networking"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
// EnablePrivateNetworkingByTag enables private networking for Droplets matched by a Tag. // EnablePrivateNetworkingByTag enables private networking for Droplets matched by a Tag.
func (s *DropletActionsServiceOp) EnablePrivateNetworkingByTag(tag string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) EnablePrivateNetworkingByTag(ctx context.Context, tag string) (*Action, *Response, error) {
request := &ActionRequest{"type": "enable_private_networking"} request := &ActionRequest{"type": "enable_private_networking"}
return s.doActionByTag(tag, request) return s.doActionByTag(ctx, tag, request)
} }
// Upgrade a Droplet. // Upgrade a Droplet.
func (s *DropletActionsServiceOp) Upgrade(id int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) Upgrade(ctx context.Context, id int) (*Action, *Response, error) {
request := &ActionRequest{"type": "upgrade"} request := &ActionRequest{"type": "upgrade"}
return s.doAction(id, request) return s.doAction(ctx, id, request)
} }
func (s *DropletActionsServiceOp) doAction(id int, request *ActionRequest) (*Action, *Response, error) { func (s *DropletActionsServiceOp) doAction(ctx context.Context, id int, request *ActionRequest) (*Action, *Response, error) {
if id < 1 { if id < 1 {
return nil, nil, NewArgError("id", "cannot be less than 1") return nil, nil, NewArgError("id", "cannot be less than 1")
} }
@ -245,13 +247,13 @@ func (s *DropletActionsServiceOp) doAction(id int, request *ActionRequest) (*Act
path := dropletActionPath(id) path := dropletActionPath(id)
req, err := s.client.NewRequest("POST", path, request) req, err := s.client.NewRequest(ctx, "POST", path, request)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -259,7 +261,7 @@ func (s *DropletActionsServiceOp) doAction(id int, request *ActionRequest) (*Act
return root.Event, resp, err return root.Event, resp, err
} }
func (s *DropletActionsServiceOp) doActionByTag(tag string, request *ActionRequest) (*Action, *Response, error) { func (s *DropletActionsServiceOp) doActionByTag(ctx context.Context, tag string, request *ActionRequest) (*Action, *Response, error) {
if tag == "" { if tag == "" {
return nil, nil, NewArgError("tag", "cannot be empty") return nil, nil, NewArgError("tag", "cannot be empty")
} }
@ -270,13 +272,13 @@ func (s *DropletActionsServiceOp) doActionByTag(tag string, request *ActionReque
path := dropletActionPathByTag(tag) path := dropletActionPathByTag(tag)
req, err := s.client.NewRequest("POST", path, request) req, err := s.client.NewRequest(ctx, "POST", path, request)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -285,7 +287,7 @@ func (s *DropletActionsServiceOp) doActionByTag(tag string, request *ActionReque
} }
// Get an action for a particular Droplet by id. // Get an action for a particular Droplet by id.
func (s *DropletActionsServiceOp) Get(dropletID, actionID int) (*Action, *Response, error) { func (s *DropletActionsServiceOp) Get(ctx context.Context, dropletID, actionID int) (*Action, *Response, error) {
if dropletID < 1 { if dropletID < 1 {
return nil, nil, NewArgError("dropletID", "cannot be less than 1") return nil, nil, NewArgError("dropletID", "cannot be less than 1")
} }
@ -295,28 +297,28 @@ func (s *DropletActionsServiceOp) Get(dropletID, actionID int) (*Action, *Respon
} }
path := fmt.Sprintf("%s/%d", dropletActionPath(dropletID), actionID) path := fmt.Sprintf("%s/%d", dropletActionPath(dropletID), actionID)
return s.get(path) return s.get(ctx, path)
} }
// GetByURI gets an action for a particular Droplet by id. // GetByURI gets an action for a particular Droplet by id.
func (s *DropletActionsServiceOp) GetByURI(rawurl string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) GetByURI(ctx context.Context, rawurl string) (*Action, *Response, error) {
u, err := url.Parse(rawurl) u, err := url.Parse(rawurl)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return s.get(u.Path) return s.get(ctx, u.Path)
} }
func (s *DropletActionsServiceOp) get(path string) (*Action, *Response, error) { func (s *DropletActionsServiceOp) get(ctx context.Context, path string) (*Action, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -4,6 +4,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/digitalocean/godo/context"
) )
const dropletBasePath = "v2/droplets" const dropletBasePath = "v2/droplets"
@ -14,18 +16,18 @@ var errNoNetworks = errors.New("no networks have been defined")
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#droplets // See: https://developers.digitalocean.com/documentation/v2#droplets
type DropletsService interface { type DropletsService interface {
List(*ListOptions) ([]Droplet, *Response, error) List(context.Context, *ListOptions) ([]Droplet, *Response, error)
ListByTag(string, *ListOptions) ([]Droplet, *Response, error) ListByTag(context.Context, string, *ListOptions) ([]Droplet, *Response, error)
Get(int) (*Droplet, *Response, error) Get(context.Context, int) (*Droplet, *Response, error)
Create(*DropletCreateRequest) (*Droplet, *Response, error) Create(context.Context, *DropletCreateRequest) (*Droplet, *Response, error)
CreateMultiple(*DropletMultiCreateRequest) ([]Droplet, *Response, error) CreateMultiple(context.Context, *DropletMultiCreateRequest) ([]Droplet, *Response, error)
Delete(int) (*Response, error) Delete(context.Context, int) (*Response, error)
DeleteByTag(string) (*Response, error) DeleteByTag(context.Context, string) (*Response, error)
Kernels(int, *ListOptions) ([]Kernel, *Response, error) Kernels(context.Context, int, *ListOptions) ([]Kernel, *Response, error)
Snapshots(int, *ListOptions) ([]Image, *Response, error) Snapshots(context.Context, int, *ListOptions) ([]Image, *Response, error)
Backups(int, *ListOptions) ([]Image, *Response, error) Backups(context.Context, int, *ListOptions) ([]Image, *Response, error)
Actions(int, *ListOptions) ([]Action, *Response, error) Actions(context.Context, int, *ListOptions) ([]Action, *Response, error)
Neighbors(int) ([]Droplet, *Response, error) Neighbors(context.Context, int) ([]Droplet, *Response, error)
} }
// DropletsServiceOp handles communication with the Droplet related methods of the // DropletsServiceOp handles communication with the Droplet related methods of the
@ -90,15 +92,15 @@ func (d *Droplet) PrivateIPv4() (string, error) {
return "", nil return "", nil
} }
// PublicIPv6 returns the private IPv6 address for the Droplet. // PublicIPv6 returns the public IPv6 address for the Droplet.
func (d *Droplet) PublicIPv6() (string, error) { func (d *Droplet) PublicIPv6() (string, error) {
if d.Networks == nil { if d.Networks == nil {
return "", errNoNetworks return "", errNoNetworks
} }
for _, v4 := range d.Networks.V6 { for _, v6 := range d.Networks.V6 {
if v4.Type == "public" { if v6.Type == "public" {
return v4.IPAddress, nil return v6.IPAddress, nil
} }
} }
@ -272,14 +274,14 @@ func (n NetworkV6) String() string {
} }
// Performs a list request given a path. // Performs a list request given a path.
func (s *DropletsServiceOp) list(path string) ([]Droplet, *Response, error) { func (s *DropletsServiceOp) list(ctx context.Context, path string) ([]Droplet, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(dropletsRoot) root := new(dropletsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -291,42 +293,42 @@ func (s *DropletsServiceOp) list(path string) ([]Droplet, *Response, error) {
} }
// List all Droplets. // List all Droplets.
func (s *DropletsServiceOp) List(opt *ListOptions) ([]Droplet, *Response, error) { func (s *DropletsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Droplet, *Response, error) {
path := dropletBasePath path := dropletBasePath
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return s.list(path) return s.list(ctx, path)
} }
// ListByTag lists all Droplets matched by a Tag. // ListByTag lists all Droplets matched by a Tag.
func (s *DropletsServiceOp) ListByTag(tag string, opt *ListOptions) ([]Droplet, *Response, error) { func (s *DropletsServiceOp) ListByTag(ctx context.Context, tag string, opt *ListOptions) ([]Droplet, *Response, error) {
path := fmt.Sprintf("%s?tag_name=%s", dropletBasePath, tag) path := fmt.Sprintf("%s?tag_name=%s", dropletBasePath, tag)
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return s.list(path) return s.list(ctx, path)
} }
// Get individual Droplet. // Get individual Droplet.
func (s *DropletsServiceOp) Get(dropletID int) (*Droplet, *Response, error) { func (s *DropletsServiceOp) Get(ctx context.Context, dropletID int) (*Droplet, *Response, error) {
if dropletID < 1 { if dropletID < 1 {
return nil, nil, NewArgError("dropletID", "cannot be less than 1") return nil, nil, NewArgError("dropletID", "cannot be less than 1")
} }
path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID) path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID)
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(dropletRoot) root := new(dropletRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -335,20 +337,20 @@ func (s *DropletsServiceOp) Get(dropletID int) (*Droplet, *Response, error) {
} }
// Create Droplet // Create Droplet
func (s *DropletsServiceOp) Create(createRequest *DropletCreateRequest) (*Droplet, *Response, error) { func (s *DropletsServiceOp) Create(ctx context.Context, createRequest *DropletCreateRequest) (*Droplet, *Response, error) {
if createRequest == nil { if createRequest == nil {
return nil, nil, NewArgError("createRequest", "cannot be nil") return nil, nil, NewArgError("createRequest", "cannot be nil")
} }
path := dropletBasePath path := dropletBasePath
req, err := s.client.NewRequest("POST", path, createRequest) req, err := s.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(dropletRoot) root := new(dropletRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -360,20 +362,20 @@ func (s *DropletsServiceOp) Create(createRequest *DropletCreateRequest) (*Drople
} }
// CreateMultiple creates multiple Droplets. // CreateMultiple creates multiple Droplets.
func (s *DropletsServiceOp) CreateMultiple(createRequest *DropletMultiCreateRequest) ([]Droplet, *Response, error) { func (s *DropletsServiceOp) CreateMultiple(ctx context.Context, createRequest *DropletMultiCreateRequest) ([]Droplet, *Response, error) {
if createRequest == nil { if createRequest == nil {
return nil, nil, NewArgError("createRequest", "cannot be nil") return nil, nil, NewArgError("createRequest", "cannot be nil")
} }
path := dropletBasePath path := dropletBasePath
req, err := s.client.NewRequest("POST", path, createRequest) req, err := s.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(dropletsRoot) root := new(dropletsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -385,41 +387,41 @@ func (s *DropletsServiceOp) CreateMultiple(createRequest *DropletMultiCreateRequ
} }
// Performs a delete request given a path // Performs a delete request given a path
func (s *DropletsServiceOp) delete(path string) (*Response, error) { func (s *DropletsServiceOp) delete(ctx context.Context, path string) (*Response, error) {
req, err := s.client.NewRequest("DELETE", path, nil) req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }
// Delete Droplet. // Delete Droplet.
func (s *DropletsServiceOp) Delete(dropletID int) (*Response, error) { func (s *DropletsServiceOp) Delete(ctx context.Context, dropletID int) (*Response, error) {
if dropletID < 1 { if dropletID < 1 {
return nil, NewArgError("dropletID", "cannot be less than 1") return nil, NewArgError("dropletID", "cannot be less than 1")
} }
path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID) path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID)
return s.delete(path) return s.delete(ctx, path)
} }
// DeleteByTag deletes Droplets matched by a Tag. // DeleteByTag deletes Droplets matched by a Tag.
func (s *DropletsServiceOp) DeleteByTag(tag string) (*Response, error) { func (s *DropletsServiceOp) DeleteByTag(ctx context.Context, tag string) (*Response, error) {
if tag == "" { if tag == "" {
return nil, NewArgError("tag", "cannot be empty") return nil, NewArgError("tag", "cannot be empty")
} }
path := fmt.Sprintf("%s?tag_name=%s", dropletBasePath, tag) path := fmt.Sprintf("%s?tag_name=%s", dropletBasePath, tag)
return s.delete(path) return s.delete(ctx, path)
} }
// Kernels lists kernels available for a Droplet. // Kernels lists kernels available for a Droplet.
func (s *DropletsServiceOp) Kernels(dropletID int, opt *ListOptions) ([]Kernel, *Response, error) { func (s *DropletsServiceOp) Kernels(ctx context.Context, dropletID int, opt *ListOptions) ([]Kernel, *Response, error) {
if dropletID < 1 { if dropletID < 1 {
return nil, nil, NewArgError("dropletID", "cannot be less than 1") return nil, nil, NewArgError("dropletID", "cannot be less than 1")
} }
@ -430,13 +432,13 @@ func (s *DropletsServiceOp) Kernels(dropletID int, opt *ListOptions) ([]Kernel,
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(kernelsRoot) root := new(kernelsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if l := root.Links; l != nil { if l := root.Links; l != nil {
resp.Links = l resp.Links = l
} }
@ -445,7 +447,7 @@ func (s *DropletsServiceOp) Kernels(dropletID int, opt *ListOptions) ([]Kernel,
} }
// Actions lists the actions for a Droplet. // Actions lists the actions for a Droplet.
func (s *DropletsServiceOp) Actions(dropletID int, opt *ListOptions) ([]Action, *Response, error) { func (s *DropletsServiceOp) Actions(ctx context.Context, dropletID int, opt *ListOptions) ([]Action, *Response, error) {
if dropletID < 1 { if dropletID < 1 {
return nil, nil, NewArgError("dropletID", "cannot be less than 1") return nil, nil, NewArgError("dropletID", "cannot be less than 1")
} }
@ -456,13 +458,13 @@ func (s *DropletsServiceOp) Actions(dropletID int, opt *ListOptions) ([]Action,
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionsRoot) root := new(actionsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -474,7 +476,7 @@ func (s *DropletsServiceOp) Actions(dropletID int, opt *ListOptions) ([]Action,
} }
// Backups lists the backups for a Droplet. // Backups lists the backups for a Droplet.
func (s *DropletsServiceOp) Backups(dropletID int, opt *ListOptions) ([]Image, *Response, error) { func (s *DropletsServiceOp) Backups(ctx context.Context, dropletID int, opt *ListOptions) ([]Image, *Response, error) {
if dropletID < 1 { if dropletID < 1 {
return nil, nil, NewArgError("dropletID", "cannot be less than 1") return nil, nil, NewArgError("dropletID", "cannot be less than 1")
} }
@ -485,13 +487,13 @@ func (s *DropletsServiceOp) Backups(dropletID int, opt *ListOptions) ([]Image, *
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(backupsRoot) root := new(backupsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -503,7 +505,7 @@ func (s *DropletsServiceOp) Backups(dropletID int, opt *ListOptions) ([]Image, *
} }
// Snapshots lists the snapshots available for a Droplet. // Snapshots lists the snapshots available for a Droplet.
func (s *DropletsServiceOp) Snapshots(dropletID int, opt *ListOptions) ([]Image, *Response, error) { func (s *DropletsServiceOp) Snapshots(ctx context.Context, dropletID int, opt *ListOptions) ([]Image, *Response, error) {
if dropletID < 1 { if dropletID < 1 {
return nil, nil, NewArgError("dropletID", "cannot be less than 1") return nil, nil, NewArgError("dropletID", "cannot be less than 1")
} }
@ -514,13 +516,13 @@ func (s *DropletsServiceOp) Snapshots(dropletID int, opt *ListOptions) ([]Image,
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(dropletSnapshotsRoot) root := new(dropletSnapshotsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -532,20 +534,20 @@ func (s *DropletsServiceOp) Snapshots(dropletID int, opt *ListOptions) ([]Image,
} }
// Neighbors lists the neighbors for a Droplet. // Neighbors lists the neighbors for a Droplet.
func (s *DropletsServiceOp) Neighbors(dropletID int) ([]Droplet, *Response, error) { func (s *DropletsServiceOp) Neighbors(ctx context.Context, dropletID int) ([]Droplet, *Response, error) {
if dropletID < 1 { if dropletID < 1 {
return nil, nil, NewArgError("dropletID", "cannot be less than 1") return nil, nil, NewArgError("dropletID", "cannot be less than 1")
} }
path := fmt.Sprintf("%s/%d/neighbors", dropletBasePath, dropletID) path := fmt.Sprintf("%s/%d/neighbors", dropletBasePath, dropletID)
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(dropletsRoot) root := new(dropletsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -553,8 +555,8 @@ func (s *DropletsServiceOp) Neighbors(dropletID int) ([]Droplet, *Response, erro
return root.Droplets, resp, err return root.Droplets, resp, err
} }
func (s *DropletsServiceOp) dropletActionStatus(uri string) (string, error) { func (s *DropletsServiceOp) dropletActionStatus(ctx context.Context, uri string) (string, error) {
action, _, err := s.client.DropletActions.GetByURI(uri) action, _, err := s.client.DropletActions.GetByURI(ctx, uri)
if err != nil { if err != nil {
return "", err return "", err

View File

@ -1,6 +1,10 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
const floatingBasePath = "v2/floating_ips" const floatingBasePath = "v2/floating_ips"
@ -8,10 +12,10 @@ const floatingBasePath = "v2/floating_ips"
// endpoints of the Digital Ocean API. // endpoints of the Digital Ocean API.
// See: https://developers.digitalocean.com/documentation/v2#floating-ips // See: https://developers.digitalocean.com/documentation/v2#floating-ips
type FloatingIPsService interface { type FloatingIPsService interface {
List(*ListOptions) ([]FloatingIP, *Response, error) List(context.Context, *ListOptions) ([]FloatingIP, *Response, error)
Get(string) (*FloatingIP, *Response, error) Get(context.Context, string) (*FloatingIP, *Response, error)
Create(*FloatingIPCreateRequest) (*FloatingIP, *Response, error) Create(context.Context, *FloatingIPCreateRequest) (*FloatingIP, *Response, error)
Delete(string) (*Response, error) Delete(context.Context, string) (*Response, error)
} }
// FloatingIPsServiceOp handles communication with the floating IPs related methods of the // FloatingIPsServiceOp handles communication with the floating IPs related methods of the
@ -52,20 +56,20 @@ type FloatingIPCreateRequest struct {
} }
// List all floating IPs. // List all floating IPs.
func (f *FloatingIPsServiceOp) List(opt *ListOptions) ([]FloatingIP, *Response, error) { func (f *FloatingIPsServiceOp) List(ctx context.Context, opt *ListOptions) ([]FloatingIP, *Response, error) {
path := floatingBasePath path := floatingBasePath
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req, err := f.client.NewRequest("GET", path, nil) req, err := f.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(floatingIPsRoot) root := new(floatingIPsRoot)
resp, err := f.client.Do(req, root) resp, err := f.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -77,16 +81,16 @@ func (f *FloatingIPsServiceOp) List(opt *ListOptions) ([]FloatingIP, *Response,
} }
// Get an individual floating IP. // Get an individual floating IP.
func (f *FloatingIPsServiceOp) Get(ip string) (*FloatingIP, *Response, error) { func (f *FloatingIPsServiceOp) Get(ctx context.Context, ip string) (*FloatingIP, *Response, error) {
path := fmt.Sprintf("%s/%s", floatingBasePath, ip) path := fmt.Sprintf("%s/%s", floatingBasePath, ip)
req, err := f.client.NewRequest("GET", path, nil) req, err := f.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(floatingIPRoot) root := new(floatingIPRoot)
resp, err := f.client.Do(req, root) resp, err := f.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -96,16 +100,16 @@ func (f *FloatingIPsServiceOp) Get(ip string) (*FloatingIP, *Response, error) {
// Create a floating IP. If the DropletID field of the request is not empty, // Create a floating IP. If the DropletID field of the request is not empty,
// the floating IP will also be assigned to the droplet. // the floating IP will also be assigned to the droplet.
func (f *FloatingIPsServiceOp) Create(createRequest *FloatingIPCreateRequest) (*FloatingIP, *Response, error) { func (f *FloatingIPsServiceOp) Create(ctx context.Context, createRequest *FloatingIPCreateRequest) (*FloatingIP, *Response, error) {
path := floatingBasePath path := floatingBasePath
req, err := f.client.NewRequest("POST", path, createRequest) req, err := f.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(floatingIPRoot) root := new(floatingIPRoot)
resp, err := f.client.Do(req, root) resp, err := f.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -117,15 +121,15 @@ func (f *FloatingIPsServiceOp) Create(createRequest *FloatingIPCreateRequest) (*
} }
// Delete a floating IP. // Delete a floating IP.
func (f *FloatingIPsServiceOp) Delete(ip string) (*Response, error) { func (f *FloatingIPsServiceOp) Delete(ctx context.Context, ip string) (*Response, error) {
path := fmt.Sprintf("%s/%s", floatingBasePath, ip) path := fmt.Sprintf("%s/%s", floatingBasePath, ip)
req, err := f.client.NewRequest("DELETE", path, nil) req, err := f.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := f.client.Do(req, nil) resp, err := f.client.Do(ctx, req, nil)
return resp, err return resp, err
} }

View File

@ -1,15 +1,19 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
// FloatingIPActionsService is an interface for interfacing with the // FloatingIPActionsService is an interface for interfacing with the
// floating IPs actions endpoints of the Digital Ocean API. // floating IPs actions endpoints of the Digital Ocean API.
// See: https://developers.digitalocean.com/documentation/v2#floating-ips-action // See: https://developers.digitalocean.com/documentation/v2#floating-ips-action
type FloatingIPActionsService interface { type FloatingIPActionsService interface {
Assign(ip string, dropletID int) (*Action, *Response, error) Assign(ctx context.Context, ip string, dropletID int) (*Action, *Response, error)
Unassign(ip string) (*Action, *Response, error) Unassign(ctx context.Context, ip string) (*Action, *Response, error)
Get(ip string, actionID int) (*Action, *Response, error) Get(ctx context.Context, ip string, actionID int) (*Action, *Response, error)
List(ip string, opt *ListOptions) ([]Action, *Response, error) List(ctx context.Context, ip string, opt *ListOptions) ([]Action, *Response, error)
} }
// FloatingIPActionsServiceOp handles communication with the floating IPs // FloatingIPActionsServiceOp handles communication with the floating IPs
@ -19,47 +23,47 @@ type FloatingIPActionsServiceOp struct {
} }
// Assign a floating IP to a droplet. // Assign a floating IP to a droplet.
func (s *FloatingIPActionsServiceOp) Assign(ip string, dropletID int) (*Action, *Response, error) { func (s *FloatingIPActionsServiceOp) Assign(ctx context.Context, ip string, dropletID int) (*Action, *Response, error) {
request := &ActionRequest{ request := &ActionRequest{
"type": "assign", "type": "assign",
"droplet_id": dropletID, "droplet_id": dropletID,
} }
return s.doAction(ip, request) return s.doAction(ctx, ip, request)
} }
// Unassign a floating IP from the droplet it is currently assigned to. // Unassign a floating IP from the droplet it is currently assigned to.
func (s *FloatingIPActionsServiceOp) Unassign(ip string) (*Action, *Response, error) { func (s *FloatingIPActionsServiceOp) Unassign(ctx context.Context, ip string) (*Action, *Response, error) {
request := &ActionRequest{"type": "unassign"} request := &ActionRequest{"type": "unassign"}
return s.doAction(ip, request) return s.doAction(ctx, ip, request)
} }
// Get an action for a particular floating IP by id. // Get an action for a particular floating IP by id.
func (s *FloatingIPActionsServiceOp) Get(ip string, actionID int) (*Action, *Response, error) { func (s *FloatingIPActionsServiceOp) Get(ctx context.Context, ip string, actionID int) (*Action, *Response, error) {
path := fmt.Sprintf("%s/%d", floatingIPActionPath(ip), actionID) path := fmt.Sprintf("%s/%d", floatingIPActionPath(ip), actionID)
return s.get(path) return s.get(ctx, path)
} }
// List the actions for a particular floating IP. // List the actions for a particular floating IP.
func (s *FloatingIPActionsServiceOp) List(ip string, opt *ListOptions) ([]Action, *Response, error) { func (s *FloatingIPActionsServiceOp) List(ctx context.Context, ip string, opt *ListOptions) ([]Action, *Response, error) {
path := floatingIPActionPath(ip) path := floatingIPActionPath(ip)
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return s.list(path) return s.list(ctx, path)
} }
func (s *FloatingIPActionsServiceOp) doAction(ip string, request *ActionRequest) (*Action, *Response, error) { func (s *FloatingIPActionsServiceOp) doAction(ctx context.Context, ip string, request *ActionRequest) (*Action, *Response, error) {
path := floatingIPActionPath(ip) path := floatingIPActionPath(ip)
req, err := s.client.NewRequest("POST", path, request) req, err := s.client.NewRequest(ctx, "POST", path, request)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -67,14 +71,14 @@ func (s *FloatingIPActionsServiceOp) doAction(ip string, request *ActionRequest)
return root.Event, resp, err return root.Event, resp, err
} }
func (s *FloatingIPActionsServiceOp) get(path string) (*Action, *Response, error) { func (s *FloatingIPActionsServiceOp) get(ctx context.Context, path string) (*Action, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -82,14 +86,14 @@ func (s *FloatingIPActionsServiceOp) get(path string) (*Action, *Response, error
return root.Event, resp, err return root.Event, resp, err
} }
func (s *FloatingIPActionsServiceOp) list(path string) ([]Action, *Response, error) { func (s *FloatingIPActionsServiceOp) list(ctx context.Context, path string) ([]Action, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionsRoot) root := new(actionsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -14,10 +14,12 @@ import (
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"
headerLink "github.com/tent/http-link-go" headerLink "github.com/tent/http-link-go"
"github.com/digitalocean/godo/context"
) )
const ( const (
libraryVersion = "0.1.0" libraryVersion = "1.0.0"
defaultBaseURL = "https://api.digitalocean.com/" defaultBaseURL = "https://api.digitalocean.com/"
userAgent = "godo/" + libraryVersion userAgent = "godo/" + libraryVersion
mediaType = "application/json" mediaType = "application/json"
@ -60,6 +62,7 @@ type Client struct {
StorageActions StorageActionsService StorageActions StorageActionsService
Tags TagsService Tags TagsService
LoadBalancers LoadBalancersService LoadBalancers LoadBalancersService
Certificates CertificatesService
// Optional function called after every successful request made to the DO APIs // Optional function called after every successful request made to the DO APIs
onRequestCompleted RequestCompletionCallback onRequestCompleted RequestCompletionCallback
@ -169,6 +172,7 @@ func NewClient(httpClient *http.Client) *Client {
c.StorageActions = &StorageActionsServiceOp{client: c} c.StorageActions = &StorageActionsServiceOp{client: c}
c.Tags = &TagsServiceOp{client: c} c.Tags = &TagsServiceOp{client: c}
c.LoadBalancers = &LoadBalancersServiceOp{client: c} c.LoadBalancers = &LoadBalancersServiceOp{client: c}
c.Certificates = &CertificatesServiceOp{client: c}
return c return c
} }
@ -212,7 +216,7 @@ func SetUserAgent(ua string) ClientOpt {
// NewRequest creates an API request. A relative URL can be provided in urlStr, which will be resolved to the // NewRequest creates an API request. A relative URL can be provided in urlStr, which will be resolved to the
// BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the // BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the
// value pointed to by body is JSON encoded and included in as the request body. // value pointed to by body is JSON encoded and included in as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) { func (c *Client) NewRequest(ctx context.Context, method, urlStr string, body interface{}) (*http.Request, error) {
rel, err := url.Parse(urlStr) rel, err := url.Parse(urlStr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -289,8 +293,8 @@ func (r *Response) populateRate() {
// Do sends an API request and returns the API response. The API response is JSON decoded and stored in the value // Do sends an API request and returns the API response. The API response is JSON decoded and stored in the value
// pointed to by v, or returned as an error if an API error has occurred. If v implements the io.Writer interface, // pointed to by v, or returned as an error if an API error has occurred. If v implements the io.Writer interface,
// the raw response will be written to v, without attempting to decode it. // the raw response will be written to v, without attempting to decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
resp, err := c.client.Do(req) resp, err := context.DoRequestWithClient(ctx, c.client, req)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,13 +1,18 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
// ImageActionsService is an interface for interfacing with the image actions // ImageActionsService is an interface for interfacing with the image actions
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#image-actions // See: https://developers.digitalocean.com/documentation/v2#image-actions
type ImageActionsService interface { type ImageActionsService interface {
Get(int, int) (*Action, *Response, error) Get(context.Context, int, int) (*Action, *Response, error)
Transfer(int, *ActionRequest) (*Action, *Response, error) Transfer(context.Context, int, *ActionRequest) (*Action, *Response, error)
Convert(context.Context, int) (*Action, *Response, error)
} }
// ImageActionsServiceOp handles communition with the image action related methods of the // ImageActionsServiceOp handles communition with the image action related methods of the
@ -19,7 +24,7 @@ type ImageActionsServiceOp struct {
var _ ImageActionsService = &ImageActionsServiceOp{} var _ ImageActionsService = &ImageActionsServiceOp{}
// Transfer an image // Transfer an image
func (i *ImageActionsServiceOp) Transfer(imageID int, transferRequest *ActionRequest) (*Action, *Response, error) { func (i *ImageActionsServiceOp) Transfer(ctx context.Context, imageID int, transferRequest *ActionRequest) (*Action, *Response, error) {
if imageID < 1 { if imageID < 1 {
return nil, nil, NewArgError("imageID", "cannot be less than 1") return nil, nil, NewArgError("imageID", "cannot be less than 1")
} }
@ -30,13 +35,39 @@ func (i *ImageActionsServiceOp) Transfer(imageID int, transferRequest *ActionReq
path := fmt.Sprintf("v2/images/%d/actions", imageID) path := fmt.Sprintf("v2/images/%d/actions", imageID)
req, err := i.client.NewRequest("POST", path, transferRequest) req, err := i.client.NewRequest(ctx, "POST", path, transferRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := i.client.Do(req, root) resp, err := i.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Event, resp, err
}
// Convert an image to a snapshot
func (i *ImageActionsServiceOp) Convert(ctx context.Context, imageID int) (*Action, *Response, error) {
if imageID < 1 {
return nil, nil, NewArgError("imageID", "cannont be less than 1")
}
path := fmt.Sprintf("v2/images/%d/actions", imageID)
convertRequest := &ActionRequest{
"type": "convert",
}
req, err := i.client.NewRequest(ctx, "POST", path, convertRequest)
if err != nil {
return nil, nil, err
}
root := new(actionRoot)
resp, err := i.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -45,7 +76,7 @@ func (i *ImageActionsServiceOp) Transfer(imageID int, transferRequest *ActionReq
} }
// Get an action for a particular image by id. // Get an action for a particular image by id.
func (i *ImageActionsServiceOp) Get(imageID, actionID int) (*Action, *Response, error) { func (i *ImageActionsServiceOp) Get(ctx context.Context, imageID, actionID int) (*Action, *Response, error) {
if imageID < 1 { if imageID < 1 {
return nil, nil, NewArgError("imageID", "cannot be less than 1") return nil, nil, NewArgError("imageID", "cannot be less than 1")
} }
@ -56,13 +87,13 @@ func (i *ImageActionsServiceOp) Get(imageID, actionID int) (*Action, *Response,
path := fmt.Sprintf("v2/images/%d/actions/%d", imageID, actionID) path := fmt.Sprintf("v2/images/%d/actions/%d", imageID, actionID)
req, err := i.client.NewRequest("GET", path, nil) req, err := i.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := i.client.Do(req, root) resp, err := i.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -1,6 +1,10 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
const imageBasePath = "v2/images" const imageBasePath = "v2/images"
@ -8,14 +12,14 @@ const imageBasePath = "v2/images"
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#images // See: https://developers.digitalocean.com/documentation/v2#images
type ImagesService interface { type ImagesService interface {
List(*ListOptions) ([]Image, *Response, error) List(context.Context, *ListOptions) ([]Image, *Response, error)
ListDistribution(opt *ListOptions) ([]Image, *Response, error) ListDistribution(ctx context.Context, opt *ListOptions) ([]Image, *Response, error)
ListApplication(opt *ListOptions) ([]Image, *Response, error) ListApplication(ctx context.Context, opt *ListOptions) ([]Image, *Response, error)
ListUser(opt *ListOptions) ([]Image, *Response, error) ListUser(ctx context.Context, opt *ListOptions) ([]Image, *Response, error)
GetByID(int) (*Image, *Response, error) GetByID(context.Context, int) (*Image, *Response, error)
GetBySlug(string) (*Image, *Response, error) GetBySlug(context.Context, string) (*Image, *Response, error)
Update(int, *ImageUpdateRequest) (*Image, *Response, error) Update(context.Context, int, *ImageUpdateRequest) (*Image, *Response, error)
Delete(int) (*Response, error) Delete(context.Context, int) (*Response, error)
} }
// ImagesServiceOp handles communication with the image related methods of the // ImagesServiceOp handles communication with the image related methods of the
@ -63,48 +67,48 @@ func (i Image) String() string {
} }
// List lists all the images available. // List lists all the images available.
func (s *ImagesServiceOp) List(opt *ListOptions) ([]Image, *Response, error) { func (s *ImagesServiceOp) List(ctx context.Context, opt *ListOptions) ([]Image, *Response, error) {
return s.list(opt, nil) return s.list(ctx, opt, nil)
} }
// ListDistribution lists all the distribution images. // ListDistribution lists all the distribution images.
func (s *ImagesServiceOp) ListDistribution(opt *ListOptions) ([]Image, *Response, error) { func (s *ImagesServiceOp) ListDistribution(ctx context.Context, opt *ListOptions) ([]Image, *Response, error) {
listOpt := listImageOptions{Type: "distribution"} listOpt := listImageOptions{Type: "distribution"}
return s.list(opt, &listOpt) return s.list(ctx, opt, &listOpt)
} }
// ListApplication lists all the application images. // ListApplication lists all the application images.
func (s *ImagesServiceOp) ListApplication(opt *ListOptions) ([]Image, *Response, error) { func (s *ImagesServiceOp) ListApplication(ctx context.Context, opt *ListOptions) ([]Image, *Response, error) {
listOpt := listImageOptions{Type: "application"} listOpt := listImageOptions{Type: "application"}
return s.list(opt, &listOpt) return s.list(ctx, opt, &listOpt)
} }
// ListUser lists all the user images. // ListUser lists all the user images.
func (s *ImagesServiceOp) ListUser(opt *ListOptions) ([]Image, *Response, error) { func (s *ImagesServiceOp) ListUser(ctx context.Context, opt *ListOptions) ([]Image, *Response, error) {
listOpt := listImageOptions{Private: true} listOpt := listImageOptions{Private: true}
return s.list(opt, &listOpt) return s.list(ctx, opt, &listOpt)
} }
// GetByID retrieves an image by id. // GetByID retrieves an image by id.
func (s *ImagesServiceOp) GetByID(imageID int) (*Image, *Response, error) { func (s *ImagesServiceOp) GetByID(ctx context.Context, imageID int) (*Image, *Response, error) {
if imageID < 1 { if imageID < 1 {
return nil, nil, NewArgError("imageID", "cannot be less than 1") return nil, nil, NewArgError("imageID", "cannot be less than 1")
} }
return s.get(interface{}(imageID)) return s.get(ctx, interface{}(imageID))
} }
// GetBySlug retrieves an image by slug. // GetBySlug retrieves an image by slug.
func (s *ImagesServiceOp) GetBySlug(slug string) (*Image, *Response, error) { func (s *ImagesServiceOp) GetBySlug(ctx context.Context, slug string) (*Image, *Response, error) {
if len(slug) < 1 { if len(slug) < 1 {
return nil, nil, NewArgError("slug", "cannot be blank") return nil, nil, NewArgError("slug", "cannot be blank")
} }
return s.get(interface{}(slug)) return s.get(ctx, interface{}(slug))
} }
// Update an image name. // Update an image name.
func (s *ImagesServiceOp) Update(imageID int, updateRequest *ImageUpdateRequest) (*Image, *Response, error) { func (s *ImagesServiceOp) Update(ctx context.Context, imageID int, updateRequest *ImageUpdateRequest) (*Image, *Response, error) {
if imageID < 1 { if imageID < 1 {
return nil, nil, NewArgError("imageID", "cannot be less than 1") return nil, nil, NewArgError("imageID", "cannot be less than 1")
} }
@ -114,13 +118,13 @@ func (s *ImagesServiceOp) Update(imageID int, updateRequest *ImageUpdateRequest)
} }
path := fmt.Sprintf("%s/%d", imageBasePath, imageID) path := fmt.Sprintf("%s/%d", imageBasePath, imageID)
req, err := s.client.NewRequest("PUT", path, updateRequest) req, err := s.client.NewRequest(ctx, "PUT", path, updateRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(imageRoot) root := new(imageRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -129,34 +133,34 @@ func (s *ImagesServiceOp) Update(imageID int, updateRequest *ImageUpdateRequest)
} }
// Delete an image. // Delete an image.
func (s *ImagesServiceOp) Delete(imageID int) (*Response, error) { func (s *ImagesServiceOp) Delete(ctx context.Context, imageID int) (*Response, error) {
if imageID < 1 { if imageID < 1 {
return nil, NewArgError("imageID", "cannot be less than 1") return nil, NewArgError("imageID", "cannot be less than 1")
} }
path := fmt.Sprintf("%s/%d", imageBasePath, imageID) path := fmt.Sprintf("%s/%d", imageBasePath, imageID)
req, err := s.client.NewRequest("DELETE", path, nil) req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }
// Helper method for getting an individual image // Helper method for getting an individual image
func (s *ImagesServiceOp) get(ID interface{}) (*Image, *Response, error) { func (s *ImagesServiceOp) get(ctx context.Context, ID interface{}) (*Image, *Response, error) {
path := fmt.Sprintf("%s/%v", imageBasePath, ID) path := fmt.Sprintf("%s/%v", imageBasePath, ID)
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(imageRoot) root := new(imageRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -165,7 +169,7 @@ func (s *ImagesServiceOp) get(ID interface{}) (*Image, *Response, error) {
} }
// Helper method for listing images // Helper method for listing images
func (s *ImagesServiceOp) list(opt *ListOptions, listOpt *listImageOptions) ([]Image, *Response, error) { func (s *ImagesServiceOp) list(ctx context.Context, opt *ListOptions, listOpt *listImageOptions) ([]Image, *Response, error) {
path := imageBasePath path := imageBasePath
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
@ -176,13 +180,13 @@ func (s *ImagesServiceOp) list(opt *ListOptions, listOpt *listImageOptions) ([]I
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(imagesRoot) root := new(imagesRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -1,6 +1,10 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
const keysBasePath = "v2/account/keys" const keysBasePath = "v2/account/keys"
@ -8,14 +12,14 @@ const keysBasePath = "v2/account/keys"
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#keys // See: https://developers.digitalocean.com/documentation/v2#keys
type KeysService interface { type KeysService interface {
List(*ListOptions) ([]Key, *Response, error) List(context.Context, *ListOptions) ([]Key, *Response, error)
GetByID(int) (*Key, *Response, error) GetByID(context.Context, int) (*Key, *Response, error)
GetByFingerprint(string) (*Key, *Response, error) GetByFingerprint(context.Context, string) (*Key, *Response, error)
Create(*KeyCreateRequest) (*Key, *Response, error) Create(context.Context, *KeyCreateRequest) (*Key, *Response, error)
UpdateByID(int, *KeyUpdateRequest) (*Key, *Response, error) UpdateByID(context.Context, int, *KeyUpdateRequest) (*Key, *Response, error)
UpdateByFingerprint(string, *KeyUpdateRequest) (*Key, *Response, error) UpdateByFingerprint(context.Context, string, *KeyUpdateRequest) (*Key, *Response, error)
DeleteByID(int) (*Response, error) DeleteByID(context.Context, int) (*Response, error)
DeleteByFingerprint(string) (*Response, error) DeleteByFingerprint(context.Context, string) (*Response, error)
} }
// KeysServiceOp handles communication with key related method of the // KeysServiceOp handles communication with key related method of the
@ -59,20 +63,20 @@ type KeyCreateRequest struct {
} }
// List all keys // List all keys
func (s *KeysServiceOp) List(opt *ListOptions) ([]Key, *Response, error) { func (s *KeysServiceOp) List(ctx context.Context, opt *ListOptions) ([]Key, *Response, error) {
path := keysBasePath path := keysBasePath
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(keysRoot) root := new(keysRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -84,14 +88,14 @@ func (s *KeysServiceOp) List(opt *ListOptions) ([]Key, *Response, error) {
} }
// Performs a get given a path // Performs a get given a path
func (s *KeysServiceOp) get(path string) (*Key, *Response, error) { func (s *KeysServiceOp) get(ctx context.Context, path string) (*Key, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(keyRoot) root := new(keyRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -100,38 +104,38 @@ func (s *KeysServiceOp) get(path string) (*Key, *Response, error) {
} }
// GetByID gets a Key by id // GetByID gets a Key by id
func (s *KeysServiceOp) GetByID(keyID int) (*Key, *Response, error) { func (s *KeysServiceOp) GetByID(ctx context.Context, keyID int) (*Key, *Response, error) {
if keyID < 1 { if keyID < 1 {
return nil, nil, NewArgError("keyID", "cannot be less than 1") return nil, nil, NewArgError("keyID", "cannot be less than 1")
} }
path := fmt.Sprintf("%s/%d", keysBasePath, keyID) path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
return s.get(path) return s.get(ctx, path)
} }
// GetByFingerprint gets a Key by by fingerprint // GetByFingerprint gets a Key by by fingerprint
func (s *KeysServiceOp) GetByFingerprint(fingerprint string) (*Key, *Response, error) { func (s *KeysServiceOp) GetByFingerprint(ctx context.Context, fingerprint string) (*Key, *Response, error) {
if len(fingerprint) < 1 { if len(fingerprint) < 1 {
return nil, nil, NewArgError("fingerprint", "cannot not be empty") return nil, nil, NewArgError("fingerprint", "cannot not be empty")
} }
path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint) path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint)
return s.get(path) return s.get(ctx, path)
} }
// Create a key using a KeyCreateRequest // Create a key using a KeyCreateRequest
func (s *KeysServiceOp) Create(createRequest *KeyCreateRequest) (*Key, *Response, error) { func (s *KeysServiceOp) Create(ctx context.Context, createRequest *KeyCreateRequest) (*Key, *Response, error) {
if createRequest == nil { if createRequest == nil {
return nil, nil, NewArgError("createRequest", "cannot be nil") return nil, nil, NewArgError("createRequest", "cannot be nil")
} }
req, err := s.client.NewRequest("POST", keysBasePath, createRequest) req, err := s.client.NewRequest(ctx, "POST", keysBasePath, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(keyRoot) root := new(keyRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -140,7 +144,7 @@ func (s *KeysServiceOp) Create(createRequest *KeyCreateRequest) (*Key, *Response
} }
// UpdateByID updates a key name by ID. // UpdateByID updates a key name by ID.
func (s *KeysServiceOp) UpdateByID(keyID int, updateRequest *KeyUpdateRequest) (*Key, *Response, error) { func (s *KeysServiceOp) UpdateByID(ctx context.Context, keyID int, updateRequest *KeyUpdateRequest) (*Key, *Response, error) {
if keyID < 1 { if keyID < 1 {
return nil, nil, NewArgError("keyID", "cannot be less than 1") return nil, nil, NewArgError("keyID", "cannot be less than 1")
} }
@ -150,13 +154,13 @@ func (s *KeysServiceOp) UpdateByID(keyID int, updateRequest *KeyUpdateRequest) (
} }
path := fmt.Sprintf("%s/%d", keysBasePath, keyID) path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
req, err := s.client.NewRequest("PUT", path, updateRequest) req, err := s.client.NewRequest(ctx, "PUT", path, updateRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(keyRoot) root := new(keyRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -165,7 +169,7 @@ func (s *KeysServiceOp) UpdateByID(keyID int, updateRequest *KeyUpdateRequest) (
} }
// UpdateByFingerprint updates a key name by fingerprint. // UpdateByFingerprint updates a key name by fingerprint.
func (s *KeysServiceOp) UpdateByFingerprint(fingerprint string, updateRequest *KeyUpdateRequest) (*Key, *Response, error) { func (s *KeysServiceOp) UpdateByFingerprint(ctx context.Context, fingerprint string, updateRequest *KeyUpdateRequest) (*Key, *Response, error) {
if len(fingerprint) < 1 { if len(fingerprint) < 1 {
return nil, nil, NewArgError("fingerprint", "cannot be empty") return nil, nil, NewArgError("fingerprint", "cannot be empty")
} }
@ -175,13 +179,13 @@ func (s *KeysServiceOp) UpdateByFingerprint(fingerprint string, updateRequest *K
} }
path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint) path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint)
req, err := s.client.NewRequest("PUT", path, updateRequest) req, err := s.client.NewRequest(ctx, "PUT", path, updateRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(keyRoot) root := new(keyRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -190,33 +194,33 @@ func (s *KeysServiceOp) UpdateByFingerprint(fingerprint string, updateRequest *K
} }
// Delete key using a path // Delete key using a path
func (s *KeysServiceOp) delete(path string) (*Response, error) { func (s *KeysServiceOp) delete(ctx context.Context, path string) (*Response, error) {
req, err := s.client.NewRequest("DELETE", path, nil) req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }
// DeleteByID deletes a key by its id // DeleteByID deletes a key by its id
func (s *KeysServiceOp) DeleteByID(keyID int) (*Response, error) { func (s *KeysServiceOp) DeleteByID(ctx context.Context, keyID int) (*Response, error) {
if keyID < 1 { if keyID < 1 {
return nil, NewArgError("keyID", "cannot be less than 1") return nil, NewArgError("keyID", "cannot be less than 1")
} }
path := fmt.Sprintf("%s/%d", keysBasePath, keyID) path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
return s.delete(path) return s.delete(ctx, path)
} }
// DeleteByFingerprint deletes a key by its fingerprint // DeleteByFingerprint deletes a key by its fingerprint
func (s *KeysServiceOp) DeleteByFingerprint(fingerprint string) (*Response, error) { func (s *KeysServiceOp) DeleteByFingerprint(ctx context.Context, fingerprint string) (*Response, error) {
if len(fingerprint) < 1 { if len(fingerprint) < 1 {
return nil, NewArgError("fingerprint", "cannot be empty") return nil, NewArgError("fingerprint", "cannot be empty")
} }
path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint) path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint)
return s.delete(path) return s.delete(ctx, path)
} }

View File

@ -3,6 +3,8 @@ package godo
import ( import (
"net/url" "net/url"
"strconv" "strconv"
"github.com/digitalocean/godo/context"
) )
// Links manages links that are returned along with a List // Links manages links that are returned along with a List
@ -77,6 +79,6 @@ func pageForURL(urlText string) (int, error) {
} }
// Get a link action by id. // Get a link action by id.
func (la *LinkAction) Get(client *Client) (*Action, *Response, error) { func (la *LinkAction) Get(ctx context.Context, client *Client) (*Action, *Response, error) {
return client.Actions.Get(la.ID) return client.Actions.Get(ctx, la.ID)
} }

74
vendor/github.com/digitalocean/godo/load_balancers.go generated vendored Executable file → Normal file
View File

@ -2,6 +2,8 @@ package godo
import ( import (
"fmt" "fmt"
"github.com/digitalocean/godo/context"
) )
const loadBalancersBasePath = "/v2/load_balancers" const loadBalancersBasePath = "/v2/load_balancers"
@ -11,15 +13,15 @@ const dropletsPath = "droplets"
// LoadBalancersService is an interface for managing load balancers with the DigitalOcean API. // LoadBalancersService is an interface for managing load balancers with the DigitalOcean API.
// See: https://developers.digitalocean.com/documentation/v2#load-balancers // See: https://developers.digitalocean.com/documentation/v2#load-balancers
type LoadBalancersService interface { type LoadBalancersService interface {
Get(lbID string) (*LoadBalancer, *Response, error) Get(context.Context, string) (*LoadBalancer, *Response, error)
List(opt *ListOptions) ([]LoadBalancer, *Response, error) List(context.Context, *ListOptions) ([]LoadBalancer, *Response, error)
Create(lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error) Create(context.Context, *LoadBalancerRequest) (*LoadBalancer, *Response, error)
Update(lbID string, lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error) Update(ctx context.Context, lbID string, lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error)
Delete(lbID string) (*Response, error) Delete(ctx context.Context, lbID string) (*Response, error)
AddDroplets(lbID string, dropletIDs ...int) (*Response, error) AddDroplets(ctx context.Context, lbID string, dropletIDs ...int) (*Response, error)
RemoveDroplets(lbID string, dropletIDs ...int) (*Response, error) RemoveDroplets(ctx context.Context, lbID string, dropletIDs ...int) (*Response, error)
AddForwardingRules(lbID string, rules ...ForwardingRule) (*Response, error) AddForwardingRules(ctx context.Context, lbID string, rules ...ForwardingRule) (*Response, error)
RemoveForwardingRules(lbID string, rules ...ForwardingRule) (*Response, error) RemoveForwardingRules(ctx context.Context, lbID string, rules ...ForwardingRule) (*Response, error)
} }
// LoadBalancer represents a DigitalOcean load balancer configuration. // LoadBalancer represents a DigitalOcean load balancer configuration.
@ -138,16 +140,16 @@ type LoadBalancersServiceOp struct {
var _ LoadBalancersService = &LoadBalancersServiceOp{} var _ LoadBalancersService = &LoadBalancersServiceOp{}
// Get an existing load balancer by its identifier. // Get an existing load balancer by its identifier.
func (l *LoadBalancersServiceOp) Get(lbID string) (*LoadBalancer, *Response, error) { func (l *LoadBalancersServiceOp) Get(ctx context.Context, lbID string) (*LoadBalancer, *Response, error) {
path := fmt.Sprintf("%s/%s", loadBalancersBasePath, lbID) path := fmt.Sprintf("%s/%s", loadBalancersBasePath, lbID)
req, err := l.client.NewRequest("GET", path, nil) req, err := l.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(loadBalancerRoot) root := new(loadBalancerRoot)
resp, err := l.client.Do(req, root) resp, err := l.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -156,19 +158,19 @@ func (l *LoadBalancersServiceOp) Get(lbID string) (*LoadBalancer, *Response, err
} }
// List load balancers, with optional pagination. // List load balancers, with optional pagination.
func (l *LoadBalancersServiceOp) List(opt *ListOptions) ([]LoadBalancer, *Response, error) { func (l *LoadBalancersServiceOp) List(ctx context.Context, opt *ListOptions) ([]LoadBalancer, *Response, error) {
path, err := addOptions(loadBalancersBasePath, opt) path, err := addOptions(loadBalancersBasePath, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req, err := l.client.NewRequest("GET", path, nil) req, err := l.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(loadBalancersRoot) root := new(loadBalancersRoot)
resp, err := l.client.Do(req, root) resp, err := l.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -180,14 +182,14 @@ func (l *LoadBalancersServiceOp) List(opt *ListOptions) ([]LoadBalancer, *Respon
} }
// Create a new load balancer with a given configuration. // Create a new load balancer with a given configuration.
func (l *LoadBalancersServiceOp) Create(lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error) { func (l *LoadBalancersServiceOp) Create(ctx context.Context, lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error) {
req, err := l.client.NewRequest("POST", loadBalancersBasePath, lbr) req, err := l.client.NewRequest(ctx, "POST", loadBalancersBasePath, lbr)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(loadBalancerRoot) root := new(loadBalancerRoot)
resp, err := l.client.Do(req, root) resp, err := l.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -196,16 +198,16 @@ func (l *LoadBalancersServiceOp) Create(lbr *LoadBalancerRequest) (*LoadBalancer
} }
// Update an existing load balancer with new configuration. // Update an existing load balancer with new configuration.
func (l *LoadBalancersServiceOp) Update(lbID string, lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error) { func (l *LoadBalancersServiceOp) Update(ctx context.Context, lbID string, lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error) {
path := fmt.Sprintf("%s/%s", loadBalancersBasePath, lbID) path := fmt.Sprintf("%s/%s", loadBalancersBasePath, lbID)
req, err := l.client.NewRequest("PUT", path, lbr) req, err := l.client.NewRequest(ctx, "PUT", path, lbr)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(loadBalancerRoot) root := new(loadBalancerRoot)
resp, err := l.client.Do(req, root) resp, err := l.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -214,61 +216,61 @@ func (l *LoadBalancersServiceOp) Update(lbID string, lbr *LoadBalancerRequest) (
} }
// Delete a load balancer by its identifier. // Delete a load balancer by its identifier.
func (l *LoadBalancersServiceOp) Delete(ldID string) (*Response, error) { func (l *LoadBalancersServiceOp) Delete(ctx context.Context, ldID string) (*Response, error) {
path := fmt.Sprintf("%s/%s", loadBalancersBasePath, ldID) path := fmt.Sprintf("%s/%s", loadBalancersBasePath, ldID)
req, err := l.client.NewRequest("DELETE", path, nil) req, err := l.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return l.client.Do(req, nil) return l.client.Do(ctx, req, nil)
} }
// AddDroplets adds droplets to a load balancer. // AddDroplets adds droplets to a load balancer.
func (l *LoadBalancersServiceOp) AddDroplets(lbID string, dropletIDs ...int) (*Response, error) { func (l *LoadBalancersServiceOp) AddDroplets(ctx context.Context, lbID string, dropletIDs ...int) (*Response, error) {
path := fmt.Sprintf("%s/%s/%s", loadBalancersBasePath, lbID, dropletsPath) path := fmt.Sprintf("%s/%s/%s", loadBalancersBasePath, lbID, dropletsPath)
req, err := l.client.NewRequest("POST", path, &dropletIDsRequest{IDs: dropletIDs}) req, err := l.client.NewRequest(ctx, "POST", path, &dropletIDsRequest{IDs: dropletIDs})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return l.client.Do(req, nil) return l.client.Do(ctx, req, nil)
} }
// RemoveDroplets removes droplets from a load balancer. // RemoveDroplets removes droplets from a load balancer.
func (l *LoadBalancersServiceOp) RemoveDroplets(lbID string, dropletIDs ...int) (*Response, error) { func (l *LoadBalancersServiceOp) RemoveDroplets(ctx context.Context, lbID string, dropletIDs ...int) (*Response, error) {
path := fmt.Sprintf("%s/%s/%s", loadBalancersBasePath, lbID, dropletsPath) path := fmt.Sprintf("%s/%s/%s", loadBalancersBasePath, lbID, dropletsPath)
req, err := l.client.NewRequest("DELETE", path, &dropletIDsRequest{IDs: dropletIDs}) req, err := l.client.NewRequest(ctx, "DELETE", path, &dropletIDsRequest{IDs: dropletIDs})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return l.client.Do(req, nil) return l.client.Do(ctx, req, nil)
} }
// AddForwardingRules adds forwarding rules to a load balancer. // AddForwardingRules adds forwarding rules to a load balancer.
func (l *LoadBalancersServiceOp) AddForwardingRules(lbID string, rules ...ForwardingRule) (*Response, error) { func (l *LoadBalancersServiceOp) AddForwardingRules(ctx context.Context, lbID string, rules ...ForwardingRule) (*Response, error) {
path := fmt.Sprintf("%s/%s/%s", loadBalancersBasePath, lbID, forwardingRulesPath) path := fmt.Sprintf("%s/%s/%s", loadBalancersBasePath, lbID, forwardingRulesPath)
req, err := l.client.NewRequest("POST", path, &forwardingRulesRequest{Rules: rules}) req, err := l.client.NewRequest(ctx, "POST", path, &forwardingRulesRequest{Rules: rules})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return l.client.Do(req, nil) return l.client.Do(ctx, req, nil)
} }
// RemoveForwardingRules removes forwarding rules from a load balancer. // RemoveForwardingRules removes forwarding rules from a load balancer.
func (l *LoadBalancersServiceOp) RemoveForwardingRules(lbID string, rules ...ForwardingRule) (*Response, error) { func (l *LoadBalancersServiceOp) RemoveForwardingRules(ctx context.Context, lbID string, rules ...ForwardingRule) (*Response, error) {
path := fmt.Sprintf("%s/%s/%s", loadBalancersBasePath, lbID, forwardingRulesPath) path := fmt.Sprintf("%s/%s/%s", loadBalancersBasePath, lbID, forwardingRulesPath)
req, err := l.client.NewRequest("DELETE", path, &forwardingRulesRequest{Rules: rules}) req, err := l.client.NewRequest(ctx, "DELETE", path, &forwardingRulesRequest{Rules: rules})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return l.client.Do(req, nil) return l.client.Do(ctx, req, nil)
} }

View File

@ -1,10 +1,12 @@
package godo package godo
import "github.com/digitalocean/godo/context"
// RegionsService is an interface for interfacing with the regions // RegionsService is an interface for interfacing with the regions
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#regions // See: https://developers.digitalocean.com/documentation/v2#regions
type RegionsService interface { type RegionsService interface {
List(*ListOptions) ([]Region, *Response, error) List(context.Context, *ListOptions) ([]Region, *Response, error)
} }
// RegionsServiceOp handles communication with the region related methods of the // RegionsServiceOp handles communication with the region related methods of the
@ -34,20 +36,20 @@ func (r Region) String() string {
} }
// List all regions // List all regions
func (s *RegionsServiceOp) List(opt *ListOptions) ([]Region, *Response, error) { func (s *RegionsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Region, *Response, error) {
path := "v2/regions" path := "v2/regions"
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(regionsRoot) root := new(regionsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -1,10 +1,12 @@
package godo package godo
import "github.com/digitalocean/godo/context"
// SizesService is an interface for interfacing with the size // SizesService is an interface for interfacing with the size
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#sizes // See: https://developers.digitalocean.com/documentation/v2#sizes
type SizesService interface { type SizesService interface {
List(*ListOptions) ([]Size, *Response, error) List(context.Context, *ListOptions) ([]Size, *Response, error)
} }
// SizesServiceOp handles communication with the size related methods of the // SizesServiceOp handles communication with the size related methods of the
@ -38,20 +40,20 @@ type sizesRoot struct {
} }
// List all images // List all images
func (s *SizesServiceOp) List(opt *ListOptions) ([]Size, *Response, error) { func (s *SizesServiceOp) List(ctx context.Context, opt *ListOptions) ([]Size, *Response, error) {
path := "v2/sizes" path := "v2/sizes"
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(sizesRoot) root := new(sizesRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -1,6 +1,10 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
const snapshotBasePath = "v2/snapshots" const snapshotBasePath = "v2/snapshots"
@ -8,11 +12,11 @@ const snapshotBasePath = "v2/snapshots"
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#snapshots // See: https://developers.digitalocean.com/documentation/v2#snapshots
type SnapshotsService interface { type SnapshotsService interface {
List(*ListOptions) ([]Snapshot, *Response, error) List(context.Context, *ListOptions) ([]Snapshot, *Response, error)
ListVolume(*ListOptions) ([]Snapshot, *Response, error) ListVolume(context.Context, *ListOptions) ([]Snapshot, *Response, error)
ListDroplet(*ListOptions) ([]Snapshot, *Response, error) ListDroplet(context.Context, *ListOptions) ([]Snapshot, *Response, error)
Get(string) (*Snapshot, *Response, error) Get(context.Context, string) (*Snapshot, *Response, error)
Delete(string) (*Response, error) Delete(context.Context, string) (*Response, error)
} }
// SnapshotsServiceOp handles communication with the snapshot related methods of the // SnapshotsServiceOp handles communication with the snapshot related methods of the
@ -53,52 +57,52 @@ func (s Snapshot) String() string {
} }
// List lists all the snapshots available. // List lists all the snapshots available.
func (s *SnapshotsServiceOp) List(opt *ListOptions) ([]Snapshot, *Response, error) { func (s *SnapshotsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
return s.list(opt, nil) return s.list(ctx, opt, nil)
} }
// ListDroplet lists all the Droplet snapshots. // ListDroplet lists all the Droplet snapshots.
func (s *SnapshotsServiceOp) ListDroplet(opt *ListOptions) ([]Snapshot, *Response, error) { func (s *SnapshotsServiceOp) ListDroplet(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
listOpt := listSnapshotOptions{ResourceType: "droplet"} listOpt := listSnapshotOptions{ResourceType: "droplet"}
return s.list(opt, &listOpt) return s.list(ctx, opt, &listOpt)
} }
// ListVolume lists all the volume snapshots. // ListVolume lists all the volume snapshots.
func (s *SnapshotsServiceOp) ListVolume(opt *ListOptions) ([]Snapshot, *Response, error) { func (s *SnapshotsServiceOp) ListVolume(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
listOpt := listSnapshotOptions{ResourceType: "volume"} listOpt := listSnapshotOptions{ResourceType: "volume"}
return s.list(opt, &listOpt) return s.list(ctx, opt, &listOpt)
} }
// Get retrieves an snapshot by id. // Get retrieves an snapshot by id.
func (s *SnapshotsServiceOp) Get(snapshotID string) (*Snapshot, *Response, error) { func (s *SnapshotsServiceOp) Get(ctx context.Context, snapshotID string) (*Snapshot, *Response, error) {
return s.get(interface{}(snapshotID)) return s.get(ctx, snapshotID)
} }
// Delete an snapshot. // Delete an snapshot.
func (s *SnapshotsServiceOp) Delete(snapshotID string) (*Response, error) { func (s *SnapshotsServiceOp) Delete(ctx context.Context, snapshotID string) (*Response, error) {
path := fmt.Sprintf("%s/%s", snapshotBasePath, snapshotID) path := fmt.Sprintf("%s/%s", snapshotBasePath, snapshotID)
req, err := s.client.NewRequest("DELETE", path, nil) req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }
// Helper method for getting an individual snapshot // Helper method for getting an individual snapshot
func (s *SnapshotsServiceOp) get(ID interface{}) (*Snapshot, *Response, error) { func (s *SnapshotsServiceOp) get(ctx context.Context, ID string) (*Snapshot, *Response, error) {
path := fmt.Sprintf("%s/%v", snapshotBasePath, ID) path := fmt.Sprintf("%s/%s", snapshotBasePath, ID)
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(snapshotRoot) root := new(snapshotRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -107,7 +111,7 @@ func (s *SnapshotsServiceOp) get(ID interface{}) (*Snapshot, *Response, error) {
} }
// Helper method for listing snapshots // Helper method for listing snapshots
func (s *SnapshotsServiceOp) list(opt *ListOptions, listOpt *listSnapshotOptions) ([]Snapshot, *Response, error) { func (s *SnapshotsServiceOp) list(ctx context.Context, opt *ListOptions, listOpt *listSnapshotOptions) ([]Snapshot, *Response, error) {
path := snapshotBasePath path := snapshotBasePath
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
@ -118,13 +122,13 @@ func (s *SnapshotsServiceOp) list(opt *ListOptions, listOpt *listSnapshotOptions
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(snapshotsRoot) root := new(snapshotsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -3,6 +3,8 @@ package godo
import ( import (
"fmt" "fmt"
"time" "time"
"github.com/digitalocean/godo/context"
) )
const ( const (
@ -15,14 +17,14 @@ const (
// endpoints of the Digital Ocean API. // endpoints of the Digital Ocean API.
// See: https://developers.digitalocean.com/documentation/v2#storage // See: https://developers.digitalocean.com/documentation/v2#storage
type StorageService interface { type StorageService interface {
ListVolumes(*ListOptions) ([]Volume, *Response, error) ListVolumes(context.Context, *ListVolumeParams) ([]Volume, *Response, error)
GetVolume(string) (*Volume, *Response, error) GetVolume(context.Context, string) (*Volume, *Response, error)
CreateVolume(*VolumeCreateRequest) (*Volume, *Response, error) CreateVolume(context.Context, *VolumeCreateRequest) (*Volume, *Response, error)
DeleteVolume(string) (*Response, error) DeleteVolume(context.Context, string) (*Response, error)
ListSnapshots(volumeID string, opts *ListOptions) ([]Snapshot, *Response, error) ListSnapshots(ctx context.Context, volumeID string, opts *ListOptions) ([]Snapshot, *Response, error)
GetSnapshot(string) (*Snapshot, *Response, error) GetSnapshot(context.Context, string) (*Snapshot, *Response, error)
CreateSnapshot(*SnapshotCreateRequest) (*Snapshot, *Response, error) CreateSnapshot(context.Context, *SnapshotCreateRequest) (*Snapshot, *Response, error)
DeleteSnapshot(string) (*Response, error) DeleteSnapshot(context.Context, string) (*Response, error)
} }
// StorageServiceOp handles communication with the storage volumes related methods of the // StorageServiceOp handles communication with the storage volumes related methods of the
@ -31,6 +33,13 @@ type StorageServiceOp struct {
client *Client client *Client
} }
// ListVolumeParams stores the options you can set for a ListVolumeCall
type ListVolumeParams struct {
Region string `json:"region"`
Name string `json:"name"`
ListOptions *ListOptions `json:"list_options,omitempty"`
}
var _ StorageService = &StorageServiceOp{} var _ StorageService = &StorageServiceOp{}
// Volume represents a Digital Ocean block store volume. // Volume represents a Digital Ocean block store volume.
@ -65,22 +74,33 @@ type VolumeCreateRequest struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
SizeGigaBytes int64 `json:"size_gigabytes"` SizeGigaBytes int64 `json:"size_gigabytes"`
SnapshotID string `json:"snapshot_id"`
} }
// ListVolumes lists all storage volumes. // ListVolumes lists all storage volumes.
func (svc *StorageServiceOp) ListVolumes(opt *ListOptions) ([]Volume, *Response, error) { func (svc *StorageServiceOp) ListVolumes(ctx context.Context, params *ListVolumeParams) ([]Volume, *Response, error) {
path, err := addOptions(storageAllocPath, opt) path := storageAllocPath
if err != nil { if params != nil {
return nil, nil, err if params.Region != "" && params.Name != "" {
path = fmt.Sprintf("%s?name=%s&region=%s", path, params.Name, params.Region)
}
if params.ListOptions != nil {
var err error
path, err = addOptions(path, params.ListOptions)
if err != nil {
return nil, nil, err
}
}
} }
req, err := svc.client.NewRequest("GET", path, nil) req, err := svc.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(storageVolumesRoot) root := new(storageVolumesRoot)
resp, err := svc.client.Do(req, root) resp, err := svc.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -93,16 +113,16 @@ func (svc *StorageServiceOp) ListVolumes(opt *ListOptions) ([]Volume, *Response,
} }
// CreateVolume creates a storage volume. The name must be unique. // CreateVolume creates a storage volume. The name must be unique.
func (svc *StorageServiceOp) CreateVolume(createRequest *VolumeCreateRequest) (*Volume, *Response, error) { func (svc *StorageServiceOp) CreateVolume(ctx context.Context, createRequest *VolumeCreateRequest) (*Volume, *Response, error) {
path := storageAllocPath path := storageAllocPath
req, err := svc.client.NewRequest("POST", path, createRequest) req, err := svc.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(storageVolumeRoot) root := new(storageVolumeRoot)
resp, err := svc.client.Do(req, root) resp, err := svc.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -110,16 +130,16 @@ func (svc *StorageServiceOp) CreateVolume(createRequest *VolumeCreateRequest) (*
} }
// GetVolume retrieves an individual storage volume. // GetVolume retrieves an individual storage volume.
func (svc *StorageServiceOp) GetVolume(id string) (*Volume, *Response, error) { func (svc *StorageServiceOp) GetVolume(ctx context.Context, id string) (*Volume, *Response, error) {
path := fmt.Sprintf("%s/%s", storageAllocPath, id) path := fmt.Sprintf("%s/%s", storageAllocPath, id)
req, err := svc.client.NewRequest("GET", path, nil) req, err := svc.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(storageVolumeRoot) root := new(storageVolumeRoot)
resp, err := svc.client.Do(req, root) resp, err := svc.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -128,14 +148,14 @@ func (svc *StorageServiceOp) GetVolume(id string) (*Volume, *Response, error) {
} }
// DeleteVolume deletes a storage volume. // DeleteVolume deletes a storage volume.
func (svc *StorageServiceOp) DeleteVolume(id string) (*Response, error) { func (svc *StorageServiceOp) DeleteVolume(ctx context.Context, id string) (*Response, error) {
path := fmt.Sprintf("%s/%s", storageAllocPath, id) path := fmt.Sprintf("%s/%s", storageAllocPath, id)
req, err := svc.client.NewRequest("DELETE", path, nil) req, err := svc.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return svc.client.Do(req, nil) return svc.client.Do(ctx, req, nil)
} }
// SnapshotCreateRequest represents a request to create a block store // SnapshotCreateRequest represents a request to create a block store
@ -147,20 +167,20 @@ type SnapshotCreateRequest struct {
} }
// ListSnapshots lists all snapshots related to a storage volume. // ListSnapshots lists all snapshots related to a storage volume.
func (svc *StorageServiceOp) ListSnapshots(volumeID string, opt *ListOptions) ([]Snapshot, *Response, error) { func (svc *StorageServiceOp) ListSnapshots(ctx context.Context, volumeID string, opt *ListOptions) ([]Snapshot, *Response, error) {
path := fmt.Sprintf("%s/%s/snapshots", storageAllocPath, volumeID) path := fmt.Sprintf("%s/%s/snapshots", storageAllocPath, volumeID)
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req, err := svc.client.NewRequest("GET", path, nil) req, err := svc.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(snapshotsRoot) root := new(snapshotsRoot)
resp, err := svc.client.Do(req, root) resp, err := svc.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -173,16 +193,16 @@ func (svc *StorageServiceOp) ListSnapshots(volumeID string, opt *ListOptions) ([
} }
// CreateSnapshot creates a snapshot of a storage volume. // CreateSnapshot creates a snapshot of a storage volume.
func (svc *StorageServiceOp) CreateSnapshot(createRequest *SnapshotCreateRequest) (*Snapshot, *Response, error) { func (svc *StorageServiceOp) CreateSnapshot(ctx context.Context, createRequest *SnapshotCreateRequest) (*Snapshot, *Response, error) {
path := fmt.Sprintf("%s/%s/snapshots", storageAllocPath, createRequest.VolumeID) path := fmt.Sprintf("%s/%s/snapshots", storageAllocPath, createRequest.VolumeID)
req, err := svc.client.NewRequest("POST", path, createRequest) req, err := svc.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(snapshotRoot) root := new(snapshotRoot)
resp, err := svc.client.Do(req, root) resp, err := svc.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -190,16 +210,16 @@ func (svc *StorageServiceOp) CreateSnapshot(createRequest *SnapshotCreateRequest
} }
// GetSnapshot retrieves an individual snapshot. // GetSnapshot retrieves an individual snapshot.
func (svc *StorageServiceOp) GetSnapshot(id string) (*Snapshot, *Response, error) { func (svc *StorageServiceOp) GetSnapshot(ctx context.Context, id string) (*Snapshot, *Response, error) {
path := fmt.Sprintf("%s/%s", storageSnapPath, id) path := fmt.Sprintf("%s/%s", storageSnapPath, id)
req, err := svc.client.NewRequest("GET", path, nil) req, err := svc.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(snapshotRoot) root := new(snapshotRoot)
resp, err := svc.client.Do(req, root) resp, err := svc.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -208,12 +228,12 @@ func (svc *StorageServiceOp) GetSnapshot(id string) (*Snapshot, *Response, error
} }
// DeleteSnapshot deletes a snapshot. // DeleteSnapshot deletes a snapshot.
func (svc *StorageServiceOp) DeleteSnapshot(id string) (*Response, error) { func (svc *StorageServiceOp) DeleteSnapshot(ctx context.Context, id string) (*Response, error) {
path := fmt.Sprintf("%s/%s", storageSnapPath, id) path := fmt.Sprintf("%s/%s", storageSnapPath, id)
req, err := svc.client.NewRequest("DELETE", path, nil) req, err := svc.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return svc.client.Do(req, nil) return svc.client.Do(ctx, req, nil)
} }

View File

@ -1,17 +1,20 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
// StorageActionsService is an interface for interfacing with the // StorageActionsService is an interface for interfacing with the
// storage actions endpoints of the Digital Ocean API. // storage actions endpoints of the Digital Ocean API.
// See: https://developers.digitalocean.com/documentation/v2#storage-actions // See: https://developers.digitalocean.com/documentation/v2#storage-actions
type StorageActionsService interface { type StorageActionsService interface {
Attach(volumeID string, dropletID int) (*Action, *Response, error) Attach(ctx context.Context, volumeID string, dropletID int) (*Action, *Response, error)
Detach(volumeID string) (*Action, *Response, error) DetachByDropletID(ctx context.Context, volumeID string, dropletID int) (*Action, *Response, error)
DetachByDropletID(volumeID string, dropletID int) (*Action, *Response, error) Get(ctx context.Context, volumeID string, actionID int) (*Action, *Response, error)
Get(volumeID string, actionID int) (*Action, *Response, error) List(ctx context.Context, volumeID string, opt *ListOptions) ([]Action, *Response, error)
List(volumeID string, opt *ListOptions) ([]Action, *Response, error) Resize(ctx context.Context, volumeID string, sizeGigabytes int, regionSlug string) (*Action, *Response, error)
Resize(volumeID string, sizeGigabytes int, regionSlug string) (*Action, *Response, error)
} }
// StorageActionsServiceOp handles communication with the storage volumes // StorageActionsServiceOp handles communication with the storage volumes
@ -27,68 +30,60 @@ type StorageAttachment struct {
} }
// Attach a storage volume to a Droplet. // Attach a storage volume to a Droplet.
func (s *StorageActionsServiceOp) Attach(volumeID string, dropletID int) (*Action, *Response, error) { func (s *StorageActionsServiceOp) Attach(ctx context.Context, volumeID string, dropletID int) (*Action, *Response, error) {
request := &ActionRequest{ request := &ActionRequest{
"type": "attach", "type": "attach",
"droplet_id": dropletID, "droplet_id": dropletID,
} }
return s.doAction(volumeID, request) return s.doAction(ctx, volumeID, request)
}
// Detach a storage volume from a Droplet.
func (s *StorageActionsServiceOp) Detach(volumeID string) (*Action, *Response, error) {
request := &ActionRequest{
"type": "detach",
}
return s.doAction(volumeID, request)
} }
// DetachByDropletID a storage volume from a Droplet by Droplet ID. // DetachByDropletID a storage volume from a Droplet by Droplet ID.
func (s *StorageActionsServiceOp) DetachByDropletID(volumeID string, dropletID int) (*Action, *Response, error) { func (s *StorageActionsServiceOp) DetachByDropletID(ctx context.Context, volumeID string, dropletID int) (*Action, *Response, error) {
request := &ActionRequest{ request := &ActionRequest{
"type": "detach", "type": "detach",
"droplet_id": dropletID, "droplet_id": dropletID,
} }
return s.doAction(volumeID, request) return s.doAction(ctx, volumeID, request)
} }
// Get an action for a particular storage volume by id. // Get an action for a particular storage volume by id.
func (s *StorageActionsServiceOp) Get(volumeID string, actionID int) (*Action, *Response, error) { func (s *StorageActionsServiceOp) Get(ctx context.Context, volumeID string, actionID int) (*Action, *Response, error) {
path := fmt.Sprintf("%s/%d", storageAllocationActionPath(volumeID), actionID) path := fmt.Sprintf("%s/%d", storageAllocationActionPath(volumeID), actionID)
return s.get(path) return s.get(ctx, path)
} }
// List the actions for a particular storage volume. // List the actions for a particular storage volume.
func (s *StorageActionsServiceOp) List(volumeID string, opt *ListOptions) ([]Action, *Response, error) { func (s *StorageActionsServiceOp) List(ctx context.Context, volumeID string, opt *ListOptions) ([]Action, *Response, error) {
path := storageAllocationActionPath(volumeID) path := storageAllocationActionPath(volumeID)
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return s.list(path) return s.list(ctx, path)
} }
// Resize a storage volume. // Resize a storage volume.
func (s *StorageActionsServiceOp) Resize(volumeID string, sizeGigabytes int, regionSlug string) (*Action, *Response, error) { func (s *StorageActionsServiceOp) Resize(ctx context.Context, volumeID string, sizeGigabytes int, regionSlug string) (*Action, *Response, error) {
request := &ActionRequest{ request := &ActionRequest{
"type": "resize", "type": "resize",
"size_gigabytes": sizeGigabytes, "size_gigabytes": sizeGigabytes,
"region": regionSlug, "region": regionSlug,
} }
return s.doAction(volumeID, request) return s.doAction(ctx, volumeID, request)
} }
func (s *StorageActionsServiceOp) doAction(volumeID string, request *ActionRequest) (*Action, *Response, error) { func (s *StorageActionsServiceOp) doAction(ctx context.Context, volumeID string, request *ActionRequest) (*Action, *Response, error) {
path := storageAllocationActionPath(volumeID) path := storageAllocationActionPath(volumeID)
req, err := s.client.NewRequest("POST", path, request) req, err := s.client.NewRequest(ctx, "POST", path, request)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -96,14 +91,14 @@ func (s *StorageActionsServiceOp) doAction(volumeID string, request *ActionReque
return root.Event, resp, err return root.Event, resp, err
} }
func (s *StorageActionsServiceOp) get(path string) (*Action, *Response, error) { func (s *StorageActionsServiceOp) get(ctx context.Context, path string) (*Action, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionRoot) root := new(actionRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -111,14 +106,14 @@ func (s *StorageActionsServiceOp) get(path string) (*Action, *Response, error) {
return root.Event, resp, err return root.Event, resp, err
} }
func (s *StorageActionsServiceOp) list(path string) ([]Action, *Response, error) { func (s *StorageActionsServiceOp) list(ctx context.Context, path string) ([]Action, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(actionsRoot) root := new(actionsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View File

@ -1,6 +1,10 @@
package godo package godo
import "fmt" import (
"fmt"
"github.com/digitalocean/godo/context"
)
const tagsBasePath = "v2/tags" const tagsBasePath = "v2/tags"
@ -8,14 +12,13 @@ const tagsBasePath = "v2/tags"
// endpoints of the DigitalOcean API // endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#tags // See: https://developers.digitalocean.com/documentation/v2#tags
type TagsService interface { type TagsService interface {
List(*ListOptions) ([]Tag, *Response, error) List(context.Context, *ListOptions) ([]Tag, *Response, error)
Get(string) (*Tag, *Response, error) Get(context.Context, string) (*Tag, *Response, error)
Create(*TagCreateRequest) (*Tag, *Response, error) Create(context.Context, *TagCreateRequest) (*Tag, *Response, error)
Update(string, *TagUpdateRequest) (*Response, error) Delete(context.Context, string) (*Response, error)
Delete(string) (*Response, error)
TagResources(string, *TagResourcesRequest) (*Response, error) TagResources(context.Context, string, *TagResourcesRequest) (*Response, error)
UntagResources(string, *UntagResourcesRequest) (*Response, error) UntagResources(context.Context, string, *UntagResourcesRequest) (*Response, error)
} }
// TagsServiceOp handles communication with tag related method of the // TagsServiceOp handles communication with tag related method of the
@ -62,11 +65,6 @@ type TagCreateRequest struct {
Name string `json:"name"` Name string `json:"name"`
} }
//TagUpdateRequest represents the JSON structure of a request of that type.
type TagUpdateRequest struct {
Name string `json:"name"`
}
// TagResourcesRequest represents the JSON structure of a request of that type. // TagResourcesRequest represents the JSON structure of a request of that type.
type TagResourcesRequest struct { type TagResourcesRequest struct {
Resources []Resource `json:"resources"` Resources []Resource `json:"resources"`
@ -87,7 +85,7 @@ type tagRoot struct {
} }
// List all tags // List all tags
func (s *TagsServiceOp) List(opt *ListOptions) ([]Tag, *Response, error) { func (s *TagsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Tag, *Response, error) {
path := tagsBasePath path := tagsBasePath
path, err := addOptions(path, opt) path, err := addOptions(path, opt)
@ -95,13 +93,13 @@ func (s *TagsServiceOp) List(opt *ListOptions) ([]Tag, *Response, error) {
return nil, nil, err return nil, nil, err
} }
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(tagsRoot) root := new(tagsRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -113,16 +111,16 @@ func (s *TagsServiceOp) List(opt *ListOptions) ([]Tag, *Response, error) {
} }
// Get a single tag // Get a single tag
func (s *TagsServiceOp) Get(name string) (*Tag, *Response, error) { func (s *TagsServiceOp) Get(ctx context.Context, name string) (*Tag, *Response, error) {
path := fmt.Sprintf("%s/%s", tagsBasePath, name) path := fmt.Sprintf("%s/%s", tagsBasePath, name)
req, err := s.client.NewRequest("GET", path, nil) req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(tagRoot) root := new(tagRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -131,18 +129,18 @@ func (s *TagsServiceOp) Get(name string) (*Tag, *Response, error) {
} }
// Create a new tag // Create a new tag
func (s *TagsServiceOp) Create(createRequest *TagCreateRequest) (*Tag, *Response, error) { func (s *TagsServiceOp) Create(ctx context.Context, createRequest *TagCreateRequest) (*Tag, *Response, error) {
if createRequest == nil { if createRequest == nil {
return nil, nil, NewArgError("createRequest", "cannot be nil") return nil, nil, NewArgError("createRequest", "cannot be nil")
} }
req, err := s.client.NewRequest("POST", tagsBasePath, createRequest) req, err := s.client.NewRequest(ctx, "POST", tagsBasePath, createRequest)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
root := new(tagRoot) root := new(tagRoot)
resp, err := s.client.Do(req, root) resp, err := s.client.Do(ctx, req, root)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }
@ -150,46 +148,25 @@ func (s *TagsServiceOp) Create(createRequest *TagCreateRequest) (*Tag, *Response
return root.Tag, resp, err return root.Tag, resp, err
} }
// Update an exsting tag
func (s *TagsServiceOp) Update(name string, updateRequest *TagUpdateRequest) (*Response, error) {
if name == "" {
return nil, NewArgError("name", "cannot be empty")
}
if updateRequest == nil {
return nil, NewArgError("updateRequest", "cannot be nil")
}
path := fmt.Sprintf("%s/%s", tagsBasePath, name)
req, err := s.client.NewRequest("PUT", path, updateRequest)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
return resp, err
}
// Delete an existing tag // Delete an existing tag
func (s *TagsServiceOp) Delete(name string) (*Response, error) { func (s *TagsServiceOp) Delete(ctx context.Context, name string) (*Response, error) {
if name == "" { if name == "" {
return nil, NewArgError("name", "cannot be empty") return nil, NewArgError("name", "cannot be empty")
} }
path := fmt.Sprintf("%s/%s", tagsBasePath, name) path := fmt.Sprintf("%s/%s", tagsBasePath, name)
req, err := s.client.NewRequest("DELETE", path, nil) req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }
// TagResources associates resources with a given Tag. // TagResources associates resources with a given Tag.
func (s *TagsServiceOp) TagResources(name string, tagRequest *TagResourcesRequest) (*Response, error) { func (s *TagsServiceOp) TagResources(ctx context.Context, name string, tagRequest *TagResourcesRequest) (*Response, error) {
if name == "" { if name == "" {
return nil, NewArgError("name", "cannot be empty") return nil, NewArgError("name", "cannot be empty")
} }
@ -199,18 +176,18 @@ func (s *TagsServiceOp) TagResources(name string, tagRequest *TagResourcesReques
} }
path := fmt.Sprintf("%s/%s/resources", tagsBasePath, name) path := fmt.Sprintf("%s/%s/resources", tagsBasePath, name)
req, err := s.client.NewRequest("POST", path, tagRequest) req, err := s.client.NewRequest(ctx, "POST", path, tagRequest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }
// UntagResources dissociates resources with a given Tag. // UntagResources dissociates resources with a given Tag.
func (s *TagsServiceOp) UntagResources(name string, untagRequest *UntagResourcesRequest) (*Response, error) { func (s *TagsServiceOp) UntagResources(ctx context.Context, name string, untagRequest *UntagResourcesRequest) (*Response, error) {
if name == "" { if name == "" {
return nil, NewArgError("name", "cannot be empty") return nil, NewArgError("name", "cannot be empty")
} }
@ -220,12 +197,12 @@ func (s *TagsServiceOp) UntagResources(name string, untagRequest *UntagResources
} }
path := fmt.Sprintf("%s/%s/resources", tagsBasePath, name) path := fmt.Sprintf("%s/%s/resources", tagsBasePath, name)
req, err := s.client.NewRequest("DELETE", path, untagRequest) req, err := s.client.NewRequest(ctx, "DELETE", path, untagRequest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(ctx, req, nil)
return resp, err return resp, err
} }

12
vendor/vendor.json vendored
View File

@ -1374,11 +1374,17 @@
"revisionTime": "2016-06-17T17:01:58Z" "revisionTime": "2016-06-17T17:01:58Z"
}, },
{ {
"checksumSHA1": "tOlmmumwQ9pCv5cQgs+W7sgPVgU=", "checksumSHA1": "uuenX+nAyhQfYqedBhQ+yhBh1mA=",
"comment": "v0.9.0-20-gf75d769", "comment": "v0.9.0-20-gf75d769",
"path": "github.com/digitalocean/godo", "path": "github.com/digitalocean/godo",
"revision": "767976000cc435d38646653b52be9be572727f30", "revision": "83908b1ddd666d08a9b020c697b55ae3895be2fd",
"revisionTime": "2017-02-14T20:43:37Z" "revisionTime": "2017-04-26T22:25:10Z"
},
{
"checksumSHA1": "YpWoCsk+u9H5ctWNKKSVPf4b2as=",
"path": "github.com/digitalocean/godo/context",
"revision": "83908b1ddd666d08a9b020c697b55ae3895be2fd",
"revisionTime": "2017-04-26T22:25:10Z"
}, },
{ {
"checksumSHA1": "1PlWp7ZA8IBK6J6XcIwRpoSTNoc=", "checksumSHA1": "1PlWp7ZA8IBK6J6XcIwRpoSTNoc=",

View File

@ -0,0 +1,65 @@
---
layout: "digitalocean"
page_title: "DigitalOcean: digitalocean_certificate"
sidebar_current: "docs-do-resource-certificate"
description: |-
Provides a DigitalOcean Certificate resource.
---
# digitalocean\_certificate
Provides a DigitalOcean Certificate resource that allows you to manage
certificates for configuring TLS termination in Load Balancers.
Certificates created with this resource can be referenced in your
Load Balancer configuration via their ID.
## Example Usage
```hcl
# Create a new TLS certificate
resource "digitalocean_certificate" "cert" {
name = "Terraform Example"
private_key = "${file("/Users/terraform/certs/privkey.pem")}"
leaf_certificate = "${file("/Users/terraform/certs/cert.pem")}"
certificate_chain = "${file("/Users/terraform/certs/fullchain.pem")}"
}
# Create a new Load Balancer with TLS termination
resource "digitalocean_loadbalancer" "public" {
name = "secure-loadbalancer-1"
region = "nyc3"
droplet_tag = "backend"
forwarding_rule {
entry_port = 443
entry_protocol = "https"
target_port = 80
target_protocol = "http"
certificate_id = "${digitalocean_certificate.cert.id}"
}
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) The name of the certificate for identification.
* `private_key` - (Required) The contents of a PEM-formatted private-key
corresponding to the SSL certificate.
* `leaf_certificate` - (Required) The contents of a PEM-formatted public
TLS certificate.
* `certificate_chain` - (Optional) The full PEM-formatted trust chain
between the certificate authority's certificate and your domain's TLS
certificate.
## Attributes Reference
The following attributes are exported:
* `id` - The unique ID of the certificate
* `name` - The name of the certificate
* `not_after` - The expiration date of the certificate
* `sha1_fingerprint` - The SHA-1 fingerprint of the certificate

View File

@ -22,6 +22,9 @@
<li<%= sidebar_current("docs-do-resource") %>> <li<%= sidebar_current("docs-do-resource") %>>
<a href="#">Resources</a> <a href="#">Resources</a>
<ul class="nav nav-visible"> <ul class="nav nav-visible">
<li<%= sidebar_current("docs-do-resource-certificate") %>>
<a href="/docs/providers/do/r/certificate.html">digitalocean_certificate</a>
</li>
<li<%= sidebar_current("docs-do-resource-domain") %>> <li<%= sidebar_current("docs-do-resource-domain") %>>
<a href="/docs/providers/do/r/domain.html">digitalocean_domain</a> <a href="/docs/providers/do/r/domain.html">digitalocean_domain</a>
</li> </li>