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
import (
"context"
"log"
"net/http"
"net/http/httputil"
@ -55,7 +56,7 @@ func waitForAction(client *godo.Client, action *godo.Action) error {
pending = "in-progress"
target = "completed"
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 {
return nil, "", err
}

View File

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

View File

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

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"github.com/digitalocean/godo"
@ -9,7 +10,7 @@ import (
func loadbalancerStateRefreshFunc(client *godo.Client, loadbalancerId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
lb, _, err := client.LoadBalancers.Get(loadbalancerId)
lb, _, err := client.LoadBalancers.Get(context.Background(), loadbalancerId)
if err != nil {
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{
"digitalocean_certificate": resourceDigitalOceanCertificate(),
"digitalocean_domain": resourceDigitalOceanDomain(),
"digitalocean_droplet": resourceDigitalOceanDroplet(),
"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
import (
"context"
"fmt"
"log"
@ -44,7 +45,7 @@ func resourceDigitalOceanDomainCreate(d *schema.ResourceData, meta interface{})
}
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 {
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 {
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 the domain is somehow already destroyed, mark as
// successfully gone
@ -79,7 +80,7 @@ func resourceDigitalOceanDomainDelete(d *schema.ResourceData, meta interface{})
client := meta.(*godo.Client)
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 {
return fmt.Errorf("Error deleting Domain: %s", err)
}

View File

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

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"log"
"strconv"
@ -213,7 +214,7 @@ func resourceDigitalOceanDropletCreate(d *schema.ResourceData, meta interface{})
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 {
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
droplet, resp, err := client.Droplets.Get(id)
droplet, resp, err := client.Droplets.Get(context.Background(), id)
if err != nil {
// check if the droplet no longer exists.
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 {
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") {
return fmt.Errorf(
"Error powering off droplet (%s): %s", d.Id(), err)
@ -355,7 +356,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
}
// 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 {
newErr := powerOnAndWait(d, meta)
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)
}
_, _, err = client.DropletActions.PowerOn(id)
_, _, err = client.DropletActions.PowerOn(context.Background(), id)
if err != nil {
return fmt.Errorf(
@ -395,7 +396,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
oldName, newName := d.GetChange("name")
// Rename the droplet
_, _, err = client.DropletActions.Rename(id, newName.(string))
_, _, err = client.DropletActions.Rename(context.Background(), id, newName.(string))
if err != nil {
return fmt.Errorf(
@ -415,7 +416,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
// As there is no way to disable private networking,
// we only check if it needs to be enabled
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 {
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
if d.HasChange("ipv6") && d.Get("ipv6").(bool) {
_, _, err = client.DropletActions.EnableIPv6(id)
_, _, err = client.DropletActions.EnableIPv6(context.Background(), id)
if err != nil {
return fmt.Errorf(
@ -478,7 +479,7 @@ func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{})
oldIDSet := newSet(oldIDs.([]interface{}))
newIDSet := newSet(newIDs.([]interface{}))
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 {
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) {
action, _, err := client.StorageActions.Detach(volumeID)
action, _, err := client.StorageActions.DetachByDropletID(context.Background(), volumeID, id)
if err != nil {
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())
// Destroy the droplet
_, err = client.Droplets.Delete(id)
_, err = client.Droplets.Delete(context.Background(), id)
// Handle remotely destroyed droplets
if err != nil && strings.Contains(err.Error(), "404 Not Found") {
@ -587,7 +588,7 @@ func newDropletStateRefreshFunc(
// See if we can access our attribute
if attr, ok := d.GetOk(attribute); ok {
// Retrieve the droplet properties
droplet, _, err := client.Droplets.Get(id)
droplet, _, err := client.Droplets.Get(context.Background(), id)
if err != nil {
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)
_, _, err = client.DropletActions.PowerOn(id)
_, _, err = client.DropletActions.PowerOn(context.Background(), id)
if err != nil {
return err
}

View File

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

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"log"
"time"
@ -50,7 +51,7 @@ func resourceDigitalOceanFloatingIpCreate(d *schema.ResourceData, meta interface
}
log.Printf("[DEBUG] FloatingIP Create: %#v", regionOpts)
floatingIp, _, err := client.FloatingIPs.Create(regionOpts)
floatingIp, _, err := client.FloatingIPs.Create(context.Background(), regionOpts)
if err != nil {
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 {
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 {
return fmt.Errorf(
"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 v, ok := d.GetOk("droplet_id"); ok {
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 {
return fmt.Errorf(
"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
@ -95,7 +96,7 @@ func resourceDigitalOceanFloatingIpUpdate(d *schema.ResourceData, meta interface
}
} else {
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 {
return fmt.Errorf(
"Error Unassigning FloatingIP (%s): %s", d.Id(), err)
@ -116,7 +117,7 @@ func resourceDigitalOceanFloatingIpRead(d *schema.ResourceData, meta interface{}
client := meta.(*godo.Client)
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 {
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 {
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 {
return fmt.Errorf(
"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())
_, err := client.FloatingIPs.Delete(d.Id())
_, err := client.FloatingIPs.Delete(context.Background(), d.Id())
if err != nil {
return fmt.Errorf("Error deleting FloatingIP: %s", err)
}
@ -189,7 +190,7 @@ func newFloatingIPStateRefreshFunc(
return func() (interface{}, string, error) {
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 {
return nil, "", fmt.Errorf("Error retrieving FloatingIP (%s) ActionId (%d): %s", d.Id(), actionId, err)
}

View File

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

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"log"
"strconv"
@ -210,7 +211,7 @@ func resourceDigitalOceanLoadbalancerCreate(d *schema.ResourceData, meta interfa
}
log.Printf("[DEBUG] Loadbalancer Create: %#v", lbOpts)
loadbalancer, _, err := client.LoadBalancers.Create(lbOpts)
loadbalancer, _, err := client.LoadBalancers.Create(context.Background(), lbOpts)
if err != nil {
return fmt.Errorf("Error creating Load Balancer: %s", err)
}
@ -236,7 +237,7 @@ func resourceDigitalOceanLoadbalancerRead(d *schema.ResourceData, meta interface
client := meta.(*godo.Client)
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 {
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)
_, _, err = client.LoadBalancers.Update(d.Id(), lbOpts)
_, _, err = client.LoadBalancers.Update(context.Background(), d.Id(), lbOpts)
if err != nil {
return fmt.Errorf("Error updating Load Balancer: %s", err)
}
@ -286,7 +287,7 @@ func resourceDigitalOceanLoadbalancerDelete(d *schema.ResourceData, meta interfa
client := meta.(*godo.Client)
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 {
return fmt.Errorf("Error deleting Load Balancer: %s", err)
}

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"strings"
"testing"
@ -170,7 +171,7 @@ func testAccCheckDigitalOceanLoadbalancerDestroy(s *terraform.State) error {
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") {
return fmt.Errorf(
@ -195,7 +196,7 @@ func testAccCheckDigitalOceanLoadbalancerExists(n string, loadbalancer *godo.Loa
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 {
return err

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"log"
"strconv"
@ -101,7 +102,7 @@ func resourceDigitalOceanRecordCreate(d *schema.ResourceData, meta interface{})
}
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 {
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)
}
rec, resp, err := client.Domains.Record(domain, id)
rec, resp, err := client.Domains.Record(context.Background(), domain, id)
if err != nil {
// If the record is somehow already destroyed, mark as
// successfully gone
@ -168,7 +169,7 @@ func resourceDigitalOceanRecordUpdate(d *schema.ResourceData, meta interface{})
}
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 {
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)
resp, delErr := client.Domains.DeleteRecord(domain, id)
resp, delErr := client.Domains.DeleteRecord(context.Background(), domain, id)
if delErr != nil {
// If the record is somehow already destroyed, mark as
// successfully gone

View File

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

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"log"
"strconv"
@ -60,7 +61,7 @@ func resourceDigitalOceanSSHKeyCreate(d *schema.ResourceData, meta interface{})
}
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 {
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)
}
key, resp, err := client.Keys.GetByID(id)
key, resp, err := client.Keys.GetByID(context.Background(), id)
if err != nil {
// If the key is somehow already destroyed, mark as
// successfully gone
@ -115,7 +116,7 @@ func resourceDigitalOceanSSHKeyUpdate(d *schema.ResourceData, meta interface{})
opts := &godo.KeyUpdateRequest{
Name: newName,
}
_, _, err = client.Keys.UpdateByID(id, opts)
_, _, err = client.Keys.UpdateByID(context.Background(), id, opts)
if err != nil {
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)
_, err = client.Keys.DeleteByID(id)
_, err = client.Keys.DeleteByID(context.Background(), id)
if err != nil {
return fmt.Errorf("Error deleting SSH key: %s", err)
}

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"strconv"
"testing"
@ -52,7 +53,7 @@ func testAccCheckDigitalOceanSSHKeyDestroy(s *terraform.State) error {
}
// Try to find the key
_, _, err = client.Keys.GetByID(id)
_, _, err = client.Keys.GetByID(context.Background(), id)
if err == nil {
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
foundKey, _, err := client.Keys.GetByID(id)
foundKey, _, err := client.Keys.GetByID(context.Background(), id)
if err != nil {
return err

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"log"
@ -12,7 +13,6 @@ func resourceDigitalOceanTag() *schema.Resource {
return &schema.Resource{
Create: resourceDigitalOceanTagCreate,
Read: resourceDigitalOceanTagRead,
Update: resourceDigitalOceanTagUpdate,
Delete: resourceDigitalOceanTagDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
@ -22,6 +22,7 @@ func resourceDigitalOceanTag() *schema.Resource {
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
@ -36,7 +37,7 @@ func resourceDigitalOceanTagCreate(d *schema.ResourceData, meta interface{}) err
}
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 {
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 {
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 the tag is somehow already destroyed, mark as
// successfully gone
@ -67,34 +68,11 @@ func resourceDigitalOceanTagRead(d *schema.ResourceData, meta interface{}) error
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 {
client := meta.(*godo.Client)
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 {
return fmt.Errorf("Error deleting tag: %s", err)
}

View File

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

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"fmt"
"log"
@ -67,7 +68,7 @@ func resourceDigitalOceanVolumeCreate(d *schema.ResourceData, meta interface{})
}
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 {
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 {
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 the volume is somehow already destroyed, mark as
// successfully gone
@ -111,7 +112,7 @@ func resourceDigitalOceanVolumeDelete(d *schema.ResourceData, meta interface{})
client := meta.(*godo.Client)
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 {
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) {
client := v.(*godo.Client)
volume, _, err := client.Storage.GetVolume(rs.Id())
volume, _, err := client.Storage.GetVolume(context.Background(), rs.Id())
if err != nil {
return nil, err
}

View File

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

View File

@ -1,6 +1,7 @@
package digitalocean
import (
"context"
"log"
"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())
for _, tag := range remove {
_, err := conn.Tags.UntagResources(tag, &godo.UntagResourcesRequest{
_, err := conn.Tags.UntagResources(context.Background(), tag, &godo.UntagResourcesRequest{
Resources: []godo.Resource{
{
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())
for _, tag := range create {
_, err := conn.Tags.TagResources(tag, &godo.TagResourcesRequest{
_, err := conn.Tags.TagResources(context.Background(), tag, &godo.TagResourcesRequest{
Resources: []godo.Resource{
{
ID: d.Id(),

View File

@ -1,13 +1,14 @@
package acctest
import (
"bufio"
"bytes"
crand "crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"math/rand"
"strings"
"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
// returned in OpenSSH format, and the private key is PEM encoded.
func RandSSHKeyPair(comment string) (string, string, error) {
privateKey, err := rsa.GenerateKey(crand.Reader, 1024)
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
}
privateKey, privateKeyPEM, err := genPrivateKey()
publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
return "", "", err
}
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

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 {
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:
```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
list := []godo.Droplet{}
// create options. initially, these will be blank
opt := &godo.ListOptions{}
for {
droplets, resp, err := client.Droplets.List(opt)
droplets, resp, err := client.Droplets.List(ctx, opt)
if err != nil {
return nil, err
}

View File

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

View File

@ -1,6 +1,10 @@
package godo
import "fmt"
import (
"fmt"
"github.com/digitalocean/godo/context"
)
const (
actionsBasePath = "v2/actions"
@ -15,8 +19,8 @@ const (
// ActionsService handles communction with action related methods of the
// DigitalOcean API: https://developers.digitalocean.com/documentation/v2#actions
type ActionsService interface {
List(*ListOptions) ([]Action, *Response, error)
Get(int) (*Action, *Response, error)
List(context.Context, *ListOptions) ([]Action, *Response, error)
Get(context.Context, int) (*Action, *Response, error)
}
// ActionsServiceOp handles communition with the image action related methods of the
@ -50,20 +54,20 @@ type Action struct {
}
// 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, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(actionsRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -75,19 +79,19 @@ func (s *ActionsServiceOp) List(opt *ListOptions) ([]Action, *Response, error) {
}
// 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 {
return nil, nil, NewArgError("id", "cannot be less than 1")
}
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 {
return nil, nil, err
}
root := new(actionRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
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
import "fmt"
import (
"fmt"
"github.com/digitalocean/godo/context"
)
const domainsBasePath = "v2/domains"
@ -8,16 +12,16 @@ const domainsBasePath = "v2/domains"
// See: https://developers.digitalocean.com/documentation/v2#domains and
// https://developers.digitalocean.com/documentation/v2#domain-records
type DomainsService interface {
List(*ListOptions) ([]Domain, *Response, error)
Get(string) (*Domain, *Response, error)
Create(*DomainCreateRequest) (*Domain, *Response, error)
Delete(string) (*Response, error)
List(context.Context, *ListOptions) ([]Domain, *Response, error)
Get(context.Context, string) (*Domain, *Response, error)
Create(context.Context, *DomainCreateRequest) (*Domain, *Response, error)
Delete(context.Context, string) (*Response, error)
Records(string, *ListOptions) ([]DomainRecord, *Response, error)
Record(string, int) (*DomainRecord, *Response, error)
DeleteRecord(string, int) (*Response, error)
EditRecord(string, int, *DomainRecordEditRequest) (*DomainRecord, *Response, error)
CreateRecord(string, *DomainRecordEditRequest) (*DomainRecord, *Response, error)
Records(context.Context, string, *ListOptions) ([]DomainRecord, *Response, error)
Record(context.Context, string, int) (*DomainRecord, *Response, error)
DeleteRecord(context.Context, string, int) (*Response, error)
EditRecord(context.Context, string, int, *DomainRecordEditRequest) (*DomainRecord, *Response, error)
CreateRecord(context.Context, string, *DomainRecordEditRequest) (*DomainRecord, *Response, error)
}
// DomainsServiceOp handles communication with the domain related methods of the
@ -70,6 +74,7 @@ type DomainRecord struct {
Data string `json:"data,omitempty"`
Priority int `json:"priority,omitempty"`
Port int `json:"port,omitempty"`
TTL int `json:"ttl,omitempty"`
Weight int `json:"weight,omitempty"`
}
@ -80,6 +85,7 @@ type DomainRecordEditRequest struct {
Data string `json:"data,omitempty"`
Priority int `json:"priority,omitempty"`
Port int `json:"port,omitempty"`
TTL int `json:"ttl,omitempty"`
Weight int `json:"weight,omitempty"`
}
@ -88,20 +94,20 @@ func (d Domain) String() string {
}
// 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, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(domainsRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
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.
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 {
return nil, nil, NewArgError("name", "cannot be an empty string")
}
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 {
return nil, nil, err
}
root := new(domainRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -135,20 +141,20 @@ func (s *DomainsServiceOp) Get(name string) (*Domain, *Response, error) {
}
// 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 {
return nil, nil, NewArgError("createRequest", "cannot be nil")
}
path := domainsBasePath
req, err := s.client.NewRequest("POST", path, createRequest)
req, err := s.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil {
return nil, nil, err
}
root := new(domainRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -156,19 +162,19 @@ func (s *DomainsServiceOp) Create(createRequest *DomainCreateRequest) (*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 {
return nil, NewArgError("name", "cannot be an empty string")
}
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 {
return nil, err
}
resp, err := s.client.Do(req, nil)
resp, err := s.client.Do(ctx, req, nil)
return resp, err
}
@ -184,7 +190,7 @@ func (d DomainRecordEditRequest) String() string {
}
// 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 {
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
}
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(domainRecordsRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
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
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 {
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)
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
record := new(domainRecordRoot)
resp, err := s.client.Do(req, record)
resp, err := s.client.Do(ctx, req, record)
if err != nil {
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
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 {
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)
req, err := s.client.NewRequest("DELETE", path, nil)
req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
resp, err := s.client.Do(ctx, req, nil)
return resp, err
}
// EditRecord edits a record using a DomainRecordEditRequest
func (s *DomainsServiceOp) EditRecord(
func (s *DomainsServiceOp) EditRecord(ctx context.Context,
domain string,
id int,
editRequest *DomainRecordEditRequest,
@ -280,13 +286,13 @@ func (s *DomainsServiceOp) EditRecord(
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 {
return nil, nil, err
}
d := new(DomainRecord)
resp, err := s.client.Do(req, d)
resp, err := s.client.Do(ctx, req, d)
if err != nil {
return nil, resp, err
}
@ -295,7 +301,7 @@ func (s *DomainsServiceOp) EditRecord(
}
// CreateRecord creates a record using a DomainRecordEditRequest
func (s *DomainsServiceOp) CreateRecord(
func (s *DomainsServiceOp) CreateRecord(ctx context.Context,
domain string,
createRequest *DomainRecordEditRequest) (*DomainRecord, *Response, error) {
if len(domain) < 1 {
@ -307,14 +313,14 @@ func (s *DomainsServiceOp) CreateRecord(
}
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 {
return nil, nil, err
}
d := new(domainRecordRoot)
resp, err := s.client.Do(req, d)
resp, err := s.client.Do(ctx, req, d)
if err != nil {
return nil, resp, err
}

View File

@ -3,6 +3,8 @@ package godo
import (
"fmt"
"net/url"
"github.com/digitalocean/godo/context"
)
// ActionRequest reprents DigitalOcean Action Request
@ -12,35 +14,35 @@ type ActionRequest map[string]interface{}
// endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#droplet-actions
type DropletActionsService interface {
Shutdown(int) (*Action, *Response, error)
ShutdownByTag(string) (*Action, *Response, error)
PowerOff(int) (*Action, *Response, error)
PowerOffByTag(string) (*Action, *Response, error)
PowerOn(int) (*Action, *Response, error)
PowerOnByTag(string) (*Action, *Response, error)
PowerCycle(int) (*Action, *Response, error)
PowerCycleByTag(string) (*Action, *Response, error)
Reboot(int) (*Action, *Response, error)
Restore(int, int) (*Action, *Response, error)
Resize(int, string, bool) (*Action, *Response, error)
Rename(int, string) (*Action, *Response, error)
Snapshot(int, string) (*Action, *Response, error)
SnapshotByTag(string, string) (*Action, *Response, error)
EnableBackups(int) (*Action, *Response, error)
EnableBackupsByTag(string) (*Action, *Response, error)
DisableBackups(int) (*Action, *Response, error)
DisableBackupsByTag(string) (*Action, *Response, error)
PasswordReset(int) (*Action, *Response, error)
RebuildByImageID(int, int) (*Action, *Response, error)
RebuildByImageSlug(int, string) (*Action, *Response, error)
ChangeKernel(int, int) (*Action, *Response, error)
EnableIPv6(int) (*Action, *Response, error)
EnableIPv6ByTag(string) (*Action, *Response, error)
EnablePrivateNetworking(int) (*Action, *Response, error)
EnablePrivateNetworkingByTag(string) (*Action, *Response, error)
Upgrade(int) (*Action, *Response, error)
Get(int, int) (*Action, *Response, error)
GetByURI(string) (*Action, *Response, error)
Shutdown(context.Context, int) (*Action, *Response, error)
ShutdownByTag(context.Context, string) (*Action, *Response, error)
PowerOff(context.Context, int) (*Action, *Response, error)
PowerOffByTag(context.Context, string) (*Action, *Response, error)
PowerOn(context.Context, int) (*Action, *Response, error)
PowerOnByTag(context.Context, string) (*Action, *Response, error)
PowerCycle(context.Context, int) (*Action, *Response, error)
PowerCycleByTag(context.Context, string) (*Action, *Response, error)
Reboot(context.Context, int) (*Action, *Response, error)
Restore(context.Context, int, int) (*Action, *Response, error)
Resize(context.Context, int, string, bool) (*Action, *Response, error)
Rename(context.Context, int, string) (*Action, *Response, error)
Snapshot(context.Context, int, string) (*Action, *Response, error)
SnapshotByTag(context.Context, string, string) (*Action, *Response, error)
EnableBackups(context.Context, int) (*Action, *Response, error)
EnableBackupsByTag(context.Context, string) (*Action, *Response, error)
DisableBackups(context.Context, int) (*Action, *Response, error)
DisableBackupsByTag(context.Context, string) (*Action, *Response, error)
PasswordReset(context.Context, int) (*Action, *Response, error)
RebuildByImageID(context.Context, int, int) (*Action, *Response, error)
RebuildByImageSlug(context.Context, int, string) (*Action, *Response, error)
ChangeKernel(context.Context, int, int) (*Action, *Response, error)
EnableIPv6(context.Context, int) (*Action, *Response, error)
EnableIPv6ByTag(context.Context, string) (*Action, *Response, error)
EnablePrivateNetworking(context.Context, int) (*Action, *Response, error)
EnablePrivateNetworkingByTag(context.Context, string) (*Action, *Response, error)
Upgrade(context.Context, int) (*Action, *Response, error)
Get(context.Context, int, int) (*Action, *Response, error)
GetByURI(context.Context, string) (*Action, *Response, error)
}
// DropletActionsServiceOp handles communication with the Droplet action related
@ -52,189 +54,189 @@ type DropletActionsServiceOp struct {
var _ DropletActionsService = &DropletActionsServiceOp{}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"
request := &ActionRequest{
"type": requestType,
"image": float64(imageID),
}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"
request := &ActionRequest{
"type": requestType,
"size": sizeSlug,
"disk": resizeDisk,
}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"
request := &ActionRequest{
"type": requestType,
"name": name,
}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"
request := &ActionRequest{
"type": requestType,
"name": name,
}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"
request := &ActionRequest{
"type": requestType,
"name": name,
}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
return s.doAction(id, request)
return s.doAction(ctx, id, request)
}
// 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"}
return s.doActionByTag(tag, request)
return s.doActionByTag(ctx, tag, request)
}
// 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"}
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 {
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)
req, err := s.client.NewRequest("POST", path, request)
req, err := s.client.NewRequest(ctx, "POST", path, request)
if err != nil {
return nil, nil, err
}
root := new(actionRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -259,7 +261,7 @@ func (s *DropletActionsServiceOp) doAction(id int, request *ActionRequest) (*Act
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 == "" {
return nil, nil, NewArgError("tag", "cannot be empty")
}
@ -270,13 +272,13 @@ func (s *DropletActionsServiceOp) doActionByTag(tag string, request *ActionReque
path := dropletActionPathByTag(tag)
req, err := s.client.NewRequest("POST", path, request)
req, err := s.client.NewRequest(ctx, "POST", path, request)
if err != nil {
return nil, nil, err
}
root := new(actionRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
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.
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 {
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)
return s.get(path)
return s.get(ctx, path)
}
// 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)
if err != nil {
return nil, nil, err
}
return s.get(u.Path)
return s.get(ctx, u.Path)
}
func (s *DropletActionsServiceOp) get(path string) (*Action, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil)
func (s *DropletActionsServiceOp) get(ctx context.Context, path string) (*Action, *Response, error) {
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(actionRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

View File

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

View File

@ -1,6 +1,10 @@
package godo
import "fmt"
import (
"fmt"
"github.com/digitalocean/godo/context"
)
const floatingBasePath = "v2/floating_ips"
@ -8,10 +12,10 @@ const floatingBasePath = "v2/floating_ips"
// endpoints of the Digital Ocean API.
// See: https://developers.digitalocean.com/documentation/v2#floating-ips
type FloatingIPsService interface {
List(*ListOptions) ([]FloatingIP, *Response, error)
Get(string) (*FloatingIP, *Response, error)
Create(*FloatingIPCreateRequest) (*FloatingIP, *Response, error)
Delete(string) (*Response, error)
List(context.Context, *ListOptions) ([]FloatingIP, *Response, error)
Get(context.Context, string) (*FloatingIP, *Response, error)
Create(context.Context, *FloatingIPCreateRequest) (*FloatingIP, *Response, error)
Delete(context.Context, string) (*Response, error)
}
// FloatingIPsServiceOp handles communication with the floating IPs related methods of the
@ -52,20 +56,20 @@ type FloatingIPCreateRequest struct {
}
// 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, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
req, err := f.client.NewRequest("GET", path, nil)
req, err := f.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(floatingIPsRoot)
resp, err := f.client.Do(req, root)
resp, err := f.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -77,16 +81,16 @@ func (f *FloatingIPsServiceOp) List(opt *ListOptions) ([]FloatingIP, *Response,
}
// 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)
req, err := f.client.NewRequest("GET", path, nil)
req, err := f.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(floatingIPRoot)
resp, err := f.client.Do(req, root)
resp, err := f.client.Do(ctx, req, root)
if err != nil {
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,
// 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
req, err := f.client.NewRequest("POST", path, createRequest)
req, err := f.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil {
return nil, nil, err
}
root := new(floatingIPRoot)
resp, err := f.client.Do(req, root)
resp, err := f.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -117,15 +121,15 @@ func (f *FloatingIPsServiceOp) Create(createRequest *FloatingIPCreateRequest) (*
}
// 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)
req, err := f.client.NewRequest("DELETE", path, nil)
req, err := f.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := f.client.Do(req, nil)
resp, err := f.client.Do(ctx, req, nil)
return resp, err
}

View File

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

View File

@ -14,10 +14,12 @@ import (
"github.com/google/go-querystring/query"
headerLink "github.com/tent/http-link-go"
"github.com/digitalocean/godo/context"
)
const (
libraryVersion = "0.1.0"
libraryVersion = "1.0.0"
defaultBaseURL = "https://api.digitalocean.com/"
userAgent = "godo/" + libraryVersion
mediaType = "application/json"
@ -60,6 +62,7 @@ type Client struct {
StorageActions StorageActionsService
Tags TagsService
LoadBalancers LoadBalancersService
Certificates CertificatesService
// Optional function called after every successful request made to the DO APIs
onRequestCompleted RequestCompletionCallback
@ -169,6 +172,7 @@ func NewClient(httpClient *http.Client) *Client {
c.StorageActions = &StorageActionsServiceOp{client: c}
c.Tags = &TagsServiceOp{client: c}
c.LoadBalancers = &LoadBalancersServiceOp{client: c}
c.Certificates = &CertificatesServiceOp{client: 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
// 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.
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)
if err != nil {
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
// 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.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
resp, err := c.client.Do(req)
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
resp, err := context.DoRequestWithClient(ctx, c.client, req)
if err != nil {
return nil, err
}

View File

@ -1,13 +1,18 @@
package godo
import "fmt"
import (
"fmt"
"github.com/digitalocean/godo/context"
)
// ImageActionsService is an interface for interfacing with the image actions
// endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#image-actions
type ImageActionsService interface {
Get(int, int) (*Action, *Response, error)
Transfer(int, *ActionRequest) (*Action, *Response, error)
Get(context.Context, int, int) (*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
@ -19,7 +24,7 @@ type ImageActionsServiceOp struct {
var _ ImageActionsService = &ImageActionsServiceOp{}
// 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 {
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)
req, err := i.client.NewRequest("POST", path, transferRequest)
req, err := i.client.NewRequest(ctx, "POST", path, transferRequest)
if err != nil {
return nil, nil, err
}
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 {
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.
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 {
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)
req, err := i.client.NewRequest("GET", path, nil)
req, err := i.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
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
}

View File

@ -1,6 +1,10 @@
package godo
import "fmt"
import (
"fmt"
"github.com/digitalocean/godo/context"
)
const imageBasePath = "v2/images"
@ -8,14 +12,14 @@ const imageBasePath = "v2/images"
// endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#images
type ImagesService interface {
List(*ListOptions) ([]Image, *Response, error)
ListDistribution(opt *ListOptions) ([]Image, *Response, error)
ListApplication(opt *ListOptions) ([]Image, *Response, error)
ListUser(opt *ListOptions) ([]Image, *Response, error)
GetByID(int) (*Image, *Response, error)
GetBySlug(string) (*Image, *Response, error)
Update(int, *ImageUpdateRequest) (*Image, *Response, error)
Delete(int) (*Response, error)
List(context.Context, *ListOptions) ([]Image, *Response, error)
ListDistribution(ctx context.Context, opt *ListOptions) ([]Image, *Response, error)
ListApplication(ctx context.Context, opt *ListOptions) ([]Image, *Response, error)
ListUser(ctx context.Context, opt *ListOptions) ([]Image, *Response, error)
GetByID(context.Context, int) (*Image, *Response, error)
GetBySlug(context.Context, string) (*Image, *Response, error)
Update(context.Context, int, *ImageUpdateRequest) (*Image, *Response, error)
Delete(context.Context, int) (*Response, error)
}
// 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.
func (s *ImagesServiceOp) List(opt *ListOptions) ([]Image, *Response, error) {
return s.list(opt, nil)
func (s *ImagesServiceOp) List(ctx context.Context, opt *ListOptions) ([]Image, *Response, error) {
return s.list(ctx, opt, nil)
}
// 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"}
return s.list(opt, &listOpt)
return s.list(ctx, opt, &listOpt)
}
// 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"}
return s.list(opt, &listOpt)
return s.list(ctx, opt, &listOpt)
}
// 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}
return s.list(opt, &listOpt)
return s.list(ctx, opt, &listOpt)
}
// 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 {
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.
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 {
return nil, nil, NewArgError("slug", "cannot be blank")
}
return s.get(interface{}(slug))
return s.get(ctx, interface{}(slug))
}
// 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 {
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)
req, err := s.client.NewRequest("PUT", path, updateRequest)
req, err := s.client.NewRequest(ctx, "PUT", path, updateRequest)
if err != nil {
return nil, nil, err
}
root := new(imageRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -129,34 +133,34 @@ func (s *ImagesServiceOp) Update(imageID int, updateRequest *ImageUpdateRequest)
}
// 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 {
return nil, NewArgError("imageID", "cannot be less than 1")
}
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 {
return nil, err
}
resp, err := s.client.Do(req, nil)
resp, err := s.client.Do(ctx, req, nil)
return resp, err
}
// 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)
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(imageRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -165,7 +169,7 @@ func (s *ImagesServiceOp) get(ID interface{}) (*Image, *Response, error) {
}
// 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, err := addOptions(path, opt)
if err != nil {
@ -176,13 +180,13 @@ func (s *ImagesServiceOp) list(opt *ListOptions, listOpt *listImageOptions) ([]I
return nil, nil, err
}
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(imagesRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

View File

@ -1,6 +1,10 @@
package godo
import "fmt"
import (
"fmt"
"github.com/digitalocean/godo/context"
)
const keysBasePath = "v2/account/keys"
@ -8,14 +12,14 @@ const keysBasePath = "v2/account/keys"
// endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#keys
type KeysService interface {
List(*ListOptions) ([]Key, *Response, error)
GetByID(int) (*Key, *Response, error)
GetByFingerprint(string) (*Key, *Response, error)
Create(*KeyCreateRequest) (*Key, *Response, error)
UpdateByID(int, *KeyUpdateRequest) (*Key, *Response, error)
UpdateByFingerprint(string, *KeyUpdateRequest) (*Key, *Response, error)
DeleteByID(int) (*Response, error)
DeleteByFingerprint(string) (*Response, error)
List(context.Context, *ListOptions) ([]Key, *Response, error)
GetByID(context.Context, int) (*Key, *Response, error)
GetByFingerprint(context.Context, string) (*Key, *Response, error)
Create(context.Context, *KeyCreateRequest) (*Key, *Response, error)
UpdateByID(context.Context, int, *KeyUpdateRequest) (*Key, *Response, error)
UpdateByFingerprint(context.Context, string, *KeyUpdateRequest) (*Key, *Response, error)
DeleteByID(context.Context, int) (*Response, error)
DeleteByFingerprint(context.Context, string) (*Response, error)
}
// KeysServiceOp handles communication with key related method of the
@ -59,20 +63,20 @@ type KeyCreateRequest struct {
}
// 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, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(keysRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -84,14 +88,14 @@ func (s *KeysServiceOp) List(opt *ListOptions) ([]Key, *Response, error) {
}
// Performs a get given a path
func (s *KeysServiceOp) get(path string) (*Key, *Response, error) {
req, err := s.client.NewRequest("GET", path, nil)
func (s *KeysServiceOp) get(ctx context.Context, path string) (*Key, *Response, error) {
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(keyRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -100,38 +104,38 @@ func (s *KeysServiceOp) get(path string) (*Key, *Response, error) {
}
// 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 {
return nil, nil, NewArgError("keyID", "cannot be less than 1")
}
path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
return s.get(path)
return s.get(ctx, path)
}
// 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 {
return nil, nil, NewArgError("fingerprint", "cannot not be empty")
}
path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint)
return s.get(path)
return s.get(ctx, path)
}
// 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 {
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 {
return nil, nil, err
}
root := new(keyRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -140,7 +144,7 @@ func (s *KeysServiceOp) Create(createRequest *KeyCreateRequest) (*Key, *Response
}
// 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 {
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)
req, err := s.client.NewRequest("PUT", path, updateRequest)
req, err := s.client.NewRequest(ctx, "PUT", path, updateRequest)
if err != nil {
return nil, nil, err
}
root := new(keyRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -165,7 +169,7 @@ func (s *KeysServiceOp) UpdateByID(keyID int, updateRequest *KeyUpdateRequest) (
}
// 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 {
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)
req, err := s.client.NewRequest("PUT", path, updateRequest)
req, err := s.client.NewRequest(ctx, "PUT", path, updateRequest)
if err != nil {
return nil, nil, err
}
root := new(keyRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -190,33 +194,33 @@ func (s *KeysServiceOp) UpdateByFingerprint(fingerprint string, updateRequest *K
}
// Delete key using a path
func (s *KeysServiceOp) delete(path string) (*Response, error) {
req, err := s.client.NewRequest("DELETE", path, nil)
func (s *KeysServiceOp) delete(ctx context.Context, path string) (*Response, error) {
req, err := s.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
resp, err := s.client.Do(ctx, req, nil)
return resp, err
}
// 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 {
return nil, NewArgError("keyID", "cannot be less than 1")
}
path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
return s.delete(path)
return s.delete(ctx, path)
}
// 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 {
return nil, NewArgError("fingerprint", "cannot be empty")
}
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 (
"net/url"
"strconv"
"github.com/digitalocean/godo/context"
)
// 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.
func (la *LinkAction) Get(client *Client) (*Action, *Response, error) {
return client.Actions.Get(la.ID)
func (la *LinkAction) Get(ctx context.Context, client *Client) (*Action, *Response, error) {
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 (
"fmt"
"github.com/digitalocean/godo/context"
)
const loadBalancersBasePath = "/v2/load_balancers"
@ -11,15 +13,15 @@ const dropletsPath = "droplets"
// LoadBalancersService is an interface for managing load balancers with the DigitalOcean API.
// See: https://developers.digitalocean.com/documentation/v2#load-balancers
type LoadBalancersService interface {
Get(lbID string) (*LoadBalancer, *Response, error)
List(opt *ListOptions) ([]LoadBalancer, *Response, error)
Create(lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error)
Update(lbID string, lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error)
Delete(lbID string) (*Response, error)
AddDroplets(lbID string, dropletIDs ...int) (*Response, error)
RemoveDroplets(lbID string, dropletIDs ...int) (*Response, error)
AddForwardingRules(lbID string, rules ...ForwardingRule) (*Response, error)
RemoveForwardingRules(lbID string, rules ...ForwardingRule) (*Response, error)
Get(context.Context, string) (*LoadBalancer, *Response, error)
List(context.Context, *ListOptions) ([]LoadBalancer, *Response, error)
Create(context.Context, *LoadBalancerRequest) (*LoadBalancer, *Response, error)
Update(ctx context.Context, lbID string, lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error)
Delete(ctx context.Context, lbID string) (*Response, error)
AddDroplets(ctx context.Context, lbID string, dropletIDs ...int) (*Response, error)
RemoveDroplets(ctx context.Context, lbID string, dropletIDs ...int) (*Response, error)
AddForwardingRules(ctx context.Context, lbID string, rules ...ForwardingRule) (*Response, error)
RemoveForwardingRules(ctx context.Context, lbID string, rules ...ForwardingRule) (*Response, error)
}
// LoadBalancer represents a DigitalOcean load balancer configuration.
@ -138,16 +140,16 @@ type LoadBalancersServiceOp struct {
var _ LoadBalancersService = &LoadBalancersServiceOp{}
// 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)
req, err := l.client.NewRequest("GET", path, nil)
req, err := l.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(loadBalancerRoot)
resp, err := l.client.Do(req, root)
resp, err := l.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -156,19 +158,19 @@ func (l *LoadBalancersServiceOp) Get(lbID string) (*LoadBalancer, *Response, err
}
// 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)
if err != nil {
return nil, nil, err
}
req, err := l.client.NewRequest("GET", path, nil)
req, err := l.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(loadBalancersRoot)
resp, err := l.client.Do(req, root)
resp, err := l.client.Do(ctx, req, root)
if err != nil {
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.
func (l *LoadBalancersServiceOp) Create(lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error) {
req, err := l.client.NewRequest("POST", loadBalancersBasePath, lbr)
func (l *LoadBalancersServiceOp) Create(ctx context.Context, lbr *LoadBalancerRequest) (*LoadBalancer, *Response, error) {
req, err := l.client.NewRequest(ctx, "POST", loadBalancersBasePath, lbr)
if err != nil {
return nil, nil, err
}
root := new(loadBalancerRoot)
resp, err := l.client.Do(req, root)
resp, err := l.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -196,16 +198,16 @@ func (l *LoadBalancersServiceOp) Create(lbr *LoadBalancerRequest) (*LoadBalancer
}
// 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)
req, err := l.client.NewRequest("PUT", path, lbr)
req, err := l.client.NewRequest(ctx, "PUT", path, lbr)
if err != nil {
return nil, nil, err
}
root := new(loadBalancerRoot)
resp, err := l.client.Do(req, root)
resp, err := l.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -214,61 +216,61 @@ func (l *LoadBalancersServiceOp) Update(lbID string, lbr *LoadBalancerRequest) (
}
// 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)
req, err := l.client.NewRequest("DELETE", path, nil)
req, err := l.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return nil, err
}
return l.client.Do(req, nil)
return l.client.Do(ctx, req, nil)
}
// 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)
req, err := l.client.NewRequest("POST", path, &dropletIDsRequest{IDs: dropletIDs})
req, err := l.client.NewRequest(ctx, "POST", path, &dropletIDsRequest{IDs: dropletIDs})
if err != nil {
return nil, err
}
return l.client.Do(req, nil)
return l.client.Do(ctx, req, nil)
}
// 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)
req, err := l.client.NewRequest("DELETE", path, &dropletIDsRequest{IDs: dropletIDs})
req, err := l.client.NewRequest(ctx, "DELETE", path, &dropletIDsRequest{IDs: dropletIDs})
if err != nil {
return nil, err
}
return l.client.Do(req, nil)
return l.client.Do(ctx, req, nil)
}
// 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)
req, err := l.client.NewRequest("POST", path, &forwardingRulesRequest{Rules: rules})
req, err := l.client.NewRequest(ctx, "POST", path, &forwardingRulesRequest{Rules: rules})
if err != nil {
return nil, err
}
return l.client.Do(req, nil)
return l.client.Do(ctx, req, nil)
}
// 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)
req, err := l.client.NewRequest("DELETE", path, &forwardingRulesRequest{Rules: rules})
req, err := l.client.NewRequest(ctx, "DELETE", path, &forwardingRulesRequest{Rules: rules})
if err != nil {
return nil, err
}
return l.client.Do(req, nil)
return l.client.Do(ctx, req, nil)
}

View File

@ -1,10 +1,12 @@
package godo
import "github.com/digitalocean/godo/context"
// RegionsService is an interface for interfacing with the regions
// endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#regions
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
@ -34,20 +36,20 @@ func (r Region) String() string {
}
// 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, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(regionsRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

View File

@ -1,10 +1,12 @@
package godo
import "github.com/digitalocean/godo/context"
// SizesService is an interface for interfacing with the size
// endpoints of the DigitalOcean API
// See: https://developers.digitalocean.com/documentation/v2#sizes
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
@ -38,20 +40,20 @@ type sizesRoot struct {
}
// 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, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", path, nil)
req, err := s.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(sizesRoot)
resp, err := s.client.Do(req, root)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

View File

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

View File

@ -3,6 +3,8 @@ package godo
import (
"fmt"
"time"
"github.com/digitalocean/godo/context"
)
const (
@ -15,14 +17,14 @@ const (
// endpoints of the Digital Ocean API.
// See: https://developers.digitalocean.com/documentation/v2#storage
type StorageService interface {
ListVolumes(*ListOptions) ([]Volume, *Response, error)
GetVolume(string) (*Volume, *Response, error)
CreateVolume(*VolumeCreateRequest) (*Volume, *Response, error)
DeleteVolume(string) (*Response, error)
ListSnapshots(volumeID string, opts *ListOptions) ([]Snapshot, *Response, error)
GetSnapshot(string) (*Snapshot, *Response, error)
CreateSnapshot(*SnapshotCreateRequest) (*Snapshot, *Response, error)
DeleteSnapshot(string) (*Response, error)
ListVolumes(context.Context, *ListVolumeParams) ([]Volume, *Response, error)
GetVolume(context.Context, string) (*Volume, *Response, error)
CreateVolume(context.Context, *VolumeCreateRequest) (*Volume, *Response, error)
DeleteVolume(context.Context, string) (*Response, error)
ListSnapshots(ctx context.Context, volumeID string, opts *ListOptions) ([]Snapshot, *Response, error)
GetSnapshot(context.Context, string) (*Snapshot, *Response, error)
CreateSnapshot(context.Context, *SnapshotCreateRequest) (*Snapshot, *Response, error)
DeleteSnapshot(context.Context, string) (*Response, error)
}
// StorageServiceOp handles communication with the storage volumes related methods of the
@ -31,6 +33,13 @@ type StorageServiceOp struct {
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{}
// Volume represents a Digital Ocean block store volume.
@ -65,22 +74,33 @@ type VolumeCreateRequest struct {
Name string `json:"name"`
Description string `json:"description"`
SizeGigaBytes int64 `json:"size_gigabytes"`
SnapshotID string `json:"snapshot_id"`
}
// ListVolumes lists all storage volumes.
func (svc *StorageServiceOp) ListVolumes(opt *ListOptions) ([]Volume, *Response, error) {
path, err := addOptions(storageAllocPath, opt)
func (svc *StorageServiceOp) ListVolumes(ctx context.Context, params *ListVolumeParams) ([]Volume, *Response, error) {
path := storageAllocPath
if params != nil {
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 {
return nil, nil, err
}
root := new(storageVolumesRoot)
resp, err := svc.client.Do(req, root)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
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.
func (svc *StorageServiceOp) CreateVolume(createRequest *VolumeCreateRequest) (*Volume, *Response, error) {
func (svc *StorageServiceOp) CreateVolume(ctx context.Context, createRequest *VolumeCreateRequest) (*Volume, *Response, error) {
path := storageAllocPath
req, err := svc.client.NewRequest("POST", path, createRequest)
req, err := svc.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil {
return nil, nil, err
}
root := new(storageVolumeRoot)
resp, err := svc.client.Do(req, root)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -110,16 +130,16 @@ func (svc *StorageServiceOp) CreateVolume(createRequest *VolumeCreateRequest) (*
}
// 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)
req, err := svc.client.NewRequest("GET", path, nil)
req, err := svc.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(storageVolumeRoot)
resp, err := svc.client.Do(req, root)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -128,14 +148,14 @@ func (svc *StorageServiceOp) GetVolume(id string) (*Volume, *Response, error) {
}
// 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)
req, err := svc.client.NewRequest("DELETE", path, nil)
req, err := svc.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
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
@ -147,20 +167,20 @@ type SnapshotCreateRequest struct {
}
// 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, err := addOptions(path, opt)
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 {
return nil, nil, err
}
root := new(snapshotsRoot)
resp, err := svc.client.Do(req, root)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -173,16 +193,16 @@ func (svc *StorageServiceOp) ListSnapshots(volumeID string, opt *ListOptions) ([
}
// 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)
req, err := svc.client.NewRequest("POST", path, createRequest)
req, err := svc.client.NewRequest(ctx, "POST", path, createRequest)
if err != nil {
return nil, nil, err
}
root := new(snapshotRoot)
resp, err := svc.client.Do(req, root)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -190,16 +210,16 @@ func (svc *StorageServiceOp) CreateSnapshot(createRequest *SnapshotCreateRequest
}
// 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)
req, err := svc.client.NewRequest("GET", path, nil)
req, err := svc.client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, nil, err
}
root := new(snapshotRoot)
resp, err := svc.client.Do(req, root)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
@ -208,12 +228,12 @@ func (svc *StorageServiceOp) GetSnapshot(id string) (*Snapshot, *Response, error
}
// 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)
req, err := svc.client.NewRequest("DELETE", path, nil)
req, err := svc.client.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return nil, err
}
return svc.client.Do(req, nil)
return svc.client.Do(ctx, req, nil)
}

View File

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

View File

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

12
vendor/vendor.json vendored
View File

@ -1374,11 +1374,17 @@
"revisionTime": "2016-06-17T17:01:58Z"
},
{
"checksumSHA1": "tOlmmumwQ9pCv5cQgs+W7sgPVgU=",
"checksumSHA1": "uuenX+nAyhQfYqedBhQ+yhBh1mA=",
"comment": "v0.9.0-20-gf75d769",
"path": "github.com/digitalocean/godo",
"revision": "767976000cc435d38646653b52be9be572727f30",
"revisionTime": "2017-02-14T20:43:37Z"
"revision": "83908b1ddd666d08a9b020c697b55ae3895be2fd",
"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=",

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") %>>
<a href="#">Resources</a>
<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") %>>
<a href="/docs/providers/do/r/domain.html">digitalocean_domain</a>
</li>